Skip to content

Behave Logic Report

💡 TL;DR - Executable Test Suite, Documentation

You can optionally use the Behave test framework to capture requirements and execute a test suite (here is an Agile Approach for using Behave). Say this to your AI assistant, in order:

  1. create logic diagram for each requirement - optional; needs Graphviz (brew install graphviz)
  2. create tests from rules - writes the Behave .feature files and steps
  3. run the tests - starts the server if needed, runs the Behave suite, reports pass/fail
  4. run the behave report

This creates the Behave Logic Report shown below, as test/api_logic_server_behave/reports/Behave Logic Report.md. You can run step 4 before any tests exist: the requirements, rules, data model, security and messages sections are read from the project's files.

   

This report is generated from the project's own files, in the order an auditor reads them: requirements traced to the code that implements them, every rule, the data model, security (RBAC), messages and APIs - and then test evidence, with the logic each test exercised.

For complete documentation on using Behave: See Behave

Everything above Tests and Results is read from the project's files, so it is complete even before any tests are written.


Behave Logic Report

Project: basic_demo_eai  |  Generated: October 19, 2026 21:49  |  Rules: 8  |  Test scenarios: 14  |  Generator: Behave Logic Report 2.0

About this project (from readme.md)

This app illustrates using IntegrationServices for B2B push-style integrations with APIs, and internal integration with messages.

basic_demo_eai is a single API Logic Server providing APIs and logic — it both subscribes and publishes, so there's no second project to stand up:

  1. Order Logic: enforcing database integrity (Check Credit) and application integration (notify shipping)
  2. A Custom API (OrderB2B), matching an agreed-upon format for B2B partners
  3. Kafka Subscribe: listens on topic order_b2b for inbound orders from a message broker
  4. Kafka Publish: publishes to topic order_shipping when an order ships — consumed by whatever downstream shipping system you plug in (not part of this demo)
  5. Standard APIs for ad-hoc integration, user interfaces, etc

   

Contents

   

Requirements Traceability To Rules

Traceability here is forward (requirement, to the rules, handlers and grants that implement it, to the tests that exercise it) and backward (implementation and tests, to the requirement they serve). Anything with no requirement is listed as untraced, and every requirement with no implementation or no test is listed as a gap. Links are made by the Feature: names and §N tags that requirements, code and tests carry.

 

Coverage summary

Measure Result
Requirements 5
Implemented (at least one file) 5 of 5
Tested (at least one scenario) 4 of 5 - gap: §5 Security
Implementation not traced to a requirement integration/OrderB2bMapper.py, logic/logic_discovery/system/all_classes_stamping.py
Tests not traced to a requirement none
Test results (last run) ✅ 14 passed, 0 failed
Scenarios with a logic log 14 of 14
Rules seen in at least one scenario's log 7 of 7 (1 rule(s) cannot be matched to the engine's log)

Test results are read from logs/behave.log, so they are only as current as that run. Not recorded here: which version of a requirement the code was built against, and which clause of a requirement a given rule serves.

 

Traceability matrix

Requirement Implemented by Rules Tests
§1 Business Logic — Check Credit logic/logic_discovery/check_credit.py 5 ✅ 9 scenario(s): 9 passed
§2 B2B API — Accept orders from external partners api/api_discovery/order_b2b_api.py 0 ✅ 3 scenario(s): 3 passed
§3 Kafka Subscribe — Inbound orders from sales channel logic/logic_discovery/order_b2b_consume.py
integration/kafka/kafka_subscribe_discovery/order_b2b.py
api/api_discovery/order_b2b_consume_debug.py
1 ✅ 1 scenario(s): 1 passed
§4 Kafka Publish — Notify shipping on dispatch logic/logic_discovery/app_integration.py
integration/kafka/kafka_publish_discovery/order_shipping.py
1 ✅ 1 scenario(s): 1 passed
§5 Security security/declare_security.py 0 ⚠ none defined

 

Rule coverage by tests

Rule Requirement Seen in
Order.after_flush_row_event → _send_order_to_kafka() §4 Kafka Publish — Notify shipping on dispatch 12: Partner Order Is Accepted And Rules Derive The Totals; Create Order Rolls Up To Customer Balance; Update Item Quantity Recalculates Amounts; +9 more
Item.unit_price = copy of Product.unit_price §1 Business Logic — Check Credit 13: Partner Order Is Accepted And Rules Derive The Totals; Partner Order Exceeding Credit Limit Is Rejected; Create Order Rolls Up To Customer Balance; +10 more
Item.amount = quantity * unit_price §1 Business Logic — Check Credit 13: Partner Order Is Accepted And Rules Derive The Totals; Partner Order Exceeding Credit Limit Is Rejected; Create Order Rolls Up To Customer Balance; +10 more
Order.amount_total = sum(Item.amount) §1 Business Logic — Check Credit 13: Partner Order Is Accepted And Rules Derive The Totals; Partner Order Exceeding Credit Limit Is Rejected; Create Order Rolls Up To Customer Balance; +10 more
Customer.balance = sum(Order.amount_total) where date_shipped is None §1 Business Logic — Check Credit 13: Partner Order Is Accepted And Rules Derive The Totals; Partner Order Exceeding Credit Limit Is Rejected; Create Order Rolls Up To Customer Balance; +10 more
Customer: balance is None or credit_limit is None or balance <= credit_limit §1 Business Logic — Check Credit 2: Partner Order Exceeding Credit Limit Is Rejected; Order Exceeding Credit Limit Is Rejected
OrderB2bMessage.after_flush_row_event → _publish_order_b2b() §3 Kafka Subscribe — Inbound orders from sales channel 1: Inbound Order Message Creates The Order And Items
all classes.early_row_event → handle_all() (none) n/a - cannot be matched to the engine's log

"Seen" means the engine reported running the rule in that scenario's logic log. A scenario can only contribute if it has a log (see the coverage summary): a test that does not open one writes into whichever log was open last, and its rules are then credited to that scenario, or to the shared log. An event's function runs on every commit of its class, and its own condition decides whether it acts, so seen does not mean it took effect. A constraint appears in the log only when it rejects a transaction, so it is seen only in scenarios that make it reject. "Not seen" therefore means no log shows it, not that no test ran it.

 

Requirements in detail

8 rules in 4 files: 5 declarative (sum, count, copy, formula and constraint expressions), 0 backed by a Python function, 3 events (Python). Declarative rules are read directly from their declarations; functions and events are Python, so the report shows each one's docstring, not an analysis of its code.

Each requirement is followed by the rules and handlers in the files that implement it. Logic diagrams are shown (click to expand) where they exist.

How to create the missing logic diagrams

Needs Graphviz (brew install graphviz). Tell your AI assistant:

create logic diagram for each requirement

or run this from the Manager root (genai-logic):

python system/ApiLogicServer-Internal-Dev/logic_diagram_gv.py samples/basic_demo_eai --each

Each diagram is saved under docs/requirements/<name>/logic_diagrams/. Then regenerate this report (python behave_logic_report.py run, from test/api_logic_server_behave).

 

§1 Business Logic — Check Credit

Tests: ✅ 9 scenario(s): 9 passed

Feature: Check Credit

  Scenario: Place an order
    Given a customer with a credit limit
    When an order is placed
    Then copy the price from the product
    And multiply by quantity to get the item amount
    And sum item amounts to get the order total
    And sum unpaid order totals to get the customer balance
    And reject if balance exceeds the credit limit
Rule / item Type Logic Description Where
Item.unit_price = copy of Product.unit_price copy declarative check_credit.py
Item.amount = quantity * unit_price formula declarative check_credit.py
Order.amount_total = sum(Item.amount) sum declarative check_credit.py
Customer.balance = sum(Order.amount_total) where date_shipped is None sum declarative check_credit.py
Customer: balance is None or credit_limit is None or balance <= credit_limit constraint declarative Error: balance ({row.balance}) exceeds credit limit ({row.credit_limit}) check_credit.py
Logic diagram: check_credit

logic diagram: check_credit

§2 B2B API — Accept orders from external partners

Tests: ✅ 3 scenario(s): 3 passed

Feature: B2B Order Integration

  Scenario: Accept order from external partner
    Given an inbound B2B order in partner format (message_formats/order_b2b.json)
    When the order is received via a Custom API endpoint named OrderB2B
    Then map Account to Customer by name
    And map Items.Name to Product by name
    And map Items.QuantityOrdered to Item.quantity
Rule / item Type Logic Description Where
HTTP in: POST /api/OrderB2B http handler (Python) API service OrderB2B: accepts an inbound B2B order from an external partner. order_b2b_api.py
§3 Kafka Subscribe — Inbound orders from sales channel

Tests: ✅ 1 scenario(s): 1 passed

Feature: Kafka Subscribe Order Integration

  Scenario: Accept inbound orders from sales channel
    Given an inbound order message in JSON format (message_formats/order_b2b.json)
    When the message is received from Kafka topic order_b2b
    Then map Account to Customer by name
    And map Items.Name to Product by name
    And map Items.QuantityOrdered to Item.quantity
Rule / item Type Logic Description Where
OrderB2bMessage.after_flush_row_event → _publish_order_b2b() after_flush_row_event event (Python) OrderB2bMessage event: publishes the raw blob to order_b2b_processed after Tx 1 commits, so Consumer 2 can parse it in a clean Tx 2 (2-message pattern). order_b2b_consume.py
Kafka in: order_b2b kafka handler (Python) Kafka subscribe order_b2b (Consumer 1): saves the raw message as an OrderB2bMessage blob and commits; the row event then publishes it to order_b2b_processed. order_b2b.py
Kafka in: order_b2b_processed kafka handler (Python) Kafka subscribe order_b2b_processed (Consumer 2): parses the blob and persists Order and Item rows, marking the blob processed, in one atomic transaction (Tx 2). order_b2b.py
HTTP in: GET /consume_debug/order_b2b http handler (Python) API service consume_debug: runs the order_b2b consume pipeline without Kafka. order_b2b_consume_debug.py
§4 Kafka Publish — Notify shipping on dispatch

Tests: ✅ 1 scenario(s): 1 passed

Feature: Kafka Publish Shipping Notification

  Scenario: Notify shipping when an order is dispatched
    Given an Order exists
    When date_shipped is set
    Then publish to Kafka topic order_shipping
    And use message_formats/order_shipping.json as the message shape
    And use by-example publish rather than key-only publish
Rule / item Type Logic Description Where
Order.after_flush_row_event → _send_order_to_kafka() after_flush_row_event event (Python) Order publish: sends the Order to Kafka topic order_shipping when date_shipped is first set (or changes), by example, using the message shape in kafka_publish_discovery/order_shipping.py. app_integration.py
order_shipping.py module By-example publish mapper for Kafka topic order_shipping (Req §4). order_shipping.py
Logic diagram: app_integration

logic diagram: app_integration

§5 Security

Tests: none defined

Feature: Row-Level Security
  Scenario: Sales role sees limited customers
    Given a user with the sales role
    When querying the Customer list
    Then only return customers where credit_limit >= 3000 or balance > 0
Rule / item Type Logic Description Where
Grant on Customer to role sales: credit_limit >= 3000 or balance > 0 grant declarative declare_security.py
Rules not traced to a requirement
Rule / item Type Logic Description Where
all classes.early_row_event → handle_all() early_row_event_all_classes event (Python) Generic handler - executed for every row update across all classes. all_classes_stamping.py

   

Data Model

db diagram

Generated from docs/db.dbml (parents above children; shaded rows are derived by rules). To use your own layout, save it as docs/db_diagram.png.

 

Derived columns

Table Column Rule Definition
Item unit_price copy Item.unit_price = copy of Product.unit_price
Item amount formula Item.amount = quantity * unit_price
Order amount_total sum Order.amount_total = sum(Item.amount)
Customer balance sum Customer.balance = sum(Order.amount_total) where date_shipped is None

   

Security (RBAC)

Security enabled: no (SECURITY_ENABLED in config/default.env). The declarations below are not enforced until genai-logic add-auth is run.

 

Roles and CRUD (DefaultRolePermission)

Role Read Insert Update Delete
sa ✅ ✅ ✅ ✅
tenant ✅ — — ✅
CS_ADMIN ✅ ✅ ✅ ✅
manager ✅ ✅ ✅ —
teller ✅ ✅ ✅ —
customer ✅ ✅ ✅ —
readonly ✅ — — —
public ✅ — — —
sales ✅ — — —
default-roles-kcals ✅ ✅ ✅ —
uma_authorization ✅ ✅ ✅ —

 

Row-level grants (Grant)

Table Role Filter Requirement
Customer sales credit_limit >= 3000 or balance > 0 §5

   

Messages and APIs

Direction Channel Name Handler Tables created Message shape Requirement
➡ in Kafka order_b2b order_b2b() - Kafka subscribe order_b2b (Consumer 1): saves the raw message as an OrderB2bMessage blob and commits; the row event then publishes it to order_b2b_processed. OrderB2bMessage order_b2b.json §3 Kafka Subscribe — Inbound orders from sales channel
➡ in Kafka order_b2b_processed order_b2b_processed() - Kafka subscribe order_b2b_processed (Consumer 2): parses the blob and persists Order and Item rows, marking the blob processed, in one atomic transaction (Tx 2). Item, Order, OrderB2bMessage §3 Kafka Subscribe — Inbound orders from sales channel
⬅ out Kafka order_shipping Order.after_flush_row_event → _send_order_to_kafka() - Order publish: sends the Order to Kafka topic order_shipping when date_shipped is first set (or changes), by example, using the message shape in kafka_publish_discovery/order_shipping.py. order_shipping.json §4 Kafka Publish — Notify shipping on dispatch
⬅ out Kafka order_b2b_processed OrderB2bMessage.after_flush_row_event → _publish_order_b2b() - OrderB2bMessage event: publishes the raw blob to order_b2b_processed after Tx 1 commits, so Consumer 2 can parse it in a clean Tx 2 (2-message pattern). §3 Kafka Subscribe — Inbound orders from sales channel
➡ in HTTP POST /api/OrderB2B order_b2b_api() - API service OrderB2B: accepts an inbound B2B order from an external partner. §2 B2B API — Accept orders from external partners
➡ in HTTP GET /consume_debug/order_b2b consume_debug_order_b2b() - API service consume_debug: runs the order_b2b consume pipeline without Kafka. §3 Kafka Subscribe — Inbound orders from sales channel

Topics and endpoints are read from the discovery folders. The condition that triggers an outbound message lives in Python (see the rules under each requirement); here it is described by the handler's docstring. "Tables created" lists rows the handler's code constructs, following its calls within the project; blank means none were found, not that none exist.

Message shape: order_b2b
{
  "Account": "Alice",
  "Notes": "Kafka order from sales",
  "Items": [
    { "Name": "Widget",  "QuantityOrdered": 1 },
    { "Name": "Gadget",  "QuantityOrdered": 2 }
  ]
}
Message shape: order_shipping
{
  "order_id": 1,
  "order_date": "2026-04-06",
  "customer_name": "Alfreds Futterkiste",
  "total": 100.00,
  "items": [
    { "quantity": 2, "product_name": "Chai", "unit_price": 25.00 }
  ]
}

   

Tests and Results

✅ 14 scenario(s): 14 passed, 0 failed (from the last run, logs/behave.log).

These are Behave scenarios. Each one drives the running API the way any client would (create an order, change a quantity, ship it) and checks the result.

The logic log is what makes them more than pass/fail. Business rules run inside the server on every commit, so the server records exactly what they did, and this report embeds that record for each scenario. Two things to look for:

  1. It shows every rule that runs. Each line is one rule execution, with the row's state, old and new values. You see not just that a test passed, but which rules ran and what each one changed.
  2. The nesting shows multi-table chaining. Indentation follows the cascade: a change to an Item adjusts its Order, which adjusts its Customer.
How to read the logic log

Open a scenario's "Rules exercised and logic log" block to see it. The log is shown in full, attribute values included, because those values are what you diagnose from when a rule produces an unexpected result.

To read a log line:

....Order[16] {Update - Adjusting order: amount_total} id: 16, customer_id: 19, amount_total:  [0.0-->] 90.0
  • The leading dots are the depth in the cascade: Item (2 dots), its Order (4), its Customer (6).
  • Order[16] is the row; {...} is the rule or action that ran; the rest is the row's attribute values at that step.
  • [0.0-->] 90.0 marks a value the rules changed, with its old and new value.
  • The log is in phases: ROW LOGIC (derivations and constraints, as rows change), COMMIT LOGIC (checks that need the finished aggregates), and AFTER_FLUSH LOGIC (events that need database-assigned keys, such as the Kafka publish).

More: Logic Log.

 

How to add more tests, and run them

1. Have AI create them. This project's context tells your AI assistant how (.github/copilot-instructions.md, docs/training/testing.md). Just say:

create tests from rules

The assistant reads database/models.py, the logic files and the custom APIs, then writes .feature files and step implementations under test/api_logic_server_behave/features/. Then say run the tests and run the behave report and the assistant does both.

Or, to have each requirement's tests linked in the Tests column above (it matches on Feature: name), say which names to use:

create tests from rules, one Feature per requirement, named exactly:
- Check Credit
- B2B Order Integration
- Kafka Subscribe Order Integration
- Kafka Publish Shipping Notification
- Row-Level Security

Tests with other names still run and appear below; they just aren't linked to a requirement.

2. You can also define tests manually. Add a <name>.feature file (Gherkin) under test/api_logic_server_behave/features/ and its steps under features/steps/. The steps call the running API, so tests exercise the same rules as any client. See docs/training/testing.md for the patterns that keep tests repeatable.

Or run them yourself (server running, from test/api_logic_server_behave):

python behave_run.py --outfile=logs/behave.log
python behave_logic_report.py run

   

Feature: B2B Order Integration

   

Scenario: Partner Order Is Accepted And Rules Derive The Totals ✅

  Scenario: Partner Order Is Accepted And Rules Derive The Totals
   Given Customer "Acme" with balance 0 and credit limit 1000
   When B2B order is posted for "Acme" with 2 Widget and 1 Gadget
   Then B2B order is accepted
   Then Order has 2 items
   Then Order amount_total is 330
   Then Customer balance is 330

Rules exercised and logic log (1 transaction)

   

Rules Used in Scenario: Partner Order Is Accepted And Rules Derive The Totals

  Customer  
    1. Derive Customer.balance as Sum(Order.amount_total Where lambda row: row.date_shipped is None))  
  Item  
    2. Derive Item.amount as Formula (1): as_expression=lambda row: row.quantity * row.unit [...]  
    3. Derive Item.unit_price as Copy(product.unit_price)  
  Order  
    4. RowEvent Order._send_order_to_kafka()  
    5. Derive Order.amount_total as Sum(Item.amount Where  - None)  

Logic Log in Scenario: Partner Order Is Accepted And Rules Derive The Totals (1 transaction)

Logic Phase:        ROW LOGIC       (session=0x10c8009d0) (sqlalchemy before_flush)          - 2026-10-19 20:06:20,581 - logic_logger - INFO
..Order[None] {Insert - client} id: None, notes: behave test, customer_id: 6, CreatedOn: None, date_shipped: None, amount_total: None  row: 0x10c78b150  session: 0x10c8009d0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,581 - logic_logger - INFO
..Order[None] {server aggregate_defaults: amount_total } id: None, notes: behave test, customer_id: 6, CreatedOn: None, date_shipped: None, amount_total: 0  row: 0x10c78b150  session: 0x10c8009d0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,581 - logic_logger - INFO
..Item[None] {Insert - client} id: None, order_id: None, product_id: 2, quantity: 2, amount: None, unit_price: None  row: 0x10c78bc50  session: 0x10c8009d0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,581 - logic_logger - INFO
..Item[None] {copy_rules for role: product - unit_price} id: None, order_id: None, product_id: 2, quantity: 2, amount: None, unit_price: 90.0000000000  row: 0x10c78bc50  session: 0x10c8009d0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,582 - logic_logger - INFO
..Item[None] {Formula amount} id: None, order_id: None, product_id: 2, quantity: 2, amount: 180.0000000000, unit_price: 90.0000000000  row: 0x10c78bc50  session: 0x10c8009d0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,582 - logic_logger - INFO
....Order[None] {Update - Adjusting order: amount_total} id: None, notes: behave test, customer_id: 6, CreatedOn: None, date_shipped: None, amount_total:  [0-->] 180.0000000000  row: 0x10c78b150  session: 0x10c8009d0  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,582 - logic_logger - INFO
......Customer[6] {Update - Adjusting customer: balance} id: 6, name: Acme 1792465580574, balance:  [0E-10-->] 180.0000000000, credit_limit: 1000.0000000000, email: None, email_opt_out: None  row: 0x10c78afd0  session: 0x10c8009d0  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,582 - logic_logger - INFO
..Item[None] {Insert - client} id: None, order_id: None, product_id: 1, quantity: 1, amount: None, unit_price: None  row: 0x10c098450  session: 0x10c8009d0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,582 - logic_logger - INFO
..Item[None] {copy_rules for role: product - unit_price} id: None, order_id: None, product_id: 1, quantity: 1, amount: None, unit_price: 150.0000000000  row: 0x10c098450  session: 0x10c8009d0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,582 - logic_logger - INFO
..Item[None] {Formula amount} id: None, order_id: None, product_id: 1, quantity: 1, amount: 150.0000000000, unit_price: 150.0000000000  row: 0x10c098450  session: 0x10c8009d0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,583 - logic_logger - INFO
....Order[None] {Update - Adjusting order: amount_total} id: None, notes: behave test, customer_id: 6, CreatedOn: None, date_shipped: None, amount_total:  [180.0000000000-->] 330.0000000000  row: 0x10c78b150  session: 0x10c8009d0  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,583 - logic_logger - INFO
......Customer[6] {Update - Adjusting customer: balance} id: 6, name: Acme 1792465580574, balance:  [180.0000000000-->] 330.0000000000, credit_limit: 1000.0000000000, email: None, email_opt_out: None  row: 0x10c78afd0  session: 0x10c8009d0  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,583 - logic_logger - INFO
Logic Phase:        COMMIT LOGIC        (session=0x10c8009d0)                                            - 2026-10-19 20:06:20,583 - logic_logger - INFO
Logic Phase:        AFTER_FLUSH LOGIC   (session=0x10c8009d0)                                            - 2026-10-19 20:06:20,584 - logic_logger - INFO
..Order[6] {AfterFlush Event} id: 6, notes: behave test, customer_id: 6, CreatedOn: None, date_shipped: None, amount_total: 330.0000000000  row: 0x10c78b150  session: 0x10c8009d0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,584 - logic_logger - INFO

   

Scenario: Partner Order For An Unknown Customer Is Rejected ✅

  Scenario: Partner Order For An Unknown Customer Is Rejected
   Given Customer "Beta" with balance 0 and credit limit 1000
   When B2B order is posted for unknown customer with 1 Widget
   Then B2B order is rejected with status 404
   Then Customer balance is 0

No rules fired in this scenario's logic log.

   

Scenario: Partner Order Exceeding Credit Limit Is Rejected ✅

  Scenario: Partner Order Exceeding Credit Limit Is Rejected
   Given Customer "Gamma" with balance 0 and credit limit 100
   When B2B order is posted for "Gamma" with 2 Widget
   Then B2B order is not accepted
   Then Customer balance is 0

Rules exercised and logic log (1 transaction)

   

Rules Used in Scenario: Partner Order Exceeding Credit Limit Is Rejected

  Customer  
    1. Derive Customer.balance as Sum(Order.amount_total Where lambda row: row.date_shipped is None))  
    2. Constraint Function: None  
  Item  
    3. Derive Item.amount as Formula (1): as_expression=lambda row: row.quantity * row.unit [...]  
    4. Derive Item.unit_price as Copy(product.unit_price)  
  Order  
    5. Derive Order.amount_total as Sum(Item.amount Where  - None)  

Logic Log in Scenario: Partner Order Exceeding Credit Limit Is Rejected (1 transaction)

Logic Phase:        ROW LOGIC       (session=0x10c773570) (sqlalchemy before_flush)          - 2026-10-19 20:06:20,606 - logic_logger - INFO
..Order[None] {Insert - client} id: None, notes: behave test, customer_id: 8, CreatedOn: None, date_shipped: None, amount_total: None  row: 0x10c78b9d0  session: 0x10c773570  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,606 - logic_logger - INFO
..Order[None] {server aggregate_defaults: amount_total } id: None, notes: behave test, customer_id: 8, CreatedOn: None, date_shipped: None, amount_total: 0  row: 0x10c78b9d0  session: 0x10c773570  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,606 - logic_logger - INFO
..Item[None] {Insert - client} id: None, order_id: None, product_id: 2, quantity: 2, amount: None, unit_price: None  row: 0x10c7f32d0  session: 0x10c773570  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,606 - logic_logger - INFO
..Item[None] {copy_rules for role: product - unit_price} id: None, order_id: None, product_id: 2, quantity: 2, amount: None, unit_price: 90.0000000000  row: 0x10c7f32d0  session: 0x10c773570  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,606 - logic_logger - INFO
..Item[None] {Formula amount} id: None, order_id: None, product_id: 2, quantity: 2, amount: 180.0000000000, unit_price: 90.0000000000  row: 0x10c7f32d0  session: 0x10c773570  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,606 - logic_logger - INFO
....Order[None] {Update - Adjusting order: amount_total} id: None, notes: behave test, customer_id: 8, CreatedOn: None, date_shipped: None, amount_total:  [0-->] 180.0000000000  row: 0x10c78b9d0  session: 0x10c773570  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,606 - logic_logger - INFO
......Customer[8] {Update - Adjusting customer: balance} id: 8, name: Gamma 1792465580602, balance:  [0E-10-->] 180.0000000000, credit_limit: 100.0000000000, email: None, email_opt_out: None  row: 0x10c7f3250  session: 0x10c773570  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,606 - logic_logger - INFO
......Customer[8] {Constraint Failure: balance (180.0000000000) exceeds credit limit (100.0000000000)} id: 8, name: Gamma 1792465580602, balance:  [0E-10-->] 180.0000000000, credit_limit: 100.0000000000, email: None, email_opt_out: None  row: 0x10c7f3250  session: 0x10c773570  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,606 - logic_logger - INFO

   

Feature: Check Credit

   

Scenario: Create Order Rolls Up To Customer Balance ✅

  Scenario: Create Order Rolls Up To Customer Balance
   Given Customer "Alice" with balance 0 and credit limit 1000
   And Order is created for "Alice"
   When Item is created with 5 Widget
   Then Item unit_price is 90
   Then Item amount is 450
   Then Order amount_total is 450
   Then Customer balance is 450

Rules exercised and logic log (2 transactions)

   

Rules Used in Scenario: Create Order Rolls Up To Customer Balance

  Customer  
    1. Derive Customer.balance as Sum(Order.amount_total Where lambda row: row.date_shipped is None))  
  Order  
    2. RowEvent Order._send_order_to_kafka()  
    3. Derive Order.amount_total as Sum(Item.amount Where  - None)  
  Item  
    4. Derive Item.amount as Formula (1): as_expression=lambda row: row.quantity * row.unit [...]  
    5. Derive Item.unit_price as Copy(product.unit_price)  

Logic Log in Scenario: Create Order Rolls Up To Customer Balance (2 transactions)

Logic Phase:        ROW LOGIC       (session=0x10c773570) (sqlalchemy before_flush)          - 2026-10-19 20:06:20,614 - logic_logger - INFO
..Order[None] {Insert - client} id: None, notes: None, customer_id: 9, CreatedOn: None, date_shipped: None, amount_total: None  row: 0x10c7f2850  session: 0x10c773570  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,614 - logic_logger - INFO
..Order[None] {server aggregate_defaults: amount_total } id: None, notes: None, customer_id: 9, CreatedOn: None, date_shipped: None, amount_total: 0  row: 0x10c7f2850  session: 0x10c773570  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,614 - logic_logger - INFO
Logic Phase:        COMMIT LOGIC        (session=0x10c773570)                                            - 2026-10-19 20:06:20,615 - logic_logger - INFO
Logic Phase:        AFTER_FLUSH LOGIC   (session=0x10c773570)                                            - 2026-10-19 20:06:20,615 - logic_logger - INFO
..Order[7] {AfterFlush Event} id: 7, notes: None, customer_id: 9, CreatedOn: None, date_shipped: None, amount_total: 0  row: 0x10c7f2850  session: 0x10c773570  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,615 - logic_logger - INFO


Logic Phase:        ROW LOGIC       (session=0x10c773350) (sqlalchemy before_flush)          - 2026-10-19 20:06:20,620 - logic_logger - INFO
..Item[None] {Insert - client} id: None, order_id: 7, product_id: 2, quantity: 5, amount: None, unit_price: None  row: 0x10c78bcd0  session: 0x10c773350  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,620 - logic_logger - INFO
..Item[None] {copy_rules for role: product - unit_price} id: None, order_id: 7, product_id: 2, quantity: 5, amount: None, unit_price: 90.0000000000  row: 0x10c78bcd0  session: 0x10c773350  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,621 - logic_logger - INFO
..Item[None] {Formula amount} id: None, order_id: 7, product_id: 2, quantity: 5, amount: 450.0000000000, unit_price: 90.0000000000  row: 0x10c78bcd0  session: 0x10c773350  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,621 - logic_logger - INFO
....Order[7] {Update - Adjusting order: amount_total} id: 7, notes: None, customer_id: 9, CreatedOn: None, date_shipped: None, amount_total:  [0E-10-->] 450.0000000000  row: 0x10c9562d0  session: 0x10c773350  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,621 - logic_logger - INFO
......Customer[9] {Update - Adjusting customer: balance} id: 9, name: Alice 1792465580610, balance:  [0E-10-->] 450.0000000000, credit_limit: 1000.0000000000, email: None, email_opt_out: None  row: 0x10c956ad0  session: 0x10c773350  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,622 - logic_logger - INFO
Logic Phase:        COMMIT LOGIC        (session=0x10c773350)                                            - 2026-10-19 20:06:20,622 - logic_logger - INFO
Logic Phase:        AFTER_FLUSH LOGIC   (session=0x10c773350)                                            - 2026-10-19 20:06:20,623 - logic_logger - INFO
....Order[7] {AfterFlush Event} id: 7, notes: None, customer_id: 9, CreatedOn: None, date_shipped: None, amount_total:  [0E-10-->] 450.0000000000  row: 0x10c9562d0  session: 0x10c773350  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,623 - logic_logger - INFO

   

Scenario: Update Item Quantity Recalculates Amounts ✅

  Scenario: Update Item Quantity Recalculates Amounts
   Given Customer "Bob" with balance 0 and credit limit 1000
   And Order is created for "Bob"
   And Item is created with 2 Widget
   When Item quantity is changed to 6
   Then Item amount is 540
   Then Order amount_total is 540
   Then Customer balance is 540

Rules exercised and logic log (3 transactions)

   

Rules Used in Scenario: Update Item Quantity Recalculates Amounts

  Customer  
    1. Derive Customer.balance as Sum(Order.amount_total Where lambda row: row.date_shipped is None))  
  Order  
    2. RowEvent Order._send_order_to_kafka()  
    3. Derive Order.amount_total as Sum(Item.amount Where  - None)  
  Item  
    4. Derive Item.amount as Formula (1): as_expression=lambda row: row.quantity * row.unit [...]  
    5. Derive Item.unit_price as Copy(product.unit_price)  

Logic Log in Scenario: Update Item Quantity Recalculates Amounts (3 transactions)

Logic Phase:        ROW LOGIC       (session=0x10c773460) (sqlalchemy before_flush)          - 2026-10-19 20:06:20,635 - logic_logger - INFO
..Order[None] {Insert - client} id: None, notes: None, customer_id: 10, CreatedOn: None, date_shipped: None, amount_total: None  row: 0x10c7f0850  session: 0x10c773460  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,635 - logic_logger - INFO
..Order[None] {server aggregate_defaults: amount_total } id: None, notes: None, customer_id: 10, CreatedOn: None, date_shipped: None, amount_total: 0  row: 0x10c7f0850  session: 0x10c773460  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,635 - logic_logger - INFO
Logic Phase:        COMMIT LOGIC        (session=0x10c773460)                                            - 2026-10-19 20:06:20,636 - logic_logger - INFO
Logic Phase:        AFTER_FLUSH LOGIC   (session=0x10c773460)                                            - 2026-10-19 20:06:20,636 - logic_logger - INFO
..Order[8] {AfterFlush Event} id: 8, notes: None, customer_id: 10, CreatedOn: None, date_shipped: None, amount_total: 0  row: 0x10c7f0850  session: 0x10c773460  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,636 - logic_logger - INFO


Logic Phase:        ROW LOGIC       (session=0x10c7738a0) (sqlalchemy before_flush)          - 2026-10-19 20:06:20,640 - logic_logger - INFO
..Item[None] {Insert - client} id: None, order_id: 8, product_id: 2, quantity: 2, amount: None, unit_price: None  row: 0x10c9551d0  session: 0x10c7738a0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,640 - logic_logger - INFO
..Item[None] {copy_rules for role: product - unit_price} id: None, order_id: 8, product_id: 2, quantity: 2, amount: None, unit_price: 90.0000000000  row: 0x10c9551d0  session: 0x10c7738a0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,641 - logic_logger - INFO
..Item[None] {Formula amount} id: None, order_id: 8, product_id: 2, quantity: 2, amount: 180.0000000000, unit_price: 90.0000000000  row: 0x10c9551d0  session: 0x10c7738a0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,641 - logic_logger - INFO
....Order[8] {Update - Adjusting order: amount_total} id: 8, notes: None, customer_id: 10, CreatedOn: None, date_shipped: None, amount_total:  [0E-10-->] 180.0000000000  row: 0x10c9574d0  session: 0x10c7738a0  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,641 - logic_logger - INFO
......Customer[10] {Update - Adjusting customer: balance} id: 10, name: Bob 1792465580632, balance:  [0E-10-->] 180.0000000000, credit_limit: 1000.0000000000, email: None, email_opt_out: None  row: 0x10c9bc950  session: 0x10c7738a0  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,641 - logic_logger - INFO
Logic Phase:        COMMIT LOGIC        (session=0x10c7738a0)                                            - 2026-10-19 20:06:20,641 - logic_logger - INFO
Logic Phase:        AFTER_FLUSH LOGIC   (session=0x10c7738a0)                                            - 2026-10-19 20:06:20,642 - logic_logger - INFO
....Order[8] {AfterFlush Event} id: 8, notes: None, customer_id: 10, CreatedOn: None, date_shipped: None, amount_total:  [0E-10-->] 180.0000000000  row: 0x10c9574d0  session: 0x10c7738a0  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,642 - logic_logger - INFO


Logic Phase:        ROW LOGIC       (session=0x10c9c0270) (sqlalchemy before_flush)          - 2026-10-19 20:06:20,644 - logic_logger - INFO
..Item[9] {Update - client} id: 9, order_id: 8, product_id: 2, quantity:  [2-->] 6, amount: 180.0000000000, unit_price: 90.0000000000  row: 0x10c9bc250  session: 0x10c9c0270  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,644 - logic_logger - INFO
..Item[9] {Formula amount} id: 9, order_id: 8, product_id: 2, quantity:  [2-->] 6, amount:  [180.0000000000-->] 540.0000000000, unit_price: 90.0000000000  row: 0x10c9bc250  session: 0x10c9c0270  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,645 - logic_logger - INFO
....Order[8] {Update - Adjusting order: amount_total} id: 8, notes: None, customer_id: 10, CreatedOn: None, date_shipped: None, amount_total:  [180.0000000000-->] 540.0000000000  row: 0x10c9bcb50  session: 0x10c9c0270  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,645 - logic_logger - INFO
......Customer[10] {Update - Adjusting customer: balance} id: 10, name: Bob 1792465580632, balance:  [180.0000000000-->] 540.0000000000, credit_limit: 1000.0000000000, email: None, email_opt_out: None  row: 0x10c9bd850  session: 0x10c9c0270  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,645 - logic_logger - INFO
Logic Phase:        COMMIT LOGIC        (session=0x10c9c0270)                                            - 2026-10-19 20:06:20,645 - logic_logger - INFO
Logic Phase:        AFTER_FLUSH LOGIC   (session=0x10c9c0270)                                            - 2026-10-19 20:06:20,646 - logic_logger - INFO
....Order[8] {AfterFlush Event} id: 8, notes: None, customer_id: 10, CreatedOn: None, date_shipped: None, amount_total:  [180.0000000000-->] 540.0000000000  row: 0x10c9bcb50  session: 0x10c9c0270  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,646 - logic_logger - INFO

   

Scenario: Update Item Product Recopies Unit Price ✅

  Scenario: Update Item Product Recopies Unit Price
   Given Customer "Carol" with balance 0 and credit limit 1000
   And Order is created for "Carol"
   And Item is created with 3 Widget
   When Item product is changed to Gadget
   Then Item unit_price is 150
   Then Item amount is 450
   Then Order amount_total is 450
   Then Customer balance is 450

Rules exercised and logic log (3 transactions)

   

Rules Used in Scenario: Update Item Product Recopies Unit Price

  Customer  
    1. Derive Customer.balance as Sum(Order.amount_total Where lambda row: row.date_shipped is None))  
  Order  
    2. RowEvent Order._send_order_to_kafka()  
    3. Derive Order.amount_total as Sum(Item.amount Where  - None)  
  Item  
    4. Derive Item.amount as Formula (1): as_expression=lambda row: row.quantity * row.unit [...]  
    5. Derive Item.unit_price as Copy(product.unit_price)  

Logic Log in Scenario: Update Item Product Recopies Unit Price (3 transactions)

Logic Phase:        ROW LOGIC       (session=0x10c9c09e0) (sqlalchemy before_flush)          - 2026-10-19 20:06:20,656 - logic_logger - INFO
..Order[None] {Insert - client} id: None, notes: None, customer_id: 11, CreatedOn: None, date_shipped: None, amount_total: None  row: 0x10c954050  session: 0x10c9c09e0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,656 - logic_logger - INFO
..Order[None] {server aggregate_defaults: amount_total } id: None, notes: None, customer_id: 11, CreatedOn: None, date_shipped: None, amount_total: 0  row: 0x10c954050  session: 0x10c9c09e0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,656 - logic_logger - INFO
Logic Phase:        COMMIT LOGIC        (session=0x10c9c09e0)                                            - 2026-10-19 20:06:20,656 - logic_logger - INFO
Logic Phase:        AFTER_FLUSH LOGIC   (session=0x10c9c09e0)                                            - 2026-10-19 20:06:20,657 - logic_logger - INFO
..Order[9] {AfterFlush Event} id: 9, notes: None, customer_id: 11, CreatedOn: None, date_shipped: None, amount_total: 0  row: 0x10c954050  session: 0x10c9c09e0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,657 - logic_logger - INFO


Logic Phase:        ROW LOGIC       (session=0x10c9c07c0) (sqlalchemy before_flush)          - 2026-10-19 20:06:20,661 - logic_logger - INFO
..Item[None] {Insert - client} id: None, order_id: 9, product_id: 2, quantity: 3, amount: None, unit_price: None  row: 0x10c956350  session: 0x10c9c07c0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,661 - logic_logger - INFO
..Item[None] {copy_rules for role: product - unit_price} id: None, order_id: 9, product_id: 2, quantity: 3, amount: None, unit_price: 90.0000000000  row: 0x10c956350  session: 0x10c9c07c0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,661 - logic_logger - INFO
..Item[None] {Formula amount} id: None, order_id: 9, product_id: 2, quantity: 3, amount: 270.0000000000, unit_price: 90.0000000000  row: 0x10c956350  session: 0x10c9c07c0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,662 - logic_logger - INFO
....Order[9] {Update - Adjusting order: amount_total} id: 9, notes: None, customer_id: 11, CreatedOn: None, date_shipped: None, amount_total:  [0E-10-->] 270.0000000000  row: 0x10c9bc750  session: 0x10c9c07c0  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,662 - logic_logger - INFO
......Customer[11] {Update - Adjusting customer: balance} id: 11, name: Carol 1792465580652, balance:  [0E-10-->] 270.0000000000, credit_limit: 1000.0000000000, email: None, email_opt_out: None  row: 0x10c7f0b50  session: 0x10c9c07c0  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,662 - logic_logger - INFO
Logic Phase:        COMMIT LOGIC        (session=0x10c9c07c0)                                            - 2026-10-19 20:06:20,662 - logic_logger - INFO
Logic Phase:        AFTER_FLUSH LOGIC   (session=0x10c9c07c0)                                            - 2026-10-19 20:06:20,662 - logic_logger - INFO
....Order[9] {AfterFlush Event} id: 9, notes: None, customer_id: 11, CreatedOn: None, date_shipped: None, amount_total:  [0E-10-->] 270.0000000000  row: 0x10c9bc750  session: 0x10c9c07c0  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,662 - logic_logger - INFO


Logic Phase:        ROW LOGIC       (session=0x10c772580) (sqlalchemy before_flush)          - 2026-10-19 20:06:20,666 - logic_logger - INFO
..Item[10] {Update - client} id: 10, order_id: 9, product_id:  [2-->] 1, quantity: 3, amount: 270.0000000000, unit_price: 90.0000000000  row: 0x10c9bc050  session: 0x10c772580  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,666 - logic_logger - INFO
..Item[10] {copy_rules for role: product - unit_price} id: 10, order_id: 9, product_id:  [2-->] 1, quantity: 3, amount: 270.0000000000, unit_price:  [90.0000000000-->] 150.0000000000  row: 0x10c9bc050  session: 0x10c772580  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,667 - logic_logger - INFO
..Item[10] {Formula amount} id: 10, order_id: 9, product_id:  [2-->] 1, quantity: 3, amount:  [270.0000000000-->] 450.0000000000, unit_price:  [90.0000000000-->] 150.0000000000  row: 0x10c9bc050  session: 0x10c772580  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,667 - logic_logger - INFO
....Order[9] {Update - Adjusting order: amount_total} id: 9, notes: None, customer_id: 11, CreatedOn: None, date_shipped: None, amount_total:  [270.0000000000-->] 450.0000000000  row: 0x10c9bda50  session: 0x10c772580  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,667 - logic_logger - INFO
......Customer[11] {Update - Adjusting customer: balance} id: 11, name: Carol 1792465580652, balance:  [270.0000000000-->] 450.0000000000, credit_limit: 1000.0000000000, email: None, email_opt_out: None  row: 0x10c9bdcd0  session: 0x10c772580  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,667 - logic_logger - INFO
Logic Phase:        COMMIT LOGIC        (session=0x10c772580)                                            - 2026-10-19 20:06:20,667 - logic_logger - INFO
Logic Phase:        AFTER_FLUSH LOGIC   (session=0x10c772580)                                            - 2026-10-19 20:06:20,668 - logic_logger - INFO
....Order[9] {AfterFlush Event} id: 9, notes: None, customer_id: 11, CreatedOn: None, date_shipped: None, amount_total:  [270.0000000000-->] 450.0000000000  row: 0x10c9bda50  session: 0x10c772580  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,668 - logic_logger - INFO

   

Scenario: Delete Item Reduces Order And Balance ✅

  Scenario: Delete Item Reduces Order And Balance
   Given Customer "Dave" with balance 0 and credit limit 1000
   And Order is created for "Dave"
   And Item is created with 4 Widget
   When Item is deleted
   Then Order amount_total is 0
   Then Customer balance is 0

Rules exercised and logic log (3 transactions)

   

Rules Used in Scenario: Delete Item Reduces Order And Balance

  Customer  
    1. Derive Customer.balance as Sum(Order.amount_total Where lambda row: row.date_shipped is None))  
  Order  
    2. RowEvent Order._send_order_to_kafka()  
    3. Derive Order.amount_total as Sum(Item.amount Where  - None)  
  Item  
    4. Derive Item.amount as Formula (1): as_expression=lambda row: row.quantity * row.unit [...]  
    5. Derive Item.unit_price as Copy(product.unit_price)  

Logic Log in Scenario: Delete Item Reduces Order And Balance (3 transactions)

Logic Phase:        ROW LOGIC       (session=0x10c7738a0) (sqlalchemy before_flush)          - 2026-10-19 20:06:20,678 - logic_logger - INFO
..Order[None] {Insert - client} id: None, notes: None, customer_id: 12, CreatedOn: None, date_shipped: None, amount_total: None  row: 0x10c9568d0  session: 0x10c7738a0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,678 - logic_logger - INFO
..Order[None] {server aggregate_defaults: amount_total } id: None, notes: None, customer_id: 12, CreatedOn: None, date_shipped: None, amount_total: 0  row: 0x10c9568d0  session: 0x10c7738a0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,678 - logic_logger - INFO
Logic Phase:        COMMIT LOGIC        (session=0x10c7738a0)                                            - 2026-10-19 20:06:20,679 - logic_logger - INFO
Logic Phase:        AFTER_FLUSH LOGIC   (session=0x10c7738a0)                                            - 2026-10-19 20:06:20,679 - logic_logger - INFO
..Order[10] {AfterFlush Event} id: 10, notes: None, customer_id: 12, CreatedOn: None, date_shipped: None, amount_total: 0  row: 0x10c9568d0  session: 0x10c7738a0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,679 - logic_logger - INFO


Logic Phase:        ROW LOGIC       (session=0x10c9c0af0) (sqlalchemy before_flush)          - 2026-10-19 20:06:20,683 - logic_logger - INFO
..Item[None] {Insert - client} id: None, order_id: 10, product_id: 2, quantity: 4, amount: None, unit_price: None  row: 0x10c955dd0  session: 0x10c9c0af0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,683 - logic_logger - INFO
..Item[None] {copy_rules for role: product - unit_price} id: None, order_id: 10, product_id: 2, quantity: 4, amount: None, unit_price: 90.0000000000  row: 0x10c955dd0  session: 0x10c9c0af0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,684 - logic_logger - INFO
..Item[None] {Formula amount} id: None, order_id: 10, product_id: 2, quantity: 4, amount: 360.0000000000, unit_price: 90.0000000000  row: 0x10c955dd0  session: 0x10c9c0af0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,684 - logic_logger - INFO
....Order[10] {Update - Adjusting order: amount_total} id: 10, notes: None, customer_id: 12, CreatedOn: None, date_shipped: None, amount_total:  [0E-10-->] 360.0000000000  row: 0x10c9bc550  session: 0x10c9c0af0  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,684 - logic_logger - INFO
......Customer[12] {Update - Adjusting customer: balance} id: 12, name: Dave 1792465580675, balance:  [0E-10-->] 360.0000000000, credit_limit: 1000.0000000000, email: None, email_opt_out: None  row: 0x10c9be6d0  session: 0x10c9c0af0  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,684 - logic_logger - INFO
Logic Phase:        COMMIT LOGIC        (session=0x10c9c0af0)                                            - 2026-10-19 20:06:20,684 - logic_logger - INFO
Logic Phase:        AFTER_FLUSH LOGIC   (session=0x10c9c0af0)                                            - 2026-10-19 20:06:20,685 - logic_logger - INFO
....Order[10] {AfterFlush Event} id: 10, notes: None, customer_id: 12, CreatedOn: None, date_shipped: None, amount_total:  [0E-10-->] 360.0000000000  row: 0x10c9bc550  session: 0x10c9c0af0  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,685 - logic_logger - INFO


Logic Phase:        ROW LOGIC       (session=0x10c9c0380) (sqlalchemy before_flush)          - 2026-10-19 20:06:20,687 - logic_logger - INFO
..Item[11] {Delete - client} id: 11, order_id: 10, product_id: 2, quantity: 4, amount: 360.0000000000, unit_price: 90.0000000000  row: 0x10c9bc9d0  session: 0x10c9c0380  ins_upd_dlt: dlt, initial: dlt - 2026-10-19 20:06:20,687 - logic_logger - INFO
....Order[10] {Update - Adjusting order: amount_total} id: 10, notes: None, customer_id: 12, CreatedOn: None, date_shipped: None, amount_total:  [360.0000000000-->] 0E-10  row: 0x10c9bded0  session: 0x10c9c0380  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,687 - logic_logger - INFO
......Customer[12] {Update - Adjusting customer: balance} id: 12, name: Dave 1792465580675, balance:  [360.0000000000-->] 0E-10, credit_limit: 1000.0000000000, email: None, email_opt_out: None  row: 0x10c9bead0  session: 0x10c9c0380  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,688 - logic_logger - INFO
Logic Phase:        COMMIT LOGIC        (session=0x10c9c0380)                                            - 2026-10-19 20:06:20,688 - logic_logger - INFO
Logic Phase:        AFTER_FLUSH LOGIC   (session=0x10c9c0380)                                            - 2026-10-19 20:06:20,688 - logic_logger - INFO
....Order[10] {AfterFlush Event} id: 10, notes: None, customer_id: 12, CreatedOn: None, date_shipped: None, amount_total:  [360.0000000000-->] 0E-10  row: 0x10c9bded0  session: 0x10c9c0380  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,688 - logic_logger - INFO

   

Scenario: Change Order Customer Adjusts Both Balances ✅

  Scenario: Change Order Customer Adjusts Both Balances
   Given Customer "Erin" with balance 0 and credit limit 1000
   And Customer "Frank" with balance 0 and credit limit 1000
   And Order is created for "Erin"
   And Item is created with 5 Widget
   When Order customer is changed to "Frank"
   Then Customer "Erin" balance is 0
   Then Customer "Frank" balance is 450

Rules exercised and logic log (3 transactions)

   

Rules Used in Scenario: Change Order Customer Adjusts Both Balances

  Customer  
    1. Derive Customer.balance as Sum(Order.amount_total Where lambda row: row.date_shipped is None))  
  Order  
    2. RowEvent Order._send_order_to_kafka()  
    3. Derive Order.amount_total as Sum(Item.amount Where  - None)  
  Item  
    4. Derive Item.amount as Formula (1): as_expression=lambda row: row.quantity * row.unit [...]  
    5. Derive Item.unit_price as Copy(product.unit_price)  

Logic Log in Scenario: Change Order Customer Adjusts Both Balances (3 transactions)

Logic Phase:        ROW LOGIC       (session=0x10c9c0e20) (sqlalchemy before_flush)          - 2026-10-19 20:06:20,700 - logic_logger - INFO
..Order[None] {Insert - client} id: None, notes: None, customer_id: 13, CreatedOn: None, date_shipped: None, amount_total: None  row: 0x10c9be650  session: 0x10c9c0e20  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,700 - logic_logger - INFO
..Order[None] {server aggregate_defaults: amount_total } id: None, notes: None, customer_id: 13, CreatedOn: None, date_shipped: None, amount_total: 0  row: 0x10c9be650  session: 0x10c9c0e20  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,700 - logic_logger - INFO
Logic Phase:        COMMIT LOGIC        (session=0x10c9c0e20)                                            - 2026-10-19 20:06:20,700 - logic_logger - INFO
Logic Phase:        AFTER_FLUSH LOGIC   (session=0x10c9c0e20)                                            - 2026-10-19 20:06:20,700 - logic_logger - INFO
..Order[11] {AfterFlush Event} id: 11, notes: None, customer_id: 13, CreatedOn: None, date_shipped: None, amount_total: 0  row: 0x10c9be650  session: 0x10c9c0e20  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,700 - logic_logger - INFO


Logic Phase:        ROW LOGIC       (session=0x10c9c0f30) (sqlalchemy before_flush)          - 2026-10-19 20:06:20,704 - logic_logger - INFO
..Item[None] {Insert - client} id: None, order_id: 11, product_id: 2, quantity: 5, amount: None, unit_price: None  row: 0x10c9bcb50  session: 0x10c9c0f30  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,704 - logic_logger - INFO
..Item[None] {copy_rules for role: product - unit_price} id: None, order_id: 11, product_id: 2, quantity: 5, amount: None, unit_price: 90.0000000000  row: 0x10c9bcb50  session: 0x10c9c0f30  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,705 - logic_logger - INFO
..Item[None] {Formula amount} id: None, order_id: 11, product_id: 2, quantity: 5, amount: 450.0000000000, unit_price: 90.0000000000  row: 0x10c9bcb50  session: 0x10c9c0f30  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,705 - logic_logger - INFO
....Order[11] {Update - Adjusting order: amount_total} id: 11, notes: None, customer_id: 13, CreatedOn: None, date_shipped: None, amount_total:  [0E-10-->] 450.0000000000  row: 0x10c9bdf50  session: 0x10c9c0f30  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,705 - logic_logger - INFO
......Customer[13] {Update - Adjusting customer: balance} id: 13, name: Erin 1792465580693, balance:  [0E-10-->] 450.0000000000, credit_limit: 1000.0000000000, email: None, email_opt_out: None  row: 0x10c9bee50  session: 0x10c9c0f30  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,705 - logic_logger - INFO
Logic Phase:        COMMIT LOGIC        (session=0x10c9c0f30)                                            - 2026-10-19 20:06:20,705 - logic_logger - INFO
Logic Phase:        AFTER_FLUSH LOGIC   (session=0x10c9c0f30)                                            - 2026-10-19 20:06:20,706 - logic_logger - INFO
....Order[11] {AfterFlush Event} id: 11, notes: None, customer_id: 13, CreatedOn: None, date_shipped: None, amount_total:  [0E-10-->] 450.0000000000  row: 0x10c9bdf50  session: 0x10c9c0f30  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,706 - logic_logger - INFO


Logic Phase:        ROW LOGIC       (session=0x10c7738a0) (sqlalchemy before_flush)          - 2026-10-19 20:06:20,708 - logic_logger - INFO
..Order[11] {Update - client} id: 11, notes: None, customer_id:  [13-->] 14, CreatedOn: None, date_shipped: None, amount_total: 450.0000000000  row: 0x10c9bf2d0  session: 0x10c7738a0  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,708 - logic_logger - INFO
....Customer[14] {Update - Adjusting customer: balance, balance} id: 14, name: Frank 1792465580696, balance:  [0E-10-->] 450.0000000000, credit_limit: 1000.0000000000, email: None, email_opt_out: None  row: 0x10c9beed0  session: 0x10c7738a0  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,709 - logic_logger - INFO
....Customer[13] {Update - Adjusting Old customer} id: 13, name: Erin 1792465580693, balance:  [450.0000000000-->] 0E-10, credit_limit: 1000.0000000000, email: None, email_opt_out: None  row: 0x10c9be250  session: 0x10c7738a0  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,709 - logic_logger - INFO
Logic Phase:        COMMIT LOGIC        (session=0x10c7738a0)                                            - 2026-10-19 20:06:20,709 - logic_logger - INFO
Logic Phase:        AFTER_FLUSH LOGIC   (session=0x10c7738a0)                                            - 2026-10-19 20:06:20,709 - logic_logger - INFO
..Order[11] {AfterFlush Event} id: 11, notes: None, customer_id:  [13-->] 14, CreatedOn: None, date_shipped: None, amount_total: 450.0000000000  row: 0x10c9bf2d0  session: 0x10c7738a0  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,710 - logic_logger - INFO

   

Scenario: Ship Order Excludes From Balance ✅

  Scenario: Ship Order Excludes From Balance
   Given Customer "Grace" with balance 0 and credit limit 1000
   And Order is created for "Grace"
   And Item is created with 5 Widget
   When Order is shipped
   Then Customer balance is 0

Rules exercised and logic log (3 transactions)

   

Rules Used in Scenario: Ship Order Excludes From Balance

  Customer  
    1. Derive Customer.balance as Sum(Order.amount_total Where lambda row: row.date_shipped is None))  
  Order  
    2. RowEvent Order._send_order_to_kafka()  
    3. Derive Order.amount_total as Sum(Item.amount Where  - None)  
  Item  
    4. Derive Item.amount as Formula (1): as_expression=lambda row: row.quantity * row.unit [...]  
    5. Derive Item.unit_price as Copy(product.unit_price)  

Logic Log in Scenario: Ship Order Excludes From Balance (3 transactions)

Logic Phase:        ROW LOGIC       (session=0x10c773680) (sqlalchemy before_flush)          - 2026-10-19 20:06:20,719 - logic_logger - INFO
..Order[None] {Insert - client} id: None, notes: None, customer_id: 15, CreatedOn: None, date_shipped: None, amount_total: None  row: 0x10c9577d0  session: 0x10c773680  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,719 - logic_logger - INFO
..Order[None] {server aggregate_defaults: amount_total } id: None, notes: None, customer_id: 15, CreatedOn: None, date_shipped: None, amount_total: 0  row: 0x10c9577d0  session: 0x10c773680  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,719 - logic_logger - INFO
Logic Phase:        COMMIT LOGIC        (session=0x10c773680)                                            - 2026-10-19 20:06:20,719 - logic_logger - INFO
Logic Phase:        AFTER_FLUSH LOGIC   (session=0x10c773680)                                            - 2026-10-19 20:06:20,720 - logic_logger - INFO
..Order[12] {AfterFlush Event} id: 12, notes: None, customer_id: 15, CreatedOn: None, date_shipped: None, amount_total: 0  row: 0x10c9577d0  session: 0x10c773680  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,720 - logic_logger - INFO


Logic Phase:        ROW LOGIC       (session=0x10c9c0270) (sqlalchemy before_flush)          - 2026-10-19 20:06:20,723 - logic_logger - INFO
..Item[None] {Insert - client} id: None, order_id: 12, product_id: 2, quantity: 5, amount: None, unit_price: None  row: 0x10c9548d0  session: 0x10c9c0270  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,723 - logic_logger - INFO
..Item[None] {copy_rules for role: product - unit_price} id: None, order_id: 12, product_id: 2, quantity: 5, amount: None, unit_price: 90.0000000000  row: 0x10c9548d0  session: 0x10c9c0270  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,724 - logic_logger - INFO
..Item[None] {Formula amount} id: None, order_id: 12, product_id: 2, quantity: 5, amount: 450.0000000000, unit_price: 90.0000000000  row: 0x10c9548d0  session: 0x10c9c0270  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,724 - logic_logger - INFO
....Order[12] {Update - Adjusting order: amount_total} id: 12, notes: None, customer_id: 15, CreatedOn: None, date_shipped: None, amount_total:  [0E-10-->] 450.0000000000  row: 0x10c9be150  session: 0x10c9c0270  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,724 - logic_logger - INFO
......Customer[15] {Update - Adjusting customer: balance} id: 15, name: Grace 1792465580715, balance:  [0E-10-->] 450.0000000000, credit_limit: 1000.0000000000, email: None, email_opt_out: None  row: 0x10c9be6d0  session: 0x10c9c0270  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,724 - logic_logger - INFO
Logic Phase:        COMMIT LOGIC        (session=0x10c9c0270)                                            - 2026-10-19 20:06:20,724 - logic_logger - INFO
Logic Phase:        AFTER_FLUSH LOGIC   (session=0x10c9c0270)                                            - 2026-10-19 20:06:20,725 - logic_logger - INFO
....Order[12] {AfterFlush Event} id: 12, notes: None, customer_id: 15, CreatedOn: None, date_shipped: None, amount_total:  [0E-10-->] 450.0000000000  row: 0x10c9be150  session: 0x10c9c0270  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,725 - logic_logger - INFO


Logic Phase:        ROW LOGIC       (session=0x10c9c0050) (sqlalchemy before_flush)          - 2026-10-19 20:06:20,728 - logic_logger - INFO
..Order[12] {Update - client} id: 12, notes: None, customer_id: 15, CreatedOn: None, date_shipped:  [None-->] 2026-01-01 00:00:00, amount_total: 450.0000000000  row: 0x10c9bded0  session: 0x10c9c0050  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,728 - logic_logger - INFO
....Customer[15] {Update - Adjusting customer: balance} id: 15, name: Grace 1792465580715, balance:  [450.0000000000-->] 0E-10, credit_limit: 1000.0000000000, email: None, email_opt_out: None  row: 0x10c9bf950  session: 0x10c9c0050  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,728 - logic_logger - INFO
Logic Phase:        COMMIT LOGIC        (session=0x10c9c0050)                                            - 2026-10-19 20:06:20,728 - logic_logger - INFO
Logic Phase:        AFTER_FLUSH LOGIC   (session=0x10c9c0050)                                            - 2026-10-19 20:06:20,729 - logic_logger - INFO
..Order[12] {AfterFlush Event} id: 12, notes: None, customer_id: 15, CreatedOn: None, date_shipped:  [None-->] 2026-01-01 00:00:00, amount_total: 450.0000000000  row: 0x10c9bded0  session: 0x10c9c0050  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,729 - logic_logger - INFO
..Order[12] {publish_kafka_message: topic='order_shipping', key={'id': 12}} id: 12, notes: None, customer_id: 15, CreatedOn: None, date_shipped:  [None-->] 2026-01-01 00:00:00, amount_total: 450.0000000000  row: 0x10c9bded0  session: 0x10c9c0050  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,739 - logic_logger - INFO

   

Scenario: Unship Order Includes In Balance ✅

  Scenario: Unship Order Includes In Balance
   Given Customer "Heidi" with balance 0 and credit limit 1000
   And Order is created for "Heidi"
   And Item is created with 5 Widget
   And Order is shipped
   When Order is unshipped
   Then Customer balance is 450

Rules exercised and logic log (4 transactions)

   

Rules Used in Scenario: Unship Order Includes In Balance

  Customer  
    1. Derive Customer.balance as Sum(Order.amount_total Where lambda row: row.date_shipped is None))  
  Order  
    2. RowEvent Order._send_order_to_kafka()  
    3. Derive Order.amount_total as Sum(Item.amount Where  - None)  
  Item  
    4. Derive Item.amount as Formula (1): as_expression=lambda row: row.quantity * row.unit [...]  
    5. Derive Item.unit_price as Copy(product.unit_price)  

Logic Log in Scenario: Unship Order Includes In Balance (4 transactions)

Logic Phase:        ROW LOGIC       (session=0x10c9c1480) (sqlalchemy before_flush)          - 2026-10-19 20:06:20,748 - logic_logger - INFO
..Order[None] {Insert - client} id: None, notes: None, customer_id: 16, CreatedOn: None, date_shipped: None, amount_total: None  row: 0x10c9568d0  session: 0x10c9c1480  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,748 - logic_logger - INFO
..Order[None] {server aggregate_defaults: amount_total } id: None, notes: None, customer_id: 16, CreatedOn: None, date_shipped: None, amount_total: 0  row: 0x10c9568d0  session: 0x10c9c1480  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,748 - logic_logger - INFO
Logic Phase:        COMMIT LOGIC        (session=0x10c9c1480)                                            - 2026-10-19 20:06:20,748 - logic_logger - INFO
Logic Phase:        AFTER_FLUSH LOGIC   (session=0x10c9c1480)                                            - 2026-10-19 20:06:20,748 - logic_logger - INFO
..Order[13] {AfterFlush Event} id: 13, notes: None, customer_id: 16, CreatedOn: None, date_shipped: None, amount_total: 0  row: 0x10c9568d0  session: 0x10c9c1480  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,748 - logic_logger - INFO


Logic Phase:        ROW LOGIC       (session=0x10c9c16a0) (sqlalchemy before_flush)          - 2026-10-19 20:06:20,752 - logic_logger - INFO
..Item[None] {Insert - client} id: None, order_id: 13, product_id: 2, quantity: 5, amount: None, unit_price: None  row: 0x10c9bd8d0  session: 0x10c9c16a0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,752 - logic_logger - INFO
..Item[None] {copy_rules for role: product - unit_price} id: None, order_id: 13, product_id: 2, quantity: 5, amount: None, unit_price: 90.0000000000  row: 0x10c9bd8d0  session: 0x10c9c16a0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,753 - logic_logger - INFO
..Item[None] {Formula amount} id: None, order_id: 13, product_id: 2, quantity: 5, amount: 450.0000000000, unit_price: 90.0000000000  row: 0x10c9bd8d0  session: 0x10c9c16a0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,753 - logic_logger - INFO
....Order[13] {Update - Adjusting order: amount_total} id: 13, notes: None, customer_id: 16, CreatedOn: None, date_shipped: None, amount_total:  [0E-10-->] 450.0000000000  row: 0x10c9befd0  session: 0x10c9c16a0  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,753 - logic_logger - INFO
......Customer[16] {Update - Adjusting customer: balance} id: 16, name: Heidi 1792465580744, balance:  [0E-10-->] 450.0000000000, credit_limit: 1000.0000000000, email: None, email_opt_out: None  row: 0x10ca18d50  session: 0x10c9c16a0  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,753 - logic_logger - INFO
Logic Phase:        COMMIT LOGIC        (session=0x10c9c16a0)                                            - 2026-10-19 20:06:20,754 - logic_logger - INFO
Logic Phase:        AFTER_FLUSH LOGIC   (session=0x10c9c16a0)                                            - 2026-10-19 20:06:20,754 - logic_logger - INFO
....Order[13] {AfterFlush Event} id: 13, notes: None, customer_id: 16, CreatedOn: None, date_shipped: None, amount_total:  [0E-10-->] 450.0000000000  row: 0x10c9befd0  session: 0x10c9c16a0  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,754 - logic_logger - INFO


Logic Phase:        ROW LOGIC       (session=0x10c773680) (sqlalchemy before_flush)          - 2026-10-19 20:06:20,757 - logic_logger - INFO
..Order[13] {Update - client} id: 13, notes: None, customer_id: 16, CreatedOn: None, date_shipped:  [None-->] 2026-01-01 00:00:00, amount_total: 450.0000000000  row: 0x10c9be3d0  session: 0x10c773680  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,757 - logic_logger - INFO
....Customer[16] {Update - Adjusting customer: balance} id: 16, name: Heidi 1792465580744, balance:  [450.0000000000-->] 0E-10, credit_limit: 1000.0000000000, email: None, email_opt_out: None  row: 0x10c9bea50  session: 0x10c773680  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,758 - logic_logger - INFO
Logic Phase:        COMMIT LOGIC        (session=0x10c773680)                                            - 2026-10-19 20:06:20,758 - logic_logger - INFO
Logic Phase:        AFTER_FLUSH LOGIC   (session=0x10c773680)                                            - 2026-10-19 20:06:20,758 - logic_logger - INFO
..Order[13] {AfterFlush Event} id: 13, notes: None, customer_id: 16, CreatedOn: None, date_shipped:  [None-->] 2026-01-01 00:00:00, amount_total: 450.0000000000  row: 0x10c9be3d0  session: 0x10c773680  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,758 - logic_logger - INFO
..Order[13] {publish_kafka_message: topic='order_shipping', key={'id': 13}} id: 13, notes: None, customer_id: 16, CreatedOn: None, date_shipped:  [None-->] 2026-01-01 00:00:00, amount_total: 450.0000000000  row: 0x10c9be3d0  session: 0x10c773680  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,760 - logic_logger - INFO


Logic Phase:        ROW LOGIC       (session=0x10c773460) (sqlalchemy before_flush)          - 2026-10-19 20:06:20,763 - logic_logger - INFO
..Order[13] {Update - client} id: 13, notes: None, customer_id: 16, CreatedOn: None, date_shipped:  [2026-01-01-->] None, amount_total: 450.0000000000  row: 0x10c9be8d0  session: 0x10c773460  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,763 - logic_logger - INFO
....Customer[16] {Update - Adjusting customer: balance} id: 16, name: Heidi 1792465580744, balance:  [0E-10-->] 450.0000000000, credit_limit: 1000.0000000000, email: None, email_opt_out: None  row: 0x10c9bde50  session: 0x10c773460  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,763 - logic_logger - INFO
Logic Phase:        COMMIT LOGIC        (session=0x10c773460)                                            - 2026-10-19 20:06:20,763 - logic_logger - INFO
Logic Phase:        AFTER_FLUSH LOGIC   (session=0x10c773460)                                            - 2026-10-19 20:06:20,764 - logic_logger - INFO
..Order[13] {AfterFlush Event} id: 13, notes: None, customer_id: 16, CreatedOn: None, date_shipped:  [2026-01-01-->] None, amount_total: 450.0000000000  row: 0x10c9be8d0  session: 0x10c773460  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,764 - logic_logger - INFO

   

Scenario: Order Within Credit Limit Is Accepted ✅

  Scenario: Order Within Credit Limit Is Accepted
   Given Customer "Ivan" with balance 0 and credit limit 1000
   And Order is created for "Ivan"
   When Item is created with 10 Widget
   Then Order creation succeeded
   Then Customer balance is 900

Rules exercised and logic log (2 transactions)

   

Rules Used in Scenario: Order Within Credit Limit Is Accepted

  Customer  
    1. Derive Customer.balance as Sum(Order.amount_total Where lambda row: row.date_shipped is None))  
  Order  
    2. RowEvent Order._send_order_to_kafka()  
    3. Derive Order.amount_total as Sum(Item.amount Where  - None)  
  Item  
    4. Derive Item.amount as Formula (1): as_expression=lambda row: row.quantity * row.unit [...]  
    5. Derive Item.unit_price as Copy(product.unit_price)  

Logic Log in Scenario: Order Within Credit Limit Is Accepted (2 transactions)

Logic Phase:        ROW LOGIC       (session=0x10c9c05a0) (sqlalchemy before_flush)          - 2026-10-19 20:06:20,771 - logic_logger - INFO
..Order[None] {Insert - client} id: None, notes: None, customer_id: 17, CreatedOn: None, date_shipped: None, amount_total: None  row: 0x10c9557d0  session: 0x10c9c05a0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,771 - logic_logger - INFO
..Order[None] {server aggregate_defaults: amount_total } id: None, notes: None, customer_id: 17, CreatedOn: None, date_shipped: None, amount_total: 0  row: 0x10c9557d0  session: 0x10c9c05a0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,771 - logic_logger - INFO
Logic Phase:        COMMIT LOGIC        (session=0x10c9c05a0)                                            - 2026-10-19 20:06:20,772 - logic_logger - INFO
Logic Phase:        AFTER_FLUSH LOGIC   (session=0x10c9c05a0)                                            - 2026-10-19 20:06:20,772 - logic_logger - INFO
..Order[14] {AfterFlush Event} id: 14, notes: None, customer_id: 17, CreatedOn: None, date_shipped: None, amount_total: 0  row: 0x10c9557d0  session: 0x10c9c05a0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,772 - logic_logger - INFO


Logic Phase:        ROW LOGIC       (session=0x10c9c08d0) (sqlalchemy before_flush)          - 2026-10-19 20:06:20,776 - logic_logger - INFO
..Item[None] {Insert - client} id: None, order_id: 14, product_id: 2, quantity: 10, amount: None, unit_price: None  row: 0x10c954cd0  session: 0x10c9c08d0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,776 - logic_logger - INFO
..Item[None] {copy_rules for role: product - unit_price} id: None, order_id: 14, product_id: 2, quantity: 10, amount: None, unit_price: 90.0000000000  row: 0x10c954cd0  session: 0x10c9c08d0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,777 - logic_logger - INFO
..Item[None] {Formula amount} id: None, order_id: 14, product_id: 2, quantity: 10, amount: 900.0000000000, unit_price: 90.0000000000  row: 0x10c954cd0  session: 0x10c9c08d0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,777 - logic_logger - INFO
....Order[14] {Update - Adjusting order: amount_total} id: 14, notes: None, customer_id: 17, CreatedOn: None, date_shipped: None, amount_total:  [0E-10-->] 900.0000000000  row: 0x10c9bda50  session: 0x10c9c08d0  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,777 - logic_logger - INFO
......Customer[17] {Update - Adjusting customer: balance} id: 17, name: Ivan 1792465580767, balance:  [0E-10-->] 900.0000000000, credit_limit: 1000.0000000000, email: None, email_opt_out: None  row: 0x10ca182d0  session: 0x10c9c08d0  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,777 - logic_logger - INFO
Logic Phase:        COMMIT LOGIC        (session=0x10c9c08d0)                                            - 2026-10-19 20:06:20,778 - logic_logger - INFO
Logic Phase:        AFTER_FLUSH LOGIC   (session=0x10c9c08d0)                                            - 2026-10-19 20:06:20,778 - logic_logger - INFO
....Order[14] {AfterFlush Event} id: 14, notes: None, customer_id: 17, CreatedOn: None, date_shipped: None, amount_total:  [0E-10-->] 900.0000000000  row: 0x10c9bda50  session: 0x10c9c08d0  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,778 - logic_logger - INFO

   

Scenario: Order Exceeding Credit Limit Is Rejected ✅

  Scenario: Order Exceeding Credit Limit Is Rejected
   Given Customer "Judy" with balance 0 and credit limit 40
   And Order is created for "Judy"
   When Item is created with 5 Widget
   Then Item creation is rejected
   Then Customer balance is 0

Rules exercised and logic log (2 transactions)

   

Rules Used in Scenario: Order Exceeding Credit Limit Is Rejected

  Customer  
    1. Derive Customer.balance as Sum(Order.amount_total Where lambda row: row.date_shipped is None))  
    2. Constraint Function: None  
  Order  
    3. RowEvent Order._send_order_to_kafka()  
    4. Derive Order.amount_total as Sum(Item.amount Where  - None)  
  Item  
    5. Derive Item.amount as Formula (1): as_expression=lambda row: row.quantity * row.unit [...]  
    6. Derive Item.unit_price as Copy(product.unit_price)  

Logic Log in Scenario: Order Exceeding Credit Limit Is Rejected (2 transactions)

Logic Phase:        ROW LOGIC       (session=0x10c9c0d10) (sqlalchemy before_flush)          - 2026-10-19 20:06:20,786 - logic_logger - INFO
..Order[None] {Insert - client} id: None, notes: None, customer_id: 18, CreatedOn: None, date_shipped: None, amount_total: None  row: 0x10c9551d0  session: 0x10c9c0d10  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,786 - logic_logger - INFO
..Order[None] {server aggregate_defaults: amount_total } id: None, notes: None, customer_id: 18, CreatedOn: None, date_shipped: None, amount_total: 0  row: 0x10c9551d0  session: 0x10c9c0d10  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,786 - logic_logger - INFO
Logic Phase:        COMMIT LOGIC        (session=0x10c9c0d10)                                            - 2026-10-19 20:06:20,786 - logic_logger - INFO
Logic Phase:        AFTER_FLUSH LOGIC   (session=0x10c9c0d10)                                            - 2026-10-19 20:06:20,787 - logic_logger - INFO
..Order[15] {AfterFlush Event} id: 15, notes: None, customer_id: 18, CreatedOn: None, date_shipped: None, amount_total: 0  row: 0x10c9551d0  session: 0x10c9c0d10  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,787 - logic_logger - INFO


Logic Phase:        ROW LOGIC       (session=0x10c9c0270) (sqlalchemy before_flush)          - 2026-10-19 20:06:20,791 - logic_logger - INFO
..Item[None] {Insert - client} id: None, order_id: 15, product_id: 2, quantity: 5, amount: None, unit_price: None  row: 0x10c9bf050  session: 0x10c9c0270  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,791 - logic_logger - INFO
..Item[None] {copy_rules for role: product - unit_price} id: None, order_id: 15, product_id: 2, quantity: 5, amount: None, unit_price: 90.0000000000  row: 0x10c9bf050  session: 0x10c9c0270  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,792 - logic_logger - INFO
..Item[None] {Formula amount} id: None, order_id: 15, product_id: 2, quantity: 5, amount: 450.0000000000, unit_price: 90.0000000000  row: 0x10c9bf050  session: 0x10c9c0270  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,792 - logic_logger - INFO
....Order[15] {Update - Adjusting order: amount_total} id: 15, notes: None, customer_id: 18, CreatedOn: None, date_shipped: None, amount_total:  [0E-10-->] 450.0000000000  row: 0x10ca18c50  session: 0x10c9c0270  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,792 - logic_logger - INFO
......Customer[18] {Update - Adjusting customer: balance} id: 18, name: Judy 1792465580782, balance:  [0E-10-->] 450.0000000000, credit_limit: 40.0000000000, email: None, email_opt_out: None  row: 0x10ca18f50  session: 0x10c9c0270  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,792 - logic_logger - INFO
......Customer[18] {Constraint Failure: balance (450.0000000000) exceeds credit limit (40.0000000000)} id: 18, name: Judy 1792465580782, balance:  [0E-10-->] 450.0000000000, credit_limit: 40.0000000000, email: None, email_opt_out: None  row: 0x10ca18f50  session: 0x10c9c0270  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,792 - logic_logger - INFO

   

Feature: Kafka Publish Shipping Notification

   

Scenario: Shipping An Order Publishes To order_shipping ✅

  Scenario: Shipping An Order Publishes To order_shipping
   Given Customer "Echo" with balance 0 and credit limit 1000
   And Order is created for "Echo"
   And Item is created with 1 Widget
   When Order is shipped
   Then The order_shipping publish event fired
   Then A message for the order is on topic order_shipping

Rules exercised and logic log (3 transactions)

   

Rules Used in Scenario: Shipping An Order Publishes To order_shipping

  Customer  
    1. Derive Customer.balance as Sum(Order.amount_total Where lambda row: row.date_shipped is None))  
  Order  
    2. RowEvent Order._send_order_to_kafka()  
    3. Derive Order.amount_total as Sum(Item.amount Where  - None)  
  Item  
    4. Derive Item.amount as Formula (1): as_expression=lambda row: row.quantity * row.unit [...]  
    5. Derive Item.unit_price as Copy(product.unit_price)  

Logic Log in Scenario: Shipping An Order Publishes To order_shipping (3 transactions)

Logic Phase:        ROW LOGIC       (session=0x10c9c1d00) (sqlalchemy before_flush)          - 2026-10-19 20:06:20,804 - logic_logger - INFO
..Order[None] {Insert - client} id: None, notes: None, customer_id: 19, CreatedOn: None, date_shipped: None, amount_total: None  row: 0x10ca18a50  session: 0x10c9c1d00  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,804 - logic_logger - INFO
..Order[None] {server aggregate_defaults: amount_total } id: None, notes: None, customer_id: 19, CreatedOn: None, date_shipped: None, amount_total: 0  row: 0x10ca18a50  session: 0x10c9c1d00  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,804 - logic_logger - INFO
Logic Phase:        COMMIT LOGIC        (session=0x10c9c1d00)                                            - 2026-10-19 20:06:20,805 - logic_logger - INFO
Logic Phase:        AFTER_FLUSH LOGIC   (session=0x10c9c1d00)                                            - 2026-10-19 20:06:20,805 - logic_logger - INFO
..Order[16] {AfterFlush Event} id: 16, notes: None, customer_id: 19, CreatedOn: None, date_shipped: None, amount_total: 0  row: 0x10ca18a50  session: 0x10c9c1d00  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,805 - logic_logger - INFO


Logic Phase:        ROW LOGIC       (session=0x10c772580) (sqlalchemy before_flush)          - 2026-10-19 20:06:20,809 - logic_logger - INFO
..Item[None] {Insert - client} id: None, order_id: 16, product_id: 2, quantity: 1, amount: None, unit_price: None  row: 0x10ca187d0  session: 0x10c772580  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,809 - logic_logger - INFO
..Item[None] {copy_rules for role: product - unit_price} id: None, order_id: 16, product_id: 2, quantity: 1, amount: None, unit_price: 90.0000000000  row: 0x10ca187d0  session: 0x10c772580  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,810 - logic_logger - INFO
..Item[None] {Formula amount} id: None, order_id: 16, product_id: 2, quantity: 1, amount: 90.0000000000, unit_price: 90.0000000000  row: 0x10ca187d0  session: 0x10c772580  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:20,810 - logic_logger - INFO
....Order[16] {Update - Adjusting order: amount_total} id: 16, notes: None, customer_id: 19, CreatedOn: None, date_shipped: None, amount_total:  [0E-10-->] 90.0000000000  row: 0x10c9571d0  session: 0x10c772580  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,810 - logic_logger - INFO
......Customer[19] {Update - Adjusting customer: balance} id: 19, name: Echo 1792465580800, balance:  [0E-10-->] 90.0000000000, credit_limit: 1000.0000000000, email: None, email_opt_out: None  row: 0x10c9bf050  session: 0x10c772580  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,810 - logic_logger - INFO
Logic Phase:        COMMIT LOGIC        (session=0x10c772580)                                            - 2026-10-19 20:06:20,811 - logic_logger - INFO
Logic Phase:        AFTER_FLUSH LOGIC   (session=0x10c772580)                                            - 2026-10-19 20:06:20,811 - logic_logger - INFO
....Order[16] {AfterFlush Event} id: 16, notes: None, customer_id: 19, CreatedOn: None, date_shipped: None, amount_total:  [0E-10-->] 90.0000000000  row: 0x10c9571d0  session: 0x10c772580  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,811 - logic_logger - INFO


Logic Phase:        ROW LOGIC       (session=0x10c773680) (sqlalchemy before_flush)          - 2026-10-19 20:06:20,813 - logic_logger - INFO
..Order[16] {Update - client} id: 16, notes: None, customer_id: 19, CreatedOn: None, date_shipped:  [None-->] 2026-01-01 00:00:00, amount_total: 90.0000000000  row: 0x10c7f3550  session: 0x10c773680  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,813 - logic_logger - INFO
....Customer[19] {Update - Adjusting customer: balance} id: 19, name: Echo 1792465580800, balance:  [90.0000000000-->] 0E-10, credit_limit: 1000.0000000000, email: None, email_opt_out: None  row: 0x10c9bf1d0  session: 0x10c773680  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,814 - logic_logger - INFO
Logic Phase:        COMMIT LOGIC        (session=0x10c773680)                                            - 2026-10-19 20:06:20,814 - logic_logger - INFO
Logic Phase:        AFTER_FLUSH LOGIC   (session=0x10c773680)                                            - 2026-10-19 20:06:20,814 - logic_logger - INFO
..Order[16] {AfterFlush Event} id: 16, notes: None, customer_id: 19, CreatedOn: None, date_shipped:  [None-->] 2026-01-01 00:00:00, amount_total: 90.0000000000  row: 0x10c7f3550  session: 0x10c773680  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,814 - logic_logger - INFO
..Order[16] {publish_kafka_message: topic='order_shipping', key={'id': 16}} id: 16, notes: None, customer_id: 19, CreatedOn: None, date_shipped:  [None-->] 2026-01-01 00:00:00, amount_total: 90.0000000000  row: 0x10c7f3550  session: 0x10c773680  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:20,816 - logic_logger - INFO

   

Feature: Kafka Subscribe Order Integration

   

Scenario: Inbound Order Message Creates The Order And Items ✅

  Scenario: Inbound Order Message Creates The Order And Items
   Given Customer "Delta" with balance 0 and credit limit 1000
   When Inbound order message is consumed for "Delta" with 2 Widget and 1 Gadget
   Then Order is persisted from the message
   Then Order has 2 items
   Then Order amount_total is 330
   Then Customer balance is 330
   Then Message blob is marked processed

Rules exercised and logic log (1 transaction)

   

Rules Used in Scenario: Inbound Order Message Creates The Order And Items

  Customer  
    1. Derive Customer.balance as Sum(Order.amount_total Where lambda row: row.date_shipped is None))  
  Item  
    2. Derive Item.amount as Formula (1): as_expression=lambda row: row.quantity * row.unit [...]  
    3. Derive Item.unit_price as Copy(product.unit_price)  
  Order  
    4. RowEvent Order._send_order_to_kafka()  
    5. Derive Order.amount_total as Sum(Item.amount Where  - None)  
  OrderB2bMessage  
    6. RowEvent OrderB2bMessage._publish_order_b2b()  

Logic Log in Scenario: Inbound Order Message Creates The Order And Items (1 transaction)

Logic Phase:        ROW LOGIC       (session=0x10c9c19d0) (sqlalchemy before_flush)          - 2026-10-19 20:06:24,046 - logic_logger - INFO
..Order[None] {Insert - client} id: None, notes: behave kafka test, customer_id: 20, CreatedOn: None, date_shipped: None, amount_total: None  row: 0x10ca183d0  session: 0x10c9c19d0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:24,046 - logic_logger - INFO
..Order[None] {server aggregate_defaults: amount_total } id: None, notes: behave kafka test, customer_id: 20, CreatedOn: None, date_shipped: None, amount_total: 0  row: 0x10ca183d0  session: 0x10c9c19d0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:24,047 - logic_logger - INFO
..Item[None] {Insert - client} id: None, order_id: None, product_id: 2, quantity: 2, amount: None, unit_price: None  row: 0x10ca18c50  session: 0x10c9c19d0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:24,047 - logic_logger - INFO
..Item[None] {copy_rules for role: product - unit_price} id: None, order_id: None, product_id: 2, quantity: 2, amount: None, unit_price: 90.0000000000  row: 0x10ca18c50  session: 0x10c9c19d0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:24,048 - logic_logger - INFO
..Item[None] {Formula amount} id: None, order_id: None, product_id: 2, quantity: 2, amount: 180.0000000000, unit_price: 90.0000000000  row: 0x10ca18c50  session: 0x10c9c19d0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:24,048 - logic_logger - INFO
....Order[None] {Update - Adjusting order: amount_total} id: None, notes: behave kafka test, customer_id: 20, CreatedOn: None, date_shipped: None, amount_total:  [0-->] 180.0000000000  row: 0x10ca183d0  session: 0x10c9c19d0  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:24,048 - logic_logger - INFO
......Customer[20] {Update - Adjusting customer: balance} id: 20, name: Delta 1792465584034, balance:  [0E-10-->] 180.0000000000, credit_limit: 1000.0000000000, email: None, email_opt_out: None  row: 0x10c9bc9d0  session: 0x10c9c19d0  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:24,048 - logic_logger - INFO
..Item[None] {Insert - client} id: None, order_id: None, product_id: 1, quantity: 1, amount: None, unit_price: None  row: 0x10c957150  session: 0x10c9c19d0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:24,048 - logic_logger - INFO
..Item[None] {copy_rules for role: product - unit_price} id: None, order_id: None, product_id: 1, quantity: 1, amount: None, unit_price: 150.0000000000  row: 0x10c957150  session: 0x10c9c19d0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:24,049 - logic_logger - INFO
..Item[None] {Formula amount} id: None, order_id: None, product_id: 1, quantity: 1, amount: 150.0000000000, unit_price: 150.0000000000  row: 0x10c957150  session: 0x10c9c19d0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:24,049 - logic_logger - INFO
....Order[None] {Update - Adjusting order: amount_total} id: None, notes: behave kafka test, customer_id: 20, CreatedOn: None, date_shipped: None, amount_total:  [180.0000000000-->] 330.0000000000  row: 0x10ca183d0  session: 0x10c9c19d0  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:24,049 - logic_logger - INFO
......Customer[20] {Update - Adjusting customer: balance} id: 20, name: Delta 1792465584034, balance:  [180.0000000000-->] 330.0000000000, credit_limit: 1000.0000000000, email: None, email_opt_out: None  row: 0x10c9bc9d0  session: 0x10c9c19d0  ins_upd_dlt: upd, initial: upd - 2026-10-19 20:06:24,049 - logic_logger - INFO
..OrderB2bMessage[None] {Insert - client} id: None, received_at: None, payload: {"Account": "Delta 1792465584034", "Notes": "behave kafka test", "Items": [{"Name": "Widget", "QuantityOrdered": 2}, {"Name": "Gadget", "QuantityOrdered": 1}]}, is_processed: True, error_text: None  row: 0x10c75d2b0  session: 0x10c9c19d0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:24,049 - logic_logger - INFO
..OrderB2bMessage[None] {server_defaults: received_at } id: None, received_at: 2026-10-19, payload: {"Account": "Delta 1792465584034", "Notes": "behave kafka test", "Items": [{"Name": "Widget", "QuantityOrdered": 2}, {"Name": "Gadget", "QuantityOrdered": 1}]}, is_processed: True, error_text: None  row: 0x10c75d2b0  session: 0x10c9c19d0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:24,049 - logic_logger - INFO
Logic Phase:        COMMIT LOGIC        (session=0x10c9c19d0)                                            - 2026-10-19 20:06:24,050 - logic_logger - INFO
Logic Phase:        AFTER_FLUSH LOGIC   (session=0x10c9c19d0)                                            - 2026-10-19 20:06:24,051 - logic_logger - INFO
..Order[17] {AfterFlush Event} id: 17, notes: behave kafka test, customer_id: 20, CreatedOn: None, date_shipped: None, amount_total: 330.0000000000  row: 0x10ca183d0  session: 0x10c9c19d0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:24,051 - logic_logger - INFO
..OrderB2bMessage[1] {AfterFlush Event} id: 1, received_at: 2026-10-19, payload: {"Account": "Delta 1792465584034", "Notes": "behave kafka test", "Items": [{"Name": "Widget", "QuantityOrdered": 2}, {"Name": "Gadget", "QuantityOrdered": 1}]}, is_processed: True, error_text: None  row: 0x10c75d2b0  session: 0x10c9c19d0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:24,051 - logic_logger - INFO
..OrderB2bMessage[1] {_publish_order_b2b: skipping re-publish — blob.id=1 already is_processed=True (debug path)} id: 1, received_at: 2026-10-19, payload: {"Account": "Delta 1792465584034", "Notes": "behave kafka test", "Items": [{"Name": "Widget", "QuantityOrdered": 2}, {"Name": "Gadget", "QuantityOrdered": 1}]}, is_processed: True, error_text: None  row: 0x10c75d2b0  session: 0x10c9c19d0  ins_upd_dlt: ins, initial: ins - 2026-10-19 20:06:24,051 - logic_logger - INFO

  
/Users/val/dev/ApiLogicServer/ApiLogicServer-dev/build_and_test/genai-logic/samples/basic_demo_eai/test/api_logic_server_behave/behave_run.py completed at October 19, 2026 20:06:24