ApiLogicServer 15.2.3__py3-none-any.whl → 15.2.10__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- api_logic_server_cli/api_logic_server.py +3 -1
- api_logic_server_cli/prototypes/base/.github/.copilot-instructions.md +114 -52
- api_logic_server_cli/prototypes/base/docs/training/testing.md +95 -9
- api_logic_server_cli/prototypes/base/test/api_logic_server_behave/behave_logic_report.py +19 -6
- api_logic_server_cli/prototypes/basic_demo/.github/.copilot-instructions.md +744 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/logic/declare_logic.py +17 -1
- api_logic_server_cli/prototypes/basic_demo/readme.md +13 -5
- api_logic_server_cli/prototypes/basic_demo/tutor.md +1436 -0
- api_logic_server_cli/prototypes/manager/.github/.copilot-instructions.md +50 -23
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/.github/.copilot-instructions.md +3 -0
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/customizations/logic/declare_logic.py +17 -1
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/docs/training/testing.md +95 -9
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/iteration/logic/declare_logic.py +17 -1
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/logic/declare_logic.py +38 -1
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/features/order_processing.feature +59 -50
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/features/steps/order_processing_steps.py +395 -248
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/behave.log +66 -62
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Carbon_Neutral_Discount_A.log +51 -41
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Change_Order_Customer.log +29 -0
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Change_Product_in_Item.log +35 -0
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Delete_Item_Reduces_Order.log +39 -19
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Exceed_Credit_Limit_Rejec.log +36 -45
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Good_Order_Placed_via_B2B.log +50 -40
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Item_Quantity_Change.log +33 -0
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Multi-Item_Order_via_B2B_.log +67 -0
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Ship_Order_Excludes_from_.log +24 -14
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Transaction_Processing.log +26 -17
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Unship_Order_Includes_in_.log +24 -14
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/reports/Behave Logic Report.md +361 -146
- api_logic_server_cli/prototypes/manager/system/ApiLogicServer-Internal-Dev/copilot-dev-context.md +270 -2
- {apilogicserver-15.2.3.dist-info → apilogicserver-15.2.10.dist-info}/METADATA +25 -16
- {apilogicserver-15.2.3.dist-info → apilogicserver-15.2.10.dist-info}/RECORD +36 -30
- {apilogicserver-15.2.3.dist-info → apilogicserver-15.2.10.dist-info}/WHEEL +0 -0
- {apilogicserver-15.2.3.dist-info → apilogicserver-15.2.10.dist-info}/entry_points.txt +0 -0
- {apilogicserver-15.2.3.dist-info → apilogicserver-15.2.10.dist-info}/licenses/LICENSE +0 -0
- {apilogicserver-15.2.3.dist-info → apilogicserver-15.2.10.dist-info}/top_level.txt +0 -0
|
@@ -12,9 +12,11 @@ ApiLogicServer CLI: given a database url, create [and run] customizable ApiLogic
|
|
|
12
12
|
Called from api_logic_server_cli.py, by instantiating the ProjectRun object.
|
|
13
13
|
'''
|
|
14
14
|
|
|
15
|
-
__version__ = "15.02.
|
|
15
|
+
__version__ = "15.02.10" # last public release: 15.02.07
|
|
16
16
|
recent_changes = \
|
|
17
17
|
f'\n\nRecent Changes:\n' +\
|
|
18
|
+
"\t10/28/2025 - 15.02.10: Tutor 3.3 (working, vibe transtion) \n"\
|
|
19
|
+
"\t10/26/2025 - 15.02.07: Clarify order created for ship test, security fixes [105], tutor 2.1 \n"\
|
|
18
20
|
"\t10/22/2025 - 15.02.03: Copilot test creation from rules and custom APIs with issues [103, 104] \n"\
|
|
19
21
|
"\t10/06/2025 - 15.01.06: Incorrect dbml reln arrows [102] \n"\
|
|
20
22
|
"\t09/27/2025 - 15.01.05: Error reporting for bad test data rebuild [101], Minor fix to ensure react-app cards have links \n"\
|
|
@@ -1,11 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Copilot Instructions for GenAI-Logic Projects
|
|
3
|
+
Description: Project-level instructions for working with generated projects
|
|
4
|
+
Source: ApiLogicServer-src/prototypes/base/.github/.copilot-instructions.md
|
|
5
|
+
Propagation: CLI create command → created projects (non-basic_demo)
|
|
6
|
+
Usage: AI assistants read this when user opens any created project
|
|
7
|
+
version: 2.1
|
|
8
|
+
changelog:
|
|
9
|
+
- 2.1 (Oct 2025) - Streamlined OBX for non-tutorial projects, friendly collaborative tone
|
|
10
|
+
- 2.0 (Oct 2025) - Added front matter, updated for OBX improvements
|
|
11
|
+
- 1.0 (Initial) - Comprehensive technical reference
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# GitHub Copilot Instructions for GenAI-Logic (aka API Logic Server) Projects
|
|
1
15
|
|
|
16
|
+
⚠️ **IMPORTANT FOR AI ASSISTANTS**: When user first opens this project or asks you to read instructions, present the Welcome section below directly to the user. Do not explain that you're following instructions - just present the welcome message naturally. The technical reference sections after the welcome are for later consultation only.
|
|
2
17
|
|
|
18
|
+
---
|
|
3
19
|
|
|
4
|
-
|
|
20
|
+
## Welcome
|
|
21
|
+
|
|
22
|
+
**Welcome! I'm here to help with your GenAI-Logic project.**
|
|
23
|
+
|
|
24
|
+
This is a complete, working microservice auto-generated from your database schema.
|
|
25
|
+
|
|
26
|
+
**What's already built:**
|
|
27
|
+
- **Admin Web Application** - Live at `http://localhost:5656`
|
|
28
|
+
- **REST API Endpoints** - All database tables exposed at `/api/*`
|
|
29
|
+
- **Database Models** - Complete SQLAlchemy ORM in `database/models.py`
|
|
30
|
+
- **Authentication System** - JWT-based auth framework
|
|
31
|
+
- **Business Logic Engine** - Declarative rules system
|
|
32
|
+
|
|
33
|
+
---
|
|
5
34
|
|
|
6
|
-
|
|
35
|
+
**Here are some things I can help you with:**
|
|
7
36
|
|
|
8
|
-
|
|
37
|
+
1. **Add business logic** - Describe your requirements in natural language, I'll generate declarative rules
|
|
38
|
+
2. **Customize the API** - Add custom endpoints for your specific needs
|
|
39
|
+
3. **Create custom UIs** - Build React apps with `genai-logic genai-add-app --vibe`
|
|
40
|
+
4. **Add security** - Set up role-based access control with `genai-logic add-auth`
|
|
41
|
+
5. **Test your logic** - Create Behave tests with requirements traceability
|
|
42
|
+
6. **Configure Admin UI** - Customize the auto-generated admin interface
|
|
43
|
+
7. **Add MCP integration** - Enable Model Context Protocol for external AI access
|
|
44
|
+
8. **Create B2B APIs** - Complex integration endpoints with partner systems
|
|
45
|
+
9. **Add events** - Integrate with Kafka, webhooks, or other event systems
|
|
46
|
+
10. **Customize models** - Add tables, attributes, or derived fields
|
|
47
|
+
11. **Discovery systems** - Auto-load logic and APIs from discovery folders
|
|
48
|
+
|
|
49
|
+
Want to get started? Press **F5** to start the server with debugger support, then open `http://localhost:5656`. (There are also run configurations for running tests and other tasks.) Or just ask me what you'd like to work on.
|
|
50
|
+
|
|
51
|
+
---
|
|
9
52
|
|
|
10
53
|
## 🔑 Key Technical Points
|
|
11
54
|
|
|
@@ -26,54 +69,15 @@ This is a **GenAI-Logic (aka API Logic Server) project** - a complete, working m
|
|
|
26
69
|
|
|
27
70
|
3. **Automatic Business Logic**: All APIs (standard and custom) automatically inherit LogicBank rules without additional code.
|
|
28
71
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
**DO NOT recreate these - they're already working:**
|
|
32
|
-
|
|
33
|
-
1. **Admin Web Application** - Live at `http://localhost:5656`
|
|
34
|
-
2. **REST API Endpoints** - All database tables exposed at `/api/*`
|
|
35
|
-
3. **Database Models** - Complete SQLAlchemy ORM in `database/models.py`
|
|
36
|
-
4. **Authentication System** - JWT-based auth framework
|
|
37
|
-
5. **Business Logic Engine** - Declarative rules system
|
|
38
|
-
|
|
39
|
-
> **📋 Testing:** For comprehensive testing conventions, patterns, and examples, see `docs/training/testing.md` (555 lines - MUST READ FIRST before creating any tests)
|
|
40
|
-
|
|
41
|
-
## 🎯 Common Tasks
|
|
42
|
-
|
|
43
|
-
If the user asks "what do I do now?", these subsections are good suggestions.
|
|
44
|
-
|
|
45
|
-
List these as choices, do not just do all of them at once - that would be overwhelming.
|
|
46
|
-
|
|
47
|
-
### 📚 Main Services Available in This Project
|
|
48
|
-
|
|
49
|
-
This GenAI-Logic project provides 13 main customization services:
|
|
72
|
+
4. **CLI Commands**: Use `genai-logic --help` to see all available commands. When CLI commands exist for a task (e.g., `add-auth`, `genai-add-mcp-client`, `genai-add-app`), ALWAYS use them instead of manual configuration - they handle all setup correctly.
|
|
50
73
|
|
|
51
|
-
|
|
52
|
-
2. **Adding Business Logic** - Declarative rules in `logic/declare_logic.py`
|
|
53
|
-
3. **Discovery Systems** - Auto-load logic and APIs from discovery folders
|
|
54
|
-
4. **Automated Testing** - Behave tests with BLT (Business Logic Traceability) reports
|
|
55
|
-
5. **Adding MCP** - Model Context Protocol client integration
|
|
56
|
-
6. **Configuring Admin UI** - Edit `ui/admin/admin.yaml`
|
|
57
|
-
7. **Create React Apps** - Custom UIs with `genai-logic genai-add-app`
|
|
58
|
-
8. **Security - RBAC** - Role-based access control with `als add-auth`
|
|
59
|
-
9. **Custom API Endpoints** - Add routes in `api/customize_api.py`
|
|
60
|
-
10. **B2B Integration APIs** - Complex endpoints with Row Dict Mappers
|
|
61
|
-
11. **Customize Models** - Add tables, attributes, derived fields
|
|
62
|
-
12. **Adding Events** - Row events for Kafka, webhooks, integrations
|
|
63
|
-
13. **Critical Patterns** - React components, null-safe constraints, test repeatability
|
|
64
|
-
|
|
65
|
-
Each service is detailed below with examples and best practices.
|
|
74
|
+
> **📋 Testing:** For comprehensive testing conventions, patterns, and examples, see `docs/training/testing.md` (555 lines - I'll read this before we create any tests)
|
|
66
75
|
|
|
67
76
|
---
|
|
68
77
|
|
|
69
|
-
|
|
70
|
-
If it is not already set, you can often find a `venv` in the GenAI-Logic Manager - a parent or grandparent directory.
|
|
71
|
-
|
|
72
|
-
### 🚀 To Run This Project
|
|
73
|
-
|
|
74
|
-
Use F5 (pre-configured run configuration - supports debugger for server logic), or (when focused on client apps):
|
|
78
|
+
## Detailed Service Documentation
|
|
75
79
|
|
|
76
|
-
|
|
80
|
+
The sections below provide complete details on each service. I'll reference these as needed when we work together.
|
|
77
81
|
python api_logic_server_run.py
|
|
78
82
|
# Then open: http://localhost:5656
|
|
79
83
|
```
|
|
@@ -417,20 +421,20 @@ Customize using CoPilot chat, with `docs/training`.
|
|
|
417
421
|
|
|
418
422
|
Configure:
|
|
419
423
|
```
|
|
420
|
-
|
|
421
|
-
|
|
424
|
+
genai-logic add-auth --provider-type=sql --db-url=
|
|
425
|
+
genai-logic add-auth --provider-type=sql --db_url=postgresql://postgres:p@localhost/authdb
|
|
422
426
|
|
|
423
|
-
|
|
424
|
-
|
|
427
|
+
genai-logic add-auth --provider-type=keycloak --db-url=localhost
|
|
428
|
+
genai-logic add-auth --provider-type=keycloak --db-url=hardened
|
|
425
429
|
|
|
426
|
-
|
|
430
|
+
genai-logic add-auth --provider-type=None # to disable
|
|
427
431
|
```
|
|
428
432
|
|
|
429
433
|
Keycloak quick start [(more information here:)](https://apilogicserver.github.io/Docs/Security-Keycloak/)
|
|
430
434
|
```bash
|
|
431
435
|
cd devops/keycloak
|
|
432
436
|
docker compose up
|
|
433
|
-
|
|
437
|
+
genai-logic add-auth --provider-type=keycloak --db-url=localhost
|
|
434
438
|
```
|
|
435
439
|
|
|
436
440
|
For more on KeyCloak: https://apilogicserver.github.io/Docs/Security-Keycloak/
|
|
@@ -441,6 +445,64 @@ Declaration:
|
|
|
441
445
|
Grant(on_entity=Customer, to_role=sales, filter=lambda: Customer.SalesRep == current_user())
|
|
442
446
|
```
|
|
443
447
|
|
|
448
|
+
|
|
449
|
+
#### Testing with Security Enabled
|
|
450
|
+
|
|
451
|
+
**CRITICAL:** When `SECURITY_ENABLED=True`, test code must obtain and include JWT authentication tokens.
|
|
452
|
+
|
|
453
|
+
**Pattern for test steps:**
|
|
454
|
+
```python
|
|
455
|
+
from pathlib import Path
|
|
456
|
+
import os
|
|
457
|
+
from dotenv import load_dotenv
|
|
458
|
+
|
|
459
|
+
# Load config to check SECURITY_ENABLED
|
|
460
|
+
config_path = Path(__file__).parent.parent.parent.parent.parent / 'config' / 'default.env'
|
|
461
|
+
load_dotenv(config_path)
|
|
462
|
+
|
|
463
|
+
# Cache for auth token (obtained once per test session)
|
|
464
|
+
_auth_token = None
|
|
465
|
+
|
|
466
|
+
def get_auth_token():
|
|
467
|
+
"""Login and get JWT token if security is enabled"""
|
|
468
|
+
global _auth_token
|
|
469
|
+
|
|
470
|
+
if _auth_token is not None:
|
|
471
|
+
return _auth_token
|
|
472
|
+
|
|
473
|
+
# Login with default admin credentials
|
|
474
|
+
login_url = f'{BASE_URL}/api/auth/login'
|
|
475
|
+
login_data = {'username': 'admin', 'password': 'p'}
|
|
476
|
+
|
|
477
|
+
response = requests.post(login_url, json=login_data)
|
|
478
|
+
if response.status_code == 200:
|
|
479
|
+
_auth_token = response.json().get('access_token')
|
|
480
|
+
return _auth_token
|
|
481
|
+
else:
|
|
482
|
+
raise Exception(f"Login failed: {response.status_code}")
|
|
483
|
+
|
|
484
|
+
def get_headers():
|
|
485
|
+
"""Get headers including auth token if security is enabled"""
|
|
486
|
+
security_enabled = os.getenv('SECURITY_ENABLED', 'false').lower() not in ['false', 'no']
|
|
487
|
+
|
|
488
|
+
headers = {'Content-Type': 'application/json'}
|
|
489
|
+
|
|
490
|
+
if security_enabled:
|
|
491
|
+
token = get_auth_token()
|
|
492
|
+
if token:
|
|
493
|
+
headers['Authorization'] = f'Bearer {token}'
|
|
494
|
+
|
|
495
|
+
return headers
|
|
496
|
+
|
|
497
|
+
# Use in all API requests
|
|
498
|
+
response = requests.post(url=api_url, json=data, headers=get_headers())
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
**Key points:**
|
|
502
|
+
- Tests DO NOT automatically include auth headers - you must code this pattern
|
|
503
|
+
- Token is cached to avoid repeated logins during test session
|
|
504
|
+
- Pattern works for both `SECURITY_ENABLED=True` and `SECURITY_ENABLED=False`
|
|
505
|
+
- See `test/api_logic_server_behave/features/steps/order_processing_steps.py` for complete example
|
|
444
506
|
### Adding Custom API Endpoints
|
|
445
507
|
|
|
446
508
|
For simple endpoints:
|
|
@@ -32,6 +32,9 @@ Step 5. SUGGEST how to run tests (DO NOT run automatically)
|
|
|
32
32
|
- [ ] @when patterns: carbon neutral > multi-item > single-item
|
|
33
33
|
- [ ] @given patterns: multi-item > single-item
|
|
34
34
|
- [ ] Use `grep -n "@when('.*with" steps/*.py` to verify order
|
|
35
|
+
- [ ] **Clear scenario language?** (Rule #13: Action-oriented wording)
|
|
36
|
+
- [ ] Use "Order is created" not "Order exists" (shows when rules fire)
|
|
37
|
+
- [ ] Makes test flow obvious: setup → action → verify
|
|
35
38
|
- [ ] Test data uses timestamps? (Rule #0: Repeatability)
|
|
36
39
|
- [ ] Security config read? (SECURITY_ENABLED value)
|
|
37
40
|
|
|
@@ -167,7 +170,7 @@ def step_impl(context, qty):
|
|
|
167
170
|
r = requests.patch(url=patch_uri, json=patch_data)
|
|
168
171
|
```
|
|
169
172
|
|
|
170
|
-
## The
|
|
173
|
+
## The Critical Rules (Read FIRST!)
|
|
171
174
|
|
|
172
175
|
### Rule #0: TEST REPEATABILITY (MOST CRITICAL!) ⚠️
|
|
173
176
|
|
|
@@ -386,18 +389,65 @@ Scenario: Exceed Credit (Constraint FAIL - negative test)
|
|
|
386
389
|
|
|
387
390
|
**CRITICAL:** Check `logic/declare_logic.py` for custom Python logic affecting calculations (e.g., discounts, adjustments) before writing constraint test expectations!
|
|
388
391
|
|
|
389
|
-
### Rule #5: Security Configuration
|
|
392
|
+
### Rule #5: Security Configuration - JWT Authentication
|
|
393
|
+
|
|
394
|
+
**CRITICAL:** When `SECURITY_ENABLED=True`, tests MUST obtain JWT token and include Authorization header.
|
|
395
|
+
|
|
390
396
|
```python
|
|
391
|
-
|
|
392
|
-
|
|
397
|
+
from pathlib import Path
|
|
398
|
+
import os
|
|
399
|
+
from dotenv import load_dotenv
|
|
393
400
|
|
|
394
|
-
#
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
401
|
+
# Load config to check SECURITY_ENABLED
|
|
402
|
+
config_path = Path(__file__).parent.parent.parent.parent.parent / 'config' / 'default.env'
|
|
403
|
+
load_dotenv(config_path)
|
|
404
|
+
|
|
405
|
+
# Cache for auth token (obtained once per test session)
|
|
406
|
+
_auth_token = None
|
|
407
|
+
|
|
408
|
+
def get_auth_token():
|
|
409
|
+
"""Login and get JWT token if security is enabled"""
|
|
410
|
+
global _auth_token
|
|
411
|
+
|
|
412
|
+
if _auth_token is not None:
|
|
413
|
+
return _auth_token
|
|
414
|
+
|
|
415
|
+
# Login with default admin credentials
|
|
416
|
+
login_url = f'{BASE_URL}/api/auth/login'
|
|
417
|
+
login_data = {'username': 'admin', 'password': 'p'}
|
|
418
|
+
|
|
419
|
+
response = requests.post(login_url, json=login_data)
|
|
420
|
+
if response.status_code == 200:
|
|
421
|
+
_auth_token = response.json().get('access_token')
|
|
422
|
+
return _auth_token
|
|
423
|
+
else:
|
|
424
|
+
raise Exception(f"Login failed: {response.status_code}")
|
|
425
|
+
|
|
426
|
+
def get_headers():
|
|
427
|
+
"""Get headers including auth token if security is enabled"""
|
|
428
|
+
security_enabled = os.getenv('SECURITY_ENABLED', 'false').lower() not in ['false', 'no']
|
|
429
|
+
|
|
430
|
+
headers = {'Content-Type': 'application/json'}
|
|
431
|
+
|
|
432
|
+
if security_enabled:
|
|
433
|
+
token = get_auth_token()
|
|
434
|
+
if token:
|
|
435
|
+
headers['Authorization'] = f'Bearer {token}'
|
|
436
|
+
|
|
437
|
+
return headers
|
|
438
|
+
|
|
439
|
+
# Use in ALL API requests
|
|
440
|
+
response = requests.post(url=api_url, json=data, headers=get_headers())
|
|
441
|
+
response = requests.get(url=api_url, headers=get_headers())
|
|
442
|
+
response = requests.patch(url=api_url, json=data, headers=get_headers())
|
|
399
443
|
```
|
|
400
444
|
|
|
445
|
+
**Key Points:**
|
|
446
|
+
- Tests DO NOT automatically include auth - you must code the pattern above
|
|
447
|
+
- Token is cached globally to avoid repeated login calls
|
|
448
|
+
- Works for both `SECURITY_ENABLED=True` and `SECURITY_ENABLED=False`
|
|
449
|
+
- See complete example: `test/api_logic_server_behave/features/steps/order_processing_steps.py`
|
|
450
|
+
|
|
401
451
|
### Rule #6: Logic Logging
|
|
402
452
|
```python
|
|
403
453
|
@when('Good Order Placed')
|
|
@@ -535,6 +585,40 @@ def step_impl(context):
|
|
|
535
585
|
return # Skip gracefully
|
|
536
586
|
```
|
|
537
587
|
|
|
588
|
+
### Rule #13: Use Clear, Action-Oriented Scenario Language ⚠️ NEW
|
|
589
|
+
```gherkin
|
|
590
|
+
# ❌ AMBIGUOUS - "exists" is passive, doesn't show when balance changes
|
|
591
|
+
Scenario: Ship Order Excludes from Balance
|
|
592
|
+
Given Customer "Charlie" with balance 0 and credit limit 2000
|
|
593
|
+
And Order exists for "Charlie" with 2 Widget
|
|
594
|
+
When Order is shipped
|
|
595
|
+
Then Customer balance should be 0
|
|
596
|
+
|
|
597
|
+
# Question: How can Charlie have balance 0 AND an order for widgets?
|
|
598
|
+
# Answer: The order EXISTS at test start, but balance calculation is unclear
|
|
599
|
+
|
|
600
|
+
# ✅ CLEAR - "is created" shows action that triggers rule
|
|
601
|
+
Scenario: Ship Order Excludes from Balance
|
|
602
|
+
Given Customer "Charlie" with balance 0 and credit limit 2000
|
|
603
|
+
And Order is created for "Charlie" with 2 Widget # Action! Balance becomes 180
|
|
604
|
+
When Order is shipped # Action! Balance drops to 0
|
|
605
|
+
Then Customer balance should be 0 # Verification
|
|
606
|
+
|
|
607
|
+
# Now it's obvious:
|
|
608
|
+
# 1. Customer starts with balance 0
|
|
609
|
+
# 2. Creating unshipped order → rule fires → balance becomes 180
|
|
610
|
+
# 3. Shipping order → WHERE clause excludes it → balance drops to 0
|
|
611
|
+
|
|
612
|
+
# More examples:
|
|
613
|
+
# ❌ "And Shipped order exists for..."
|
|
614
|
+
# ✅ "And Shipped order is created for..."
|
|
615
|
+
|
|
616
|
+
# Why this matters:
|
|
617
|
+
# - Shows WHEN rules fire (on creation, not just existence)
|
|
618
|
+
# - Makes test flow obvious (setup → action → verify)
|
|
619
|
+
# - Clarifies that declarative rules execute automatically on changes
|
|
620
|
+
```
|
|
621
|
+
|
|
538
622
|
## Complete Phase 2 Example
|
|
539
623
|
|
|
540
624
|
### .feature File
|
|
@@ -631,6 +715,8 @@ def step_impl(context, expected):
|
|
|
631
715
|
| **"balance: expected 570, got 0.0"** | **Step ordering issue (Rule #0.5)! Multi-item pattern after single-item** |
|
|
632
716
|
| **"context has no attribute 'item_id'"** | **Step ordering issue! Specific pattern defined after general pattern** |
|
|
633
717
|
| "Order created but no items" | Check if wrong step matched (print debug in step) |
|
|
718
|
+
| **"expected 810, got 900"** (carbon neutral) | **Rule #10: Verify actual database values! Check product flags with SQL first** |
|
|
719
|
+
| **"How can balance be 0 with an order?"** | **Rule #13: Use "is created" not "exists" - shows when rules fire** |
|
|
634
720
|
|
|
635
721
|
### Debugging Step Ordering Issues
|
|
636
722
|
|
|
@@ -129,19 +129,32 @@ def show_logic(scenario: str, logic_logs_dir: str):
|
|
|
129
129
|
best_section = max(rules_sections, key=lambda x: x['rule_count'])
|
|
130
130
|
last_rules_start = best_section['start']
|
|
131
131
|
last_rules_end = best_section['end']
|
|
132
|
+
# Find where the "These Rules Fired" line is (one line before rules start)
|
|
133
|
+
rules_fired_line = last_rules_start - 1
|
|
134
|
+
# Now search backwards to find the beginning of this logic section
|
|
135
|
+
logic_start_line = rules_fired_line - 1
|
|
136
|
+
while logic_start_line > 0:
|
|
137
|
+
line = logic_lines[logic_start_line].strip()
|
|
138
|
+
# Look for the start marker (usually after a blank line following "COMPLETE")
|
|
139
|
+
if 'Logic Phase:' in logic_lines[logic_start_line] and 'ROW LOGIC' in logic_lines[logic_start_line]:
|
|
140
|
+
# Found the start of the logic section
|
|
141
|
+
# Go back one more to include the header line (scenario name)
|
|
142
|
+
if logic_start_line > 0 and logic_lines[logic_start_line-1].strip():
|
|
143
|
+
logic_start_line -= 1
|
|
144
|
+
break
|
|
145
|
+
logic_start_line -= 1
|
|
132
146
|
else:
|
|
133
147
|
last_rules_start = -1
|
|
134
148
|
last_rules_end = -1
|
|
149
|
+
logic_start_line = 0
|
|
135
150
|
|
|
136
|
-
# Now process the file, collecting logic log and extracting the
|
|
151
|
+
# Now process the file, collecting logic log and extracting the rules section
|
|
137
152
|
for i, each_logic_line in enumerate(logic_lines):
|
|
138
153
|
each_logic_line = remove_trailer(each_logic_line)
|
|
139
154
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
else:
|
|
144
|
-
logic_log.append(each_logic_line)
|
|
155
|
+
# Collect logic log from the best section
|
|
156
|
+
if rules_sections and logic_start_line <= i < rules_fired_line:
|
|
157
|
+
logic_log.append(each_logic_line)
|
|
145
158
|
|
|
146
159
|
# Extract rules from the last "These Rules Fired" section
|
|
147
160
|
if last_rules_start <= i < last_rules_end:
|