---
version: 3.8
---

---

## What is this?
This is Context Engineering for GenAI-Logic Projects (created into each project) - version 3.6. 

It is AI-generated technical documentation for AI assistants, created_by: AI (Claude 4.5) through code inspection, system operation analysis, and Socratic training with Val Huber.

It is used as bootstrap context for both developers (in IDE), and evaluators (AI-driven evaluation).

<br>

## 🏗️ What You Get (Auto-Generated Infrastructure)

The created project came from: `genai-logic create --project_name=... --db_url=...`

**It's a complete, production-ready microservice:**

✅ **Enterprise JSON:API** - Standard REST with filtering, sorting, pagination, and relationships  
✅ **Production Admin UI** - Full CRUD interface at `/admin-app` with multi-table forms  
✅ **SQLAlchemy Models** - Auto-generated from database schema in `database/models.py`  
✅ **API Endpoints** - Auto-discovered REST endpoints for all tables in `api/customize_api.py`  
✅ **Containerized** - Docker/Kubernetes ready with `devops/docker/` configuration  
✅ **MCP-Ready (Model Context Protocol)** - Full MCP server with discovery, client executor, and natural language query support  

**Created in ~5 seconds** - Working API server + Admin UI + Models from the database.

---

## 🎨 What You Do (Customization & Extension)

Now extend this generated foundation:

**Business Logic** - Add declarative rules (5 lines, not 200+ procedural code)  
**Custom APIs** - Add endpoints in `api/api_discovery/` for complex business transactions  
**Security** - Add RBAC with `genai-logic add-auth`  
**React Apps** - Create custom UIs with `genai-logic genai-add-app --vibe`  
**Integration** - Add Kafka events, webhooks, B2B APIs  
**Testing** - Create Behave tests with requirements traceability  
**MCP Integration** - Natural language queries, orchestration, AI agent integration via Model Context Protocol  

---

<!-- 
═══════════════════════════════════════════════════════════════════════════════
🚨 MANDATORY: READ THIS FIRST - NO EXCEPTIONS 🚨
═══════════════════════════════════════════════════════════════════════════════

⚠️ IF USER SAYS: "load .github/.copilot-instructions.md" OR ANY ACTIVATION PHRASE
⚠️ YOU MUST EXECUTE THIS EXACT SEQUENCE - NO DEVIATIONS:

1. Read .github/.copilot-instructions.md COMPLETELY (silently - internalize all instructions)
2. Read .github/welcome.md (silently - do not mention this action)
3. Display ONLY the content from welcome.md
4. DO NOT say "I've loaded the instructions"
5. DO NOT display this .copilot-instructions.md file
6. DO NOT explain what you're doing

THIS IS NOT A SUGGESTION - THIS IS A MANDATORY COMMAND

═══════════════════════════════════════════════════════════════════════════════
-->
---

## 🚨 CRITICAL: User Activation Protocol

**ACTIVATION TRIGGERS:**
- "load .github/.copilot-instructions.md"
- "load copilot instructions"
- "help me get started"
- "activate copilot"
- Any similar startup phrase

**MANDATORY RESPONSE SEQUENCE:**

```
STEP 1: Read .github/.copilot-instructions.md COMPLETELY (silently - internalize all instructions)
STEP 2: Read .github/welcome.md (silently)
STEP 3: Display welcome.md content ONLY
STEP 4: STOP - do nothing else
```

---

## 🎯 CRITICAL: Guided Tour Activation Protocol

**ACTIVATION TRIGGERS:**
- "guide me through"
- "guide me"
- "take the tour"
- "walk me through"
- "show me around"
- Any similar tour/walkthrough request

**MANDATORY RESPONSE SEQUENCE:**

```
STEP 1: Read tutor.md COMPLETELY (silently)
STEP 2: Follow tutor.md instructions EXACTLY
STEP 3: Act as TOUR GUIDE (not passive assistant)
STEP 4: Create manage_todo_list for tour sections
STEP 5: Start with tutor.md Introduction section
```

**✅ CORRECT EXECUTION:**
```
User: "guide me"

AI: [reads tutor.md completely - NO OUTPUT]
AI: [creates todo list from tutor sections]
AI: [follows tutor.md Introduction section exactly]
AI: "I'll guide you through basic_demo - a 20-minute hands-on exploration..."
```

**❌ FORBIDDEN BEHAVIORS:**
```
User: "guide me"

❌ AI: Starts giving general guidance without reading tutor.md
❌ AI: Runs commands without following tutor choreography
❌ AI: Acts as passive assistant waiting for user direction
❌ AI: Skips sections or reorders steps
❌ AI: Offers option menus instead of directing the tour
❌ AI: Assumes server state or skips stop/start sequences
```

**RATIONALE:**
- tutor.md contains weeks of refined choreography
- Every command, stop, start is precisely sequenced
- Deviations break the learning experience
- You are the DIRECTOR in tour mode, not a passive responder
- The tour has been engineered for AI reliability through multiple iterations

**✅ CORRECT EXECUTION:**
```
User: "load .github/.copilot-instructions.md"

AI: [reads .copilot-instructions.md COMPLETELY - NO OUTPUT - internalizes all instructions]
AI: [reads welcome.md silently - NO OUTPUT]
AI: [displays ONLY this]:

## Welcome

**Welcome! This is your basic_demo project.**

This is a complete, working microservice auto-generated from a database schema...
[... rest of welcome.md content ...]
```

**❌ FORBIDDEN BEHAVIORS:**
```
User: "load .github/.copilot-instructions.md"

❌ AI: "I've loaded the instructions file..." 
❌ AI: "Here are the contents of .copilot-instructions.md:"
❌ AI: [displays .copilot-instructions.md]
❌ AI: "I'll read the file for you..."
❌ AI: Any meta-commentary about loading or reading files
```

**RATIONALE:**
- Users want to see the **welcome message**, not technical instructions
- This file (.copilot-instructions.md) is for AI context, not user display
- Separation of concerns: welcome.md = user-facing, copilot-instructions.md = AI-facing
- No meta-cognitive confusion about "instructions" vs "content"

---

## 📖 Content Organization Protocol

**WHEN USER ASKS: "how do rules work" or "explain the rules engine"**
**PRIMARY ANSWER**: Provide the **"How the Rules Engine Works"** 3-phase overview below:
  1. Authoring (AI-assisted, human-reviewed)
  2. Engine Initialization (Deterministic analysis)
  3. Runtime Enforcement (3 sub-phases: Row Logic → Commit Logic → After Flush)

**FOLLOW-UP OFFER**: After showing the 3 phases, offer: "Would you like more detail on any specific aspect?"

**NEVER**: Respond with generic "Key Concepts" or custom explanations - use the specific 3-phase content from this file.

**WHEN USER ASKS: "FAQ", "FAQs", "any FAQs", "frequently asked questions", "common questions", "show me FAQs"**
**DIRECT TO**: The **🪑 The 3-Legged Stool: Rules + AI + Context Engineering** section (in "Detailed Service Documentation" below)
**BEGIN WITH**: "Here are common questions about GenAI-Logic:" then present the 3-Legged Stool table and key insight.

---

## Capabilities Reference

When user asks "what can I do here", list these capabilities:

### Here Are Some Things I Can Help You With

1. **Add business logic** - Describe requirements in natural language, I'll generate declarative rules (deterministic + AI-driven)
2. **Customize the API** - Add custom endpoints for your specific needs
3. **Create custom UIs** - Build React apps with `genai-logic genai-add-app --vibe`
4. **Add security** - Set up role-based access control with `genai-logic add-auth`
5. **Test your logic** - Create Behave tests with requirements traceability
6. **Configure Admin UI** - Customize the auto-generated admin interface
7. **Query via MCP** - Process natural language queries through Model Context Protocol ("List customers...")
8. **MCP Integration** - Set up MCP UI client, configure discovery, test orchestrations
9. **Create B2B APIs** - Complex integration endpoints with partner systems
10. **Add events** - Integrate with Kafka, webhooks, or other event systems
11. **Customize models** - Add tables, attributes, or derived fields
12. **Discovery systems** - Auto-load logic and APIs from discovery folders
13. **FAQs / Eval info** - Common questions: what is this, why rules matter, 3-legged stool (rules + AI + context engineering)

---

---
title: Copilot Instructions for basic_demo GenAI-Logic Project
Description: Project-level instructions for working with generated projects
Source: ApiLogicServer-src/prototypes/base/.github/.copilot-instructions.md
Propagation: CLI create command → created projects (non-basic_demo)
Instrucions: Changes must be merged from api_logic_server_cli/prototypes/basic_demo/.github - see instructions there
Usage: AI assistants read this when user opens any created project
version: 3.8
changelog:
  - 3.8 (Feb 25, 2026) - Clarified workflow/messaging scope: ❌ user orchestration (Temporal/Airflow) but ✅ ideal for messaging nodes (Kafka producer, consumer, updates with integrity)
  - 3.7 (Feb 25, 2026) - Added FAQ trigger: maps FAQ/frequently-asked-questions requests to 3-Legged Stool eval content; added capability item 13
  - 3.6 (Feb 23, 2026) - Added System Creation Services section (starter.sqlite / sys_config pattern, SQL DDL → rebuild-from-database workflow, never-write-models-manually rule)
  - 3.5 (Feb 24, 2026) - Dev-focused trim: removed evaluator-only content (Quick Start for Evaluators, About This File, Common Developer Questions FAQ - ~366 lines)
  - 3.4 (Feb 23, 2026) - Added MCP full section, AI-Assisted Dev section, Request Pattern section + 4th training file; merged from customs_app v3.11
  - 3.3 (Feb 2026) - 3-Legged Stool, evaluation checklist, AI docent pattern
  - 3.1 (Nov 20, 2025) - Improved activation instructions with visual markers and examples
  - 3.0 (Nov 17, 2025) - Major streamlining: removed duplicate sections, consolidated MCP content, simplified workflows
  - 2.9 (Nov 17, 2025) - MANDATORY training file reading workflow (STOP command)
  - 2.8 (Nov 16, 2025) - Probabilistic Logic support
---

# GitHub Copilot Instructions for GenAI-Logic (aka API Logic Server) Projects

---

## 🔑 Key Technical Points

**Critical Implementation Details:**

1. **Discovery Systems**: 
   - **Logic Discovery**: Business rules automatically loaded from `logic/logic_discovery/use_case.py` via `logic/logic_discovery/auto_discovery.py`
   - **API Discovery**: Custom APIs automatically loaded from `api/api_discovery/[service_name].py` via `api/api_discovery/auto_discovery.py`
   - Do NOT manually duplicate rule calls or API registrations

2. **API Record ID Pattern**: When creating records via custom APIs, use `session.flush()` before accessing the ID to ensure it's generated:
   ```python
   session.add(sql_alchemy_row)
   session.flush()  # Ensures ID is generated
   record_id = sql_alchemy_row.id
   return {"message": "Success", "record_id": record_id}
   ```

3. **Automatic Business Logic**: All APIs (standard and custom) automatically inherit LogicBank rules without additional code.

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.

> **📋 Testing:** For comprehensive testing conventions, patterns, and examples, see `docs/training/testing.md` (555 lines - I'll read this before we create any tests)

---

## � MCP (Model Context Protocol) Integration

**Every GenAI-Logic project includes comprehensive MCP support out-of-the-box:**

### MCP Server (Automatic)
- **Discovery API**: `/.well-known/mcp.json` exposes schema + learning documentation
- **Standard JSON:API**: All endpoints are MCP-compatible (filtering, pagination, relationships)
- **Business Logic**: Rules automatically execute on all MCP operations
- **Security**: RBAC enforcement applies to MCP requests
- **Located in**: `api/api_discovery/mcp_discovery.py`

### MCP Client (Included)
- **Client Executor**: `integration/mcp/mcp_client_executor.py`
- **Natural Language**: Process queries like "List customers with credit_limit > 1000"
- **LLM Integration**: Uses OpenAI GPT-4 to translate natural language → API calls
- **Example Usage**:
  ```bash
  cd basic_demo
  python integration/mcp/mcp_client_executor.py
  ```

### MCP UI Client (Generate)
Create an interactive web interface for MCP queries:
```bash
genai-logic genai-add-mcp-client
```

### MCP Learning Materials
- **Schema**: `docs/mcp_learning/mcp_schema.json` - OpenAPI schema for AI agents
- **Prompts**: `docs/mcp_learning/mcp.prompt` - Instructions for LLMs on how to use the API
- **Discovery Config**: `integration/mcp/mcp_server_discovery.json` - Server connection details

### Use Cases
1. **AI Agent Integration**: Connect Claude Desktop, Copilot, or ChatGPT
2. **Natural Language Queries**: Business users ask questions in plain English
3. **Orchestration**: Chain multiple API calls based on natural language intent
4. **Testing**: Validate business logic through conversational interaction

---

## 🤖 AI-Assisted Development

**Use AI (Copilot, Claude, ChatGPT) to write Python code for:**

### 1. Business Logic Rules
Describe requirements in natural language → I generate declarative rules:
```python
# You say: "Customer balance is sum of unshipped order totals"
# I write:
Rule.sum(derive=models.Customer.balance, 
         as_sum_of=models.Order.amount_total,
         where=lambda row: row.date_shipped is None)
```

### 2. Custom API Endpoints
Describe API requirements → I generate Python endpoints in `api/api_discovery/`:
```python
# You say: "Create an endpoint to place an order with multiple items"
# I write the complete endpoint with proper session handling
```

### 3. Event Handlers
Describe integration needs → I write event handlers:
```python
# You say: "Send to Kafka when order ships"
# I write the event declaration and handler
```

### 4. Behave Tests
Describe test scenarios → I generate Behave test files:
```gherkin
# You say: "Test that credit limit is enforced on order placement"
# I write complete scenarios in test/api_logic_server_behave/features/
```

**Key Principle**: You focus on **what** (requirements), AI writes **how** (Python implementation).

---

## �📚 Learning Curve (Honest Assessment)

**Timeline:**
- **Week 1:** ~10 hours - Basic rules (sum, count, formula, constraint, copy), see them work
- **Month 1:** ~30 hours total - Comfortable with 90% of use cases, including events and debugging
- **Hardest part:** Mental shift from procedural → declarative thinking (1-2 weeks of practice)
- **AI eliminates the barrier** — see "Think Declarative" below

### The Declarative Mental Shift (Think Spreadsheet)

*Source: [Tech-declarative](https://apilogicserver.github.io/Docs/Tech-declarative/)*

**The Versata Challenge:** Developers instinctively think procedurally. Ask for a credit check and they write: *"When placing an order, multiply price × quantity, add to order total, compare to credit limit, reject if exceeded."*

That's **path-dependent** logic — it solves one use case. Ship an order? Different path, rewrite the logic. Agent updates? Another path, another rewrite. Logic buried in flows, duplicated across every new use case.

**The declarative way:** Instead of "when placing an order, check credit," you declare:
> *"Customer balance is always the sum of unpaid orders and must never exceed the credit limit."*

One rule. It doesn't know about placing orders, shipping, agents, or Vibe apps. It knows about **data**. Because it knows about data, it applies automatically to every path — including paths that don't exist yet.

**The AI Test:** When asked to demonstrate rules, an AI initially responded procedurally (path-dependent). But then it self-corrected — it *distilled* the procedural intent into proper declarative DSL:
```python
Rule.sum(models.Customer.balance, 
         models.Order.amount_total,
         where=lambda row: row.ShippedDate is None)

Rule.constraint(models.Customer, 
                as_condition=lambda row: row.balance <= row.credit_limit)
```
The AI had done spontaneously what took years to teach developers at Versata. **The learning curve that blocked declarative adoption for decades just disappeared.**

**Why:** The DSL rule types (`sum`, `formula`, `constraint`, `copy`) are inherently declarative — they describe invariants about data, not steps in a process. When the AI learns the DSL, it absorbs the declarative mental model with the syntax.

**The Spreadsheet Insight:** Every business runs on spreadsheets. Not because finance teams "think declaratively" — but because spreadsheets make declarative natural. `B10 = SUM(B1:B9)` and the system handles every dependency, every change, every edge case. Nobody writes procedural code to recalculate financials.

That same principle — **automatic reuse over all cases, dependencies managed by the system** — is what declarative rules bring to multi-table transactions.

> **Design Once. Govern All Paths. Correct By Construction.**

**When NOT to use rules:**
- Read-only analytics/reporting (rules enforce writes, not reads)
- Complex algorithms (graph traversal, optimization, ML - not data relationships)
- ❌ User/business workflow orchestration (Temporal/Airflow territory) — but ✅ ideal for *nodes within* workflows: send events, handle messages, execute updates with full integrity
- ❌ Pure stream analytics (Kafka Streams/Flink aggregations) — but ✅ ideal for *initiating* messages (Kafka producer on Order ship) and *handling* incoming messages

**When rules are essential:**
- Data dependency graphs (X affects Y affects Z)
- Multiple change paths (insert/update/delete/FK changes)
- Production systems requiring correctness guarantees
- Long-term maintained systems with evolving requirements

**The Scale Advantage (Production Evidence):**

**Our A/B test (3-table system):**
- AI procedural code: 220 lines, 2 bugs (missed 8 change paths)
- Declarative rules: 5 lines, 0 bugs (engine handles all 9 paths)

**The 9 Transaction Paths** (design once, govern all pathos - automatic re-use- coverage with declarative rules):
1. **Insert Order** → updates Customer.balance
2. **Insert Item** → updates Item.amount, Order.amount_total, Customer.balance  
3. **Update Item.quantity** → recalculates Item.amount, Order.amount_total, Customer.balance
4. **Update Item.unit_price** → recalculates Item.amount, Order.amount_total, Customer.balance
5. **Update Item.product_id** → copies new Product.unit_price, recalculates amounts
6. **Update Item.order_id** → adjusts **both** old and new Order totals, **both** Customers
7. **Delete Item** → adjusts Order.amount_total, Customer.balance
8. **Update Order.customer_id** → adjusts **both** old and new Customer.balance
9. **Update Order.date_shipped** → includes/excludes from Customer.balance calculation

**Why declarative wins:** Rules are defined on the **data** (Customer, Order, Item), not on specific transactions. The engine automatically applies them to ALL change paths. Procedural code must explicitly handle each scenario - easy to miss cases like reassigning items between orders (#6).

**Real enterprise system (100 tables):**
- 80 tables with business logic
- 12 rules per table average = **960 rules total**
- **Procedural approach:** 960 × 44 lines/rule = **42,240 lines to write/maintain**
- **Declarative approach:** ~960 lines written

**The Versata measurement (production systems, 1995-2010):**
- Tracked manual code vs. rules-based code across deployments
- **Result: 97% automation** - developers wrote 3% of equivalent procedural code
- For 100-table system: Write ~1,250 lines, engine automates the other 41,000 lines of logic

**Not about code golf - about correctness at scale:**
- 42k lines with multi-table dependencies = unmaintainable
- When Customer.credit_limit changes, find all 15 places that check it
- Rules: Update one constraint, engine recalculates all affected transactions automatically

### 🪑 The 3-Legged Stool: Rules + AI + Context Engineering

The customs POC ([full case study](https://github.com/KatrinaHuberJuma/customs_app?tab=readme-ov-file#readme)) demonstrates that the results are stunning — but only when all three legs work together:

| Leg | What it provides | Without it |
|-----|-----------------|------------|
| **Logic Automation** (Rules Engine) | Correct, auto-enforced business logic across all write paths; enterprise API | Path-dependent procedural code with missed cases and bugs |
| **Generative AI** | Rapid creation, iteration, test generation from natural language | Weeks of manual development |
| **Context Engineering** | Guides AI to the right architecture (declarative rules, proper data model) | AI defaults to "Fat API" procedural code — works but ungoverned |

**Key insight:** Without Context Engineering, AI generates working demos that lack enterprise architecture. Without rules automation, AI generates procedural code with correctness bugs. Together: a several-week effort became **30 minutes**, producing a correct, enterprise-class, fully tested system.

> *"A/B result: 16 declarative rules vs. equivalent procedural code with 2 critical bugs."*

---

## Detailed Service Documentation

The sections below provide complete details on each service. I'll reference these as needed when we work together.

### Critical Pattern: Request Pattern

**What it is:** Insert a row (request object) that triggers business logic via an event handler.

**Why it exists:**
- **Separation of concerns** - Calling code doesn't know implementation details
- **Automatic audit trail** - Request row captures what/when/why with full context
- **Testability** - Insert request row in tests, verify results
- **Reusability** - Same request handler works from API, UI, workflows, tests

**Common use cases:**
- **Send email** - Insert SysMailReq row → event checks opt-out, sends email, logs activity
- **Kafka integration** - Insert request row → event publishes message to topic
- **AI Logic** - Insert SysSupplierReq → event calls AI to find optimal supplier based on cost, lead time, world conditions
- **Audit trails** - Insert SysAuditReq → event captures operation details
- **External API calls** - Insert request row → event calls external service, captures response

**Implementation pattern:**
```python
def get_supplier_from_ai(product_id: int, logic_row: LogicRow) -> models.SysSupplierReq:
    """
    Wrapper that hides Request Pattern complexity.
    Caller just gets back a populated result object.
    """
    # 1. Create request row (pass CLASS not instance)
    req_logic_row = logic_row.new_logic_row(models.SysSupplierReq)
    req = req_logic_row.row

    # 2. Set input context
    req.product_id = product_id

    # 3. Insert triggers event that populates AI results
    req_logic_row.insert(reason="AI supplier selection")

    # 4. Return populated object (chosen_supplier_id, chosen_unit_price now set)
    return req
```

**See:**
- Implementation details: `docs/training/logic_bank_patterns.md` (PATTERN 3)
- Real examples: `logic/logic_discovery/place_order/ai_requests/supplier_selection.py`
- MCP integration: https://apilogicserver.github.io/Docs/Integration-MCP/#3b-logic-request-pattern

### System Creation Services (New Domain Project)

**Trigger:** `database/models.py` contains only the `SysScalar` class — no domain tables yet. The project was created from `starter.sqlite` and is waiting for a domain schema.

**`sys_config` — the settings table pattern:**  
`starter.sqlite` includes one table: `sys_config` (one row). This is a deliberate pattern — systems often need global configuration values (discount rates, tax rates, thresholds) that users manage via the Admin UI rather than code deploys. A named-column, single-row table lets LogicBank rules reference settings directly: `row.sys_config.discount_rate`. **Keep `sys_config`** in your domain schema; add columns for any domain-wide scalars.

**Workflow:**

1. **Get the domain prompt** — from the user, or from `../samples/prompts/<name>.prompt.md`

2. **Read subsystem conventions first** — load `docs/training/implement_requirements.md` before designing the schema:
   - `id INTEGER PRIMARY KEY AUTOINCREMENT` for all PKs
   - Include columns for all derived/calculated values (populated by LogicBank rules later)
   - Follow naming conventions in that file

3. **Check for Request Pattern signals** — if the prompt says "when X is given, calculate Y": apply the Request Pattern (`docs/training/RequestObjectPattern.md`) — a table with input fields + response fields computed by `early_row_event`

4. **Design schema as SQL DDL and run it:**
```bash
sqlite3 database/db.sqlite << 'SQL'
-- Keep sys_config; add domain-specific columns if needed
ALTER TABLE sys_config ADD COLUMN domain_rate REAL DEFAULT 0.0;
-- Then create domain tables:
CREATE TABLE your_table (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    ...
);
SQL
```
**⚠️ Never write `models.py` manually.** Hand-written models miss required boilerplate (`db`, `Base`, `SAFRSBaseX` conditional, `_s_collection_name`) → `discovered models: []` at startup and no JSON:API endpoints registered.

5. **Rebuild models from database:**
```bash
source venv/bin/activate
genai-logic rebuild-from-database --db_url=sqlite:///database/db.sqlite
```
This auto-generates correct `models.py` with all boilerplate intact.

6. **Add seed data** — create `database/test_data/<name>_seed.py` using **plain `DeclarativeBase` models** (not SAFRS models — seed scripts run outside Flask context and cannot import SAFRS-based models).

7. **Add logic** — declare `Rule.*` rules in `logic/logic_discovery/` using `docs/training/logic_bank_api.md`. Use `Rule.formula`, `Rule.sum`, `Rule.copy`, `Rule.constraint` — never procedural code in endpoints.

8. **Press F5** — full JSON:API + Admin UI + logic enforcement.

**Key rules:**
- Never write `models.py` manually — always `rebuild-from-database` after SQL DDL
- Never copy from existing projects — generate fresh from the prompt
- Never use `genai-logic genai` — write SQL DDL directly

---

### `venv` is required

To establish the virtual environment:

1. Attempt to find a `venv` folder in the current project directory
2. If not found, check parent or grandparent directories
3. **If no venv is found:**
   - Ask the user for the venv location, OR
   - Offer to create one using `python3 -m venv venv && source venv/bin/activate && pip install -r requirements.txt`

### Starting the server

**IMPORTANT:** Always activate the venv before starting the server.

```bash
# Activate venv first
source venv/bin/activate

# Then start server
python api_logic_server_run.py
# Then open: http://localhost:5656
```

**Server Management Best Practices:**
- Before making structural changes (models, logic files), STOP the running server to avoid file locking issues
- To stop server: `pkill -f "python api_logic_server_run.py"` or use Ctrl+C if running in foreground
- USER ACTION: After making changes, user restarts server (e.g., `python api_logic_server_run.py &`)
- Monitor startup output for errors, especially after database/model changes
- If server fails to start after model changes, check that alembic migrations have been applied

### Adding Business Logic

**For Human Learning:**
- **Primary Resource:** https://apilogicserver.github.io/Docs/Logic/
  - Complete rule type reference tables
  - Pattern tables and best practices
  - Video tutorials and examples
  - Learning path recommendations
- Use this as your main learning resource for understanding rules

**For AI Code Generation:**
- `docs/training/*.prompt` files contain patterns for AI assistants
- AI reads these BEFORE implementing logic
- Not intended as primary human learning materials

**Rule Example:**
```python
# Edit: logic/declare_logic.py
Rule.sum(derive=Customer.Balance, as_sum_of=Order.AmountTotal)
Rule.constraint(validate=Customer, as_condition=lambda row: row.Balance <= row.CreditLimit)
```

**⚠️ CRITICAL: docs/training/ Folder Organization**

The `docs/training/` folder contains ONLY universal, framework-level training materials:
- ✅ **Universal patterns** → `genai_logic_patterns.md`
- ✅ **Implementation patterns** → `probabilistic_logic_guide.md`
- ✅ **Code templates** → `probabilistic_template.py`
- ✅ **API references** → `.prompt` files (logic_bank_api.md, etc.)

**DO NOT add project-specific content to docs/training/**:
- ❌ Project-specific instructions or configurations
- ❌ Alembic migration guides specific to this project
- ❌ File structures specific to basic_demo
- ❌ Copilot instructions that reference specific project paths

**WHY:** This folder's content is designed to be reusable across ANY ApiLogicServer project using GenAI. Project-specific content should live in:
- Logic implementation → `logic/logic_discovery/`
- Project docs → `docs/` (outside training/)
- Copilot instructions → `.github/.copilot-instructions.md`

See `docs/training/README.md` for complete organization rules.

**⚠️ MANDATORY WORKFLOW - BEFORE Implementing ANY Business Logic:**

```
STOP ✋

WHEN USER PROVIDES A LOGIC PROMPT:

STEP 1: Read these files (DO THIS FIRST - NOT OPTIONAL):
   1. docs/training/logic_bank_patterns.md           (Foundation - READ FIRST)
   2. docs/training/logic_bank_api.md                (Business Rules - READ SECOND)
   3. docs/training/probabilistic_logic.md           (AI Rules - READ THIRD)
   4. docs/training/RequestObjectPattern.md          (Integration services pattern - READ FOURTH)

STEP 2: Analyze the prompt for Request Pattern signals:
   - Does prompt say "calculate/determine/select [X] when [Y] is given"?
   - Integration service needed (AI, external API, messaging, email)?
   - Compliance/audit domain (customs, finance, healthcare)?
   - IF YES → Use Request Pattern (see RequestObjectPattern.md)
   - IF NO → Continue to Step 3

STEP 3: Parse the prompt following logic_bank_api.md instructions:
   - Identify context phrase ("When X", "For Y", "On Z") → creates directory
   - Identify colon-terminated use cases → creates files
   - Follow directory structure rules EXACTLY as specified

STEP 4: Create the directory structure and logic files as instructed

STEP 5: ⛔ Create `docs/requirements/<use_case_name>/requirements.md` — MANDATORY, NO EXCEPTIONS
   Copy the user's prompt verbatim into this file. Do NOT paraphrase.
   This is the anchor for the logic diagram and requirements traceability chain:
     requirements.md → logic file → logic diagram → behave tests → execution trace
   Use the same directory name as the logic discovery directory.
   If the use case name is unknown, use `docs/requirements/unknown_use_case/requirements.md`.

STEP 6: Implement the rules following the training patterns

⚠️ CRITICAL - NO EXCEPTIONS:
   - You MUST read all four training files before implementing
   - You MUST analyze for Request Pattern BEFORE creating fat APIs
   - You MUST follow the directory structure rules in logic_bank_api.md
   - You MUST NOT create flat files when context phrase is present
   - STEP 5 is mandatory — always create docs/requirements/<use_case_name>/requirements.md
   - DO NOT skip files even if you think you know the pattern
   - These files contain failure patterns learned from production use

FAILURE MODE: Creating fat API services when Request Pattern applies
CORRECT: Request Pattern table + early_row_event + thin API wrapper
```

**Training File Contents:**

1. **`docs/training/logic_bank_patterns.md`** - Foundation patterns for ALL rule types
   - Event handler signatures (row, old_row, logic_row) - REQUIRED READING
   - Logging with logic_row.log() vs app_logger
   - Request Pattern with new_logic_row()
   - Rule API syntax dos and don'ts
   - Common anti-patterns to avoid
   
2. **`docs/training/logic_bank_api.md`** - Business Rules API
   - Rule.sum(), Rule.count(), Rule.formula(), Rule.constraint(), etc.
   - Complete API signatures with all parameters
   - References patterns file for implementation details
   
3. **`docs/training/probabilistic_logic.md`** - AI Rules API
   - AI-driven value computation and intelligent selection
   - Intelligent selection patterns (supplier optimization, dynamic pricing, route selection)
   - Automatic audit trails and graceful fallbacks when API unavailable
   - References patterns file for general implementations
   - Works seamlessly with Business Rules

4. **`docs/training/RequestObjectPattern.md`** - Integration services pattern
   - When to use Request Pattern vs other approaches
   - Request fields (input) + Response fields (output) + early_row_event (integration)
   - AI Intelligent Selection Pattern (supplier, carrier, pricing, routing)
   - Wrapper functions for hiding complexity
   - Anti-pattern: Fat API services with business logic
   - Works with unified deterministic/probabilistic architecture

**Example Natural Language Logic for basic_demo:**

```text
on Placing Orders, Check Credit:

1. The Customer's balance is less than the credit limit
2. The Customer's balance is the sum of the Order amount_total where date_shipped is null
3. The Order's amount_total is the sum of the Item amount
4. The Item amount is the quantity * unit_price
5. The Product count suppliers is the sum of the Product Suppliers
6. Use AI to Set Item field unit_price by finding the optimal Product Supplier 
                                          based on cost, lead time, and world conditions

Use case: App Integration
1. Send the Order to Kafka topic 'order_shipping' if the date_shipped is not None.
```

⚠️ **CRITICAL - Rule 6 dependency ordering:**  
Rule 6 sets `Item.unit_price`, which is an **input** to Rule 4 (`Item.amount = quantity * unit_price`).  
You MUST use `Rule.early_row_event` (not `Rule.row_event`) on the Item class.  
`row_event` fires AFTER formulas — `Item.amount` would be computed on the old/null price, **silently**.  
`early_row_event` fires BEFORE formulas — AI price is available when Rule 4 runs.  
See: [early_row_event vs row_event](docs/training/probabilistic_logic.md#the-pattern)

**How the Rules Engine Works:**

**1. Authoring (AI-assisted, human-reviewed)**
- You express business intent in natural language (via Copilot or any AI assistant)
- The AI translates intent into a declarative DSL, under human review
- Distills path-dependent logic into data-bound rules (table invariants) for automatic re-use
- Resolves ambiguity using schema and relationships (e.g., copy vs reference)
- Produces readable rules developers can inspect, edit, debug and version

*This is where AI helps — authoring, not execution.*

**2. Engine Initialization (Deterministic analysis)**
- On startup, the non-RETE rule engine loads all rules
- It computes dependencies deterministically from Rule types (derivations, constraints, actions)
- Execution order is derived once, not from code paths

No compilation. No dependencies-from-pattern-matching. No inference from runtime behavior.

**3. Runtime Enforcement (Transaction commit — 3 ordered sub-phases)**

All writes — APIs, workflows, UIs, agents — pass through the same rule set. Dependencies already known from initialization; execution is deterministic and efficient. **No rule is "called." No path can bypass enforcement.** Non-RETE optimizations: pruning, adjustment logic, delta-based aggregations.

**Phase 3a: Row Logic** (`before_flush`)
Three sub-loops (update, insert, delete) — one conceptual phase. The system creates `logic_row` objects and runs rules (formula, sum, count, copy, constraint), which may cascade: a derived change on one row triggers rules on related rows (e.g., `Item.amount` → adjusts `Order.amount_total` → adjusts `Customer.balance`). **Cascading via old_row tracking** — when `Order.customer_id` changes, adjusts BOTH old and new `Customer.balance`.

**Phase 3b: Commit Logic** (`before_flush`, after Row Logic)
One loop over all `processed_rows`, firing `CommitRowEvent` and `CommitConstraint` rules. Runs *after* all derivations are complete — these rules see finalized sums/counts. Use this phase for constraints that depend on aggregates.

**Phase 3c: After Flush Logic** (`after_flush`)
One loop over `processed_rows`, firing `AfterFlushRowEvent`. Database-generated primary keys are now available (autoincrement IDs assigned). Use this phase to publish Kafka messages, send webhooks, or call external APIs where you need the persisted row ID.

**Key implications for rule design:**
- `Rule.constraint` / `Rule.formula` / `Rule.sum` → Row Logic (Phase 3a)
- `Rule.commit_row_event` / `CommitConstraint` → after aggregates finalize (Phase 3b)
- `Rule.after_flush_row_event` → when you need database-assigned PKs, e.g., Kafka publish (Phase 3c)

**The Key Developer Insight:**

You declare invariants on data. You don't wire rules into flows. Invocation is automatic, on commit. The engine enforces them — everywhere, automatically, at commit.

**Why Declarative Rules Matter:**

LogicBank provides **~40X code reduction** (5 lines vs 220+ procedural) with:
- **Automatic ordering** - add rules anywhere that makes sense, confident they'll run in the right order
- **Understanding intent** - you see WHAT it does (business rules) vs HOW (procedural steps)
- **Maintenance** - no need to find insertion points or trace execution paths

**Why the Rules Engine is a Correctness Guarantee:**

The "2 critical bugs" that even AI-generated procedural code missed:
1. **Changing Order.customer_id** - procedural code failed to adjust BOTH the old and new customer balances
2. **Changing Item.product_id** - procedural code failed to re-copy the unit_price from the new product

These bugs illustrate why declarative rules are **mandatory, not optional**. Even AI-generated procedural code requires explicit handlers for EVERY possible change path. It's easy to miss:
- Foreign key changes affecting multiple parents
- Transitive dependencies through multiple tables
- Where clause conditions that include/exclude rows

The rules engine eliminates this entire class of bugs by automatically handling all change paths.

**The Complete A/B Test:**

For the full experiment comparing declarative rules vs AI-generated procedural code, including the 2 bugs Copilot missed and the AI's own analysis of why it failed, see:
https://github.com/ApiLogicServer/ApiLogicServer-src/blob/main/api_logic_server_cli/prototypes/basic_demo/logic/procedural/declarative-vs-procedural-comparison.md

### Discovery Systems

**IMPORTANT**: The project uses automated discovery systems that:

**Logic Discovery:**
1. **Automatically loads business logic** from `logic/logic_discovery/*.py`
    * **CRITICAL: Always create separate files named for each use case** (e.g., `check_credit.py`, `app_integration.py`)
    * **Never put multiple use cases in `use_case.py`** - that file is for templates/examples only
2. **Discovers rules at startup** via `logic/logic_discovery/auto_discovery.py`
3. **No manual rule loading required** - the `discover_logic()` function automatically finds and registers rules

**API Discovery:**
1. **Automatically loads custom APIs** from `api/api_discovery/[service_name].py`
2. **Discovers services at startup** via `api/api_discovery/auto_discovery.py` (called from `api/customize_api.py`)
3. **No manual API registration required** - services are automatically discovered and exposed

**Do NOT duplicate** by calling them manually. The discovery systems handle this automatically.

**Implementation Locations**:
- Business rules: `logic/logic_discovery/use_case.py`
- Custom APIs: `api/api_discovery/[service_name].py`
- System automatically discovers and loads both

**Pattern**:
```python
# logic/logic_discovery/use_case.py
def declare_logic():
    """Business logic rules for the application"""
    Rule.sum(derive=Customer.balance, as_sum_of=Order.amount_total)
    Rule.constraint(validate=Customer, as_condition=lambda row: row.balance <= row.credit_limit)
    # ... other rules
```

**PATTERN RECOGNITION for Business Logic**:
When users provide natural language with multiple use cases like:
- "on Placing Orders, Check Credit" + "Use case: App Integration"

**ALWAYS create separate files**:
- `logic/logic_discovery/check_credit.py` - for credit checking rules
- `logic/logic_discovery/app_integration.py` - for integration rules

**NEVER put everything in `use_case.py`** - that defeats the discovery system purpose.

### MCP Integration

**You (GitHub Copilot) can serve as an MCP client** to query and update database entities using natural language!

#### MCP Discovery Endpoint (CRITICAL)

**ALWAYS start with the standard MCP discovery endpoint:**

```bash
curl -X GET "http://localhost:5656/.well-known/mcp.json"
```

This endpoint returns:
- **Available resources** - Customer, Order, Item, Product, etc.
- **Supported methods** - GET, PATCH, POST, DELETE per resource
- **Filterable fields** - Which attributes can be used in filters
- **Base URL and paths** - Resource endpoints like `/Customer`, `/Order`
- **Learning prompts** - Instructions for MCP clients (fan-out patterns, email handling, response format)

**MCP Discovery Pattern:**
1. **First**: Query `/.well-known/mcp.json` to discover available resources
2. **Then**: Use discovered schema to construct API calls
3. **Always**: Follow JSON:API format for CRUD operations


**When users request data operations:**

1. **Authenticate first** - Login to obtain JWT token:
```bash
curl -X POST http://localhost:5656/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"p"}'
```

2. **Execute operations** - Use Bearer token for API calls:
```bash
# Read: List entities
curl -X GET http://localhost:5656/api/Customer/ \
  -H "Authorization: Bearer {token}"

# Update: Change attributes (JSON:API format)
curl -X PATCH http://localhost:5656/api/Customer/ALFKI/ \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/vnd.api+json" \
  -d '{"data": {"type": "Customer", "id": "ALFKI", "attributes": {"CreditLimit": 5000}}}'
```

3. **Handle constraint violations correctly** - Error code 2001 is SUCCESS!
   - When LogicBank prevents invalid updates, report as: "✅ Business logic working - constraint prevented invalid operation"
   - Example: "balance (2102.00) exceeds credit (1000.00)" = logic is protecting data integrity

**Natural Language → API Translation:**
- "List customers" → `GET /api/Customer/`
- "Show customer ALFKI" → `GET /api/Customer/ALFKI/`
- "Set ALFKI credit to 5000" → `PATCH /api/Customer/ALFKI/` with CreditLimit
- "What's ALFKI's balance?" → `GET /api/Customer/ALFKI/` then extract Balance

**Key Principle:** Constraint violations (code 2001) demonstrate that declarative business logic is working correctly - celebrate these as successes, not failures!

See `docs/training/MCP_Copilot_Integration.md` for authentication workflows, JSON:API formats, and architecture details.

### API Interaction Best Practices

**CRITICAL: Always Use API, Not Direct Database Access**

When users request data operations (read, update, create, delete), **ALWAYS use the REST API** instead of direct database queries:

✅ **Correct Approach - Use API:**
```bash
# Simple, readable commands that trigger business logic
curl 'http://localhost:5656/api/Customer/?page[limit]=100'
curl -X PATCH 'http://localhost:5656/api/Item/2/' \
  -H 'Content-Type: application/vnd.api+json' \
  -d '{"data": {"type": "Item", "id": "2", "attributes": {"quantity": 100}}}'
```

❌ **Wrong Approach - Direct Database:**
```bash
# DON'T use sqlite3 commands for data operations
sqlite3 database/db.sqlite "UPDATE item SET quantity=100 WHERE id=2"
```

**Why API is Required:**
1. **Business Logic Execution** - Rules automatically fire (calculations, validations, constraints)
2. **Data Integrity** - Cascading updates handled correctly
3. **Audit Trail** - Operations logged through proper channels
4. **Security** - Authentication/authorization enforced
5. **Testing Reality** - Tests actual system behavior

**Server Startup for API Operations:**

When server needs to be started for API operations:

```bash
# Option 1: Background process (for interactive testing)
python api_logic_server_run.py &
sleep 5  # Wait for full startup (not 3 seconds - too short!)

# Option 2: Use existing terminal/process
# Check if already running: lsof -i :5656
```

**Common Mistakes to Avoid:**

1. ❌ **Insufficient startup wait**: `sleep 3` often fails
   - ✅ Use: `sleep 5` or check with `curl` in retry loop

2. ❌ **Complex inline Python**: Piping JSON to `python3 -c` with complex list comprehensions
   - ✅ Use: Simple `curl` commands, pipe to `jq` for filtering, or save to file first

3. ❌ **Database queries for CRUD**: Using `sqlite3` commands
   - ✅ Use: API endpoints that trigger business logic

**Simple API Query Patterns:**

```bash
# Get all records (simple, reliable)
curl 'http://localhost:5656/api/Customer/'

# Get specific record by ID
curl 'http://localhost:5656/api/Customer/1/'

# Get related records (follow relationships)
curl 'http://localhost:5656/api/Customer/1/OrderList'

# Filter results (use bracket notation)
curl 'http://localhost:5656/api/Customer/?filter[name]=Alice'

# Limit results
curl 'http://localhost:5656/api/Customer/?page[limit]=10'
```

**Parsing JSON Responses:**

```bash
# Simple: Pipe to python -m json.tool for pretty printing
curl 'http://localhost:5656/api/Customer/' | python3 -m json.tool

# Better: Use jq if available
curl 'http://localhost:5656/api/Customer/' | jq '.data[] | {id, name: .attributes.name}'

# Alternative: Save to file first, then parse
curl 'http://localhost:5656/api/Customer/' > customers.json
python3 -c "import json; data=json.load(open('customers.json')); print(data['data'][0])"
```

**Key Principle**: The API is not just a convenience - it's the **only correct way** to interact with data because it ensures business logic executes properly.

### Automated Testing

**⚠️ BEFORE Creating Tests:**

```
STOP ✋
READ docs/training/testing.md FIRST (555 lines - comprehensive guide)

This contains EVERY bug pattern from achieving 11/11 test success:
- Rule #0: Test Repeatability (timestamps for uniqueness)
- Rule #0.5: Behave Step Ordering (specific before general)
- Top 5 Critical Bugs (common AI mistakes)
- Filter format: filter[column]=value (NOT OData)
- No circular imports (API only)
- Null-safe constraints
- Fresh test data (timestamps for uniqueness)

THEN create tests following patterns exactly.
```

**Why This Matters:** AI-generated tests fail 80% of the time without reading this guide first. The training material documents every common mistake (circular imports, wrong filter format, null-unsafe constraints, step ordering, etc.) with exact fixes. This guide achieved 11/11 test success (100%) and contains all discovered patterns.

**`docs/training/testing.md`** explains how to create Behave tests from declarative rules, execute test suites, and generate automated documentation with complete logic traceability.

**Key capabilities:**
- **Create tests from rules** - Analyze declarative rules to generate appropriate test scenarios
- **Execute test suite** - Run all tests with one command (Launch Configuration: "Behave Run")
- **Generate documentation** - Auto-create wiki reports showing requirements, tests, rules used, and execution traces
- **Requirements traceability** - Complete chain from business requirement → test → declarative rule → execution log

**The Innovation:** Unlike traditional testing, Behave Logic Reports show **which declarative rules fired** during each test, providing complete transparency from requirement to execution. This solves the ~40X advantage in testing - tests verify "what" (business rules) not "how" (procedural code).

See `test/api_logic_server_behave/` for examples and [published report](https://apilogicserver.github.io/Docs/Behave-Logic-Report/).

**Common Mistakes to Avoid (from testing.md):**
1. ❌ Wrong filter: `filter="name eq 'Alice'"` → ✅ Use: `filter[name]="Alice"`
2. ❌ Importing logic/database modules → ✅ Import only: behave, requests, test_utils
3. ❌ Unsafe constraints: `row.x <= row.y` → ✅ Use: `row.x is None or row.y is None or row.x <= row.y`
4. ❌ Step execution: `step_impl.execute_step()` → ✅ Use: `context.execute_steps('when Step')`
5. ❌ Reusing test data → ✅ Create fresh with: `f"{name} {int(time.time()*1000)}"`

**For detailed test creation patterns, see `docs/training/testing.md` which documents all critical rules including Rule #0.5 (Behave Step Ordering).**

#### Critical Learnings: Behave Logic Report Generation

**PROBLEM**: Reports not showing logic details for test scenarios.

**ROOT CAUSES DISCOVERED**:

1. **Empty behave.log** (Most Common Issue)
   - ❌ Running: `python behave_run.py` 
   - ✅ Must run: `python behave_run.py --outfile=logs/behave.log`
   - Without `--outfile`, behave.log remains empty (0 bytes) and report has no content

2. **Scenario Name Mismatch** 
   - Log files must match scenario names from .feature file
   - ❌ Using custom names: `scenario_name = f'B2B Order - {quantity} {product_name}'`
   - ✅ Use actual scenario: `scenario_name = context.scenario.name`
   - Report generator truncates to 25 chars and looks for matching .log files

3. **Report Generator Logic Bug**
   - Original code only showed logic when blank line followed "Then" step
   - Only worked for ~30% of scenarios (those with blank lines in behave.log)
   - ✅ Fixed: Trigger logic display when next scenario starts OR at end of file

**CORRECT PATTERN FOR WHEN STEPS**:

```python
@when('B2B order placed for "{customer_name}" with {quantity:d} {product_name}')
def step_impl(context, customer_name, quantity, product_name):
    """
    Phase 2: CREATE using OrderB2B API - Tests OrderB2B integration
    """
    scenario_name = context.scenario.name  # ← CRITICAL: Use actual scenario name
    test_utils.prt(f'\n{scenario_name}\n', scenario_name)
    
    # ... test implementation ...
```

**WORKFLOW FOR REPORT GENERATION**:

```bash
# 1. Run tests WITH outfile to generate behave.log
python behave_run.py --outfile=logs/behave.log

# 2. Generate report (reads behave.log + scenario_logic_logs/*.log)
python behave_logic_report.py run

# 3. View report
open reports/Behave\ Logic\ Report.md
```

**WHAT THE REPORT SHOWS**:
- Each scenario gets a `<details>` section with:
  - **Rules Used**: Which declarative rules fired (numbered list)
  - **Logic Log**: Complete trace showing before→after values for all adjustments
- Demonstrates the ~40X code reduction by showing rule automation

**LOGIC LOG FORMATTING**:

**When user says "show me the logic log"**: Display the complete logic execution from the most recent terminal output, showing the full trace from "Logic Phase: ROW LOGIC" through "Logic Phase: COMPLETE" with all row details intact (do NOT use grep commands to extract). Include:
- Complete Logic Phase sections (ROW LOGIC, COMMIT LOGIC, AFTER_FLUSH LOGIC, COMPLETE)
- All rule execution lines with full row details
- "These Rules Fired" summary section
- Format as code block for readability

When displaying logic logs to users, format them with proper hierarchical indentation like the debug console (see https://apilogicserver.github.io/Docs/Logic-Debug/):

```
Logic Phase: ROW LOGIC (session=0x...)
..Item[None] {Insert - client} id: None, order_id: 1, product_id: 6, quantity: 10
..Item[None] {Formula unit_price} unit_price: [None-->] 105.0
....SysSupplierReq[None] {Insert - Supplier AI Request} product_id: 6
....SysSupplierReq[None] {Event - calling AI} chosen_unit_price: [None-->] 105.0
..Item[None] {Formula amount} amount: [None-->] 1050.0
..Item[None] {adjust parent Order.amount_total}
....Order[1] {Update - Adjusting order: amount_total} amount_total: [300.0-->] 1350.0
```

**Key formatting rules:**
- `..` prefix = nesting level (2 dots = parent, 4 dots = child/nested object, 6 dots = deeper nesting)
- **ONE LINE per rule execution** - no line wrapping
- Each line shows: `Class[id] {action/reason} key_attributes`
- Value changes shown as: `[old_value-->] new_value`
- Hierarchical indentation (dots) shows call depth and parent-child relationships
- Only show relevant attributes, not all row details

**EXTRACTING CLEAN LOGIC LOGS**:

To get properly formatted logs (one line per rule, no wrapping), use this command:

```bash
# Extract clean logic log from server.log
grep -A 100 "Logic Phase:.*ROW LOGIC" server.log | \
  awk -F' row: ' '{print $1}' | \
  grep -E "^\.\.|^Logic Phase:" | \
  head -50
```

This removes verbose session/row details and prevents line wrapping.

**DEBUGGING TIPS**:

```bash
# Check if behave.log has content
ls -lh logs/behave.log  # Should be several KB, not 0 bytes

# Check if scenario logs exist with correct names
ls logs/scenario_logic_logs/ | head -10

# Count detail sections in report (should equal number of scenarios)
grep -c "<details markdown>" reports/Behave\ Logic\ Report.md

# View a specific scenario's log directly
cat logs/scenario_logic_logs/Delete_Item_Reduces_Order.log
```

**KEY INSIGHT**: The report generator uses a two-step process:
1. Reads behave.log for scenario structure (Given/When/Then steps)
2. Matches scenario names to .log files in scenario_logic_logs/
3. Injects logic details at the right location in the report

If scenario names don't match between behave.log and .log filenames, logic details won't appear!

### Adding MCP UI

The API is automatically MCP-enabled. The project includes a comprehensive MCP client executor at `integration/mcp/mcp_client_executor.py`, but to enable the **user interface** for MCP requests, you must run this command:

```bash
genai-logic genai-add-mcp-client
```

**CRITICAL DISTINCTION**:
- **`integration/mcp/mcp_client_executor.py`** = MCP processing engine (already exists)
- **`genai-logic genai-add-mcp-client`** = Command to add SysMcp table and UI infrastructure (must be run)

**When users ask to "Create the MCP client executor"**, they mean run the `genai-logic genai-add-mcp-client` command, NOT recreate the existing processing engine.

This command adds:
1. **SysMcp table** for business users to enter natural language requests
2. **Admin App integration** for MCP request interface
3. **Database infrastructure** for MCP client operations

### Configuring Admin UI

This is built when project is created - no need to add it.
Customize by editing the underlying yaml.

```yaml
# Edit: ui/admin/admin.yaml
resources:
  Customer:
    attributes:
      - name: CompanyName
        search: true
        sort: true
```

### Create and Customize React Apps

**REQUIRED METHOD**: Complete customization is provided by generating a React Application (requires OpenAI key, Node):

**DO NOT use `create-react-app` or `npx create-react-app`**
**ALWAYS use this command instead:**

```bash
# Create: ui/admin/my-app-name
genai-logic genai-add-app --app-name=my-app-name --vibe
```

Then, `npm install` and `npm start`

Temporary restriction: security must be disabled.

**IMPORTANT**: When working with React apps, ALWAYS read `docs/training` first. This file contains critical data access provider configuration that was built when the project was created. The data provider handles JSON:API communication and record context - ignore this at your peril.

Customize using CoPilot chat, with `docs/training`.

#### React Component Development Best Practices

**Critical Pattern for List/Card Views**: When implementing custom views (like card layouts) in React Admin components:

1. **Use `useListContext()` correctly**: Access `data` as an array, not as an object with `ids`
   ```javascript
   // CORRECT Pattern:
   const { data, isLoading } = useListContext();
   return (
     <Grid container spacing={2}>
       {data?.map(record => (
         <Grid item key={record.id}>
           <CustomCard record={record} />
         </Grid>
       ))}
     </Grid>
   );
   
   // AVOID: Trying to use data[id] pattern - this is for older React Admin versions
   ```


2. **Component Naming Consistency**: Ensure component names match their usage in JSX - mismatched names cause runtime errors.

3. **Simple Error Handling**: Use straightforward loading states rather than complex error checking:
    ```javascript
    if (isLoading) return <div>Loading...</div>;
    ```

4. 🃏 Card View Action Links (Show, Edit, Delete) **IMPORTANT:** All card views (e.g., Product cards) must include action links or buttons for **Show**, **Edit**, and **Delete** for each record (not just the display fields), matching the functionality of the table/list view.


**Common Mistakes to Avoid**:
- Using `{ data, ids }` destructuring and trying to map over `ids` - this pattern is outdated
- Creating complex error handling when simple loading checks suffice
- Not referencing existing working implementations before creating new patterns

### Security - Role-Based Access Control

Configure:
```
genai-logic add-auth --provider-type=sql --db-url=
genai-logic add-auth --provider-type=sql --db_url=postgresql://postgres:p@localhost/authdb

genai-logic add-auth --provider-type=keycloak --db-url=localhost
genai-logic add-auth --provider-type=keycloak --db-url=hardened

genai-logic add-auth --provider-type=None # to disable
``` 

Keycloak quick start [(more information here:)](https://apilogicserver.github.io/Docs/Security-Keycloak/)
```bash
cd devops/keycloak
docker compose up
genai-logic add-auth --provider-type=keycloak --db-url=localhost
```

For more on KeyCloak: https://apilogicserver.github.io/Docs/Security-Keycloak/

Declaration:
```python
# Edit: security/declare_security.py
Grant(on_entity=Customer, to_role=sales, filter=lambda: Customer.SalesRep == current_user())
```


#### Testing with Security Enabled

**CRITICAL:** When `SECURITY_ENABLED=True`, test code must obtain and include JWT authentication tokens.

**Pattern for test steps:**
```python
from pathlib import Path
import os
from dotenv import load_dotenv

# Load config to check SECURITY_ENABLED
config_path = Path(__file__).parent.parent.parent.parent.parent / 'config' / 'default.env'
load_dotenv(config_path)

# Cache for auth token (obtained once per test session)
_auth_token = None

def get_auth_token():
    """Login and get JWT token if security is enabled"""
    global _auth_token
    
    if _auth_token is not None:
        return _auth_token
    
    # Login with default admin credentials
    login_url = f'{BASE_URL}/api/auth/login'
    login_data = {'username': 'admin', 'password': 'p'}
    
    response = requests.post(login_url, json=login_data)
    if response.status_code == 200:
        _auth_token = response.json().get('access_token')
        return _auth_token
    else:
        raise Exception(f"Login failed: {response.status_code}")

def get_headers():
    """Get headers including auth token if security is enabled"""
    security_enabled = os.getenv('SECURITY_ENABLED', 'false').lower() not in ['false', 'no']
    
    headers = {'Content-Type': 'application/json'}
    
    if security_enabled:
        token = get_auth_token()
        if token:
            headers['Authorization'] = f'Bearer {token}'
    
    return headers

# Use in all API requests
response = requests.post(url=api_url, json=data, headers=get_headers())
```

**Key points:**
- Tests DO NOT automatically include auth headers - you must code this pattern
- Token is cached to avoid repeated logins during test session
- Pattern works for both `SECURITY_ENABLED=True` and `SECURITY_ENABLED=False`
- See `test/api_logic_server_behave/features/steps/order_processing_steps.py` for complete example
### Adding Custom API Endpoints

For simple endpoints:
```python
# Edit: api/customize_api.py
@app.route('/api/custom-endpoint')
def my_endpoint():
    return {"message": "Custom endpoint"}
```

### Creating Advanced B2B Integration APIs with Natural Language

Users can create sophisticated custom API endpoints for B2B integration using natural language. The system automatically generates and discovers:

1. **Custom API Service** (`api/api_discovery/[service_name].py`) - automatically discovered by `api/api_discovery/auto_discovery.py`
2. **Row Dict Mapper** (`integration/row_dict_maps/[MapperName].py`)

**Example Implementation**: This project includes a working **OrderB2B API** that demonstrates the complete pattern:
- **API**: `api/api_discovery/order_b2b_service.py`
- **Mapper**: `integration/row_dict_maps/OrderB2BMapper.py`
- **Test Cases**: `test_requests.http` and `test_b2b_order_api.py`

**Pattern Recognition**: When users describe B2B integration scenarios involving:
- External partner data formats (✅ Account → Customer lookup)
- Field aliasing/renaming (✅ "Name" → Product.name, "QuantityOrdered" → Item.quantity)
- Nested data structures (✅ Items array handling)
- Lookups and joins (✅ Customer by name, Product by name)
- Data transformation (✅ External format to internal models)

Generate both the API service and corresponding Row Dict Mapper following these patterns:

**API Service Template** (`api/api_discovery/[service_name].py`) - Keep it concise:
```python
from flask import request
from safrs import jsonapi_rpc
import safrs
from integration.row_dict_maps.OrderB2BMapper import OrderB2BMapper
import logging

app_logger = logging.getLogger("api_logic_server_app")

def add_service(app, api, project_dir, swagger_host: str, PORT: str, method_decorators = []):
    api.expose_object(OrderB2BEndPoint)

class OrderB2BEndPoint(safrs.JABase):
    @classmethod
    @jsonapi_rpc(http_methods=["POST"])
    def OrderB2B(self, *args, **kwargs):  # yaml comment => swagger description
        """ # yaml creates Swagger description
            args :
                data:
                    Account: "Alice"
                    Notes: "Rush order for Q4 promotion"
                    Items :
                    - Name: "Widget"
                      QuantityOrdered: 5
                    - Name: "Gadget"
                      QuantityOrdered: 3
            ---
        
        Creates B2B orders from external partner systems with automatic lookups and business logic.
        Features automatic customer/product lookups by name, unit price copying, 
        amount calculations, customer balance updates, and credit limit validation.
        """
        db = safrs.DB
        session = db.session
        
        try:
            mapper_def = OrderB2BMapper()
            request_dict_data = request.json["meta"]["args"]["data"]
            
            app_logger.info(f"OrderB2B: Processing order for account: {request_dict_data.get('Account')}")
            
            sql_alchemy_row = mapper_def.dict_to_row(row_dict=request_dict_data, session=session)
            
            session.add(sql_alchemy_row)
            session.flush()  # Ensures ID is generated before accessing it
            
            order_id = sql_alchemy_row.id
            customer_name = sql_alchemy_row.customer.name if sql_alchemy_row.customer else "Unknown"
            item_count = len(sql_alchemy_row.ItemList)
            
            return {
                "message": "B2B Order created successfully", 
                "order_id": order_id,
                "customer": customer_name,
                "items_count": item_count
            }
            
        except Exception as e:
            app_logger.error(f"OrderB2B: Error creating order: {str(e)}")
            session.rollback()
            return {"error": "Failed to create B2B order", "details": str(e)}, 400
```

**IMPORTANT**: The project includes a working B2B integration example:
- **API Endpoint**: `OrderB2BEndPoint.OrderB2B` - Creates orders from external partner format
- **Error Handling**: Proper exception handling with session rollback for failed operations
- **Business Logic**: Automatic inheritance of all LogicBank rules (pricing, calculations, validation)
- **Testing**: Comprehensive test suite demonstrating success and error scenarios
- **Documentation**: Professional Swagger docs with YAML examples using real database data

When creating new B2B APIs, follow this proven pattern:
- Use `session.flush()` when you need generated IDs before commit
- Include proper error handling with try/catch and session.rollback()
- Provide meaningful success messages with key information (ID, customer, item count)
- Use YAML format in docstrings for clean Swagger documentation
- Always use actual database data in examples (check with sqlite3 queries)

**AI Anti-Patterns to Avoid**:
- **Don't assume CRUD operations**: If user asks for "create order API", only implement POST/insert (ask if they need GET/PUT/DELETE)
- **Don't add "enterprise" features** unless specifically requested:
  - Detailed logging/monitoring beyond basic debugging
  - Complex response objects with metadata
  - Extensive documentation/comments
  - HTTP status code handling beyond defaults
- **Don't import unused libraries**: Skip `logging`, `jsonify`, etc. unless actually needed
- **Don't over-engineer**: Simple success messages beat complex response objects

**Swagger Examples Must Use Real Data**: 
When creating YAML docstring examples, use actual database data. Check first:
```bash
sqlite3 database/db.sqlite "SELECT name FROM customer LIMIT 3;"
sqlite3 database/db.sqlite "SELECT name FROM product LIMIT 3;"
```

**Getting Sample Data for Tests**:
```bash
# Check actual customer names
sqlite3 database/db.sqlite "SELECT name FROM customer LIMIT 5;"

# Check actual product names  
sqlite3 database/db.sqlite "SELECT name FROM product LIMIT 5;"
```
Never assume data from other databases (like Northwind's "ALFKI") - always use the current project's actual data.

**Row Dict Mapper Template** (`integration/row_dict_maps/[MapperName].py`):
```python
from integration.system.RowDictMapper import RowDictMapper
from database import models

class OrderB2BMapper(RowDictMapper):
    def __init__(self):
        """
        B2B Order API Mapper for external partner integration.
        
        Maps external B2B format to internal Order/Item structure:
        - 'Account' field maps to Customer lookup by name
        - 'Notes' field maps directly to Order notes
        - 'Items' array with 'Name' and 'QuantityOrdered' maps to Item records
        """
        mapper = super(OrderB2BMapper, self).__init__(
            model_class=models.Order,
            alias="Order",
            fields=[
                (models.Order.notes, "Notes"),
                # customer_id will be set via parent lookup
                # amount_total will be calculated by business logic
                # CreatedOn will be set by business logic
            ],
            parent_lookups=[
                (models.Customer, [(models.Customer.name, 'Account')])
            ],
            related=[
                ItemB2BMapper()
            ]
        )
        return mapper

class ItemB2BMapper(RowDictMapper):
    def __init__(self):
        """
        B2B Item Mapper for order line items.
        
        Maps external item format to internal Item structure:
        - 'Name' field maps to Product lookup by name
        - 'QuantityOrdered' maps to Item quantity
        """
        mapper = super(ItemB2BMapper, self).__init__(
            model_class=models.Item,
            alias="Items",
            fields=[
                (models.Item.quantity, "QuantityOrdered"),
                # unit_price will be copied from product by business logic
                # amount will be calculated by business logic (quantity * unit_price)
            ],
            parent_lookups=[
                (models.Product, [(models.Product.name, 'Name')])
            ],
            isParent=False
        )
        return mapper
```

**Key Components for Natural Language Processing**:
- **Field Aliasing**: `(models.Table.field, "ExternalName")`
- **Parent Lookups**: `(models.ParentTable, [(models.ParentTable.lookup_field, 'ExternalKey')])`
- **Related Entities**: Nested RowDictMapper instances for child records
- **Automatic Joins**: System handles foreign key relationships automatically

**Business Logic Integration**: All generated APIs automatically inherit the full LogicBank rule engine through the discovery systems (`logic/logic_discovery/auto_discovery.py` and `api/api_discovery/auto_discovery.py`), ensuring data integrity, calculations, and constraints without additional code. Rules are automatically loaded from `logic/logic_discovery/use_case.py` and APIs from `api/api_discovery/[service_name].py` at startup.

**Testing B2B APIs**: The project includes comprehensive testing infrastructure:
- **REST Client Tests**: `test_requests.http` - Test directly in VS Code with REST Client extension
- **Python Test Suite**: `test_b2b_order_api.py` - Automated testing with requests library
- **Swagger UI**: `http://localhost:5656/api` - Interactive API testing and documentation
- **Sample Requests**: `sample_b2b_request.json` - Copy-paste examples for testing

**Working Example Results**: The OrderB2B API demonstrates:
- ✅ External format mapping (Account → Customer, Name → Product)
- ✅ Automatic lookups with error handling (missing customer/product detection)
- ✅ Business logic inheritance (unit price copying, amount calculations, balance updates)
- ✅ Professional Swagger documentation with YAML examples
- ✅ Complete test coverage (success cases and error scenarios)

### Customize Models - Add Tables, Attributes

To add tables / columns to the database (highly impactful - request permission):

1. Update `database/models.py` with new models/columns
2. Generate and apply Alembic migration (see database/alembic/readme.md):
   ```bash
   cd database
   alembic revision --autogenerate -m "Description of changes"
   ```
3. **CRITICAL - Edit the migration file:**
   - `alembic --autogenerate` detects ALL differences between models.py and database
   - Open the generated file in `database/alembic/versions/`
   - **Remove ALL unwanted changes** (ALTER TABLE on existing tables)
   - **Keep ONLY your intended changes** (e.g., CREATE TABLE for new audit table)
   - Simplify `downgrade()` function to reverse only your changes
4. Apply the edited migration:
   ```bash
   alembic upgrade head
   ```
5. After rebuild, offer the admin.yaml swap: back up `admin.yaml` → `admin.yaml.bak`, copy `admin-merge.yaml` → `admin.yaml`. If user declines, they merge manually.

**General Migration Notes**:
- Stop the server before running migrations to avoid database locking
- When adding new models, follow existing patterns in models.py
- Models should not contain `__bind_key__`
- USER ACTION REQUIRED: Restart server after migrations

See: https://apilogicserver.github.io/Docs/Database-Changes/#use-alembic-to-update-database-schema-from-model

If altering `database/models.py`, be sure to follow the patterns shown in the existing models. Note they do not contain a `__bind_key__`.

### Addressing `Missing Attributes` during logic loading at project startup

First, check for misspelling (logic vs `database/models.py`), and repair.

If there are no obvious misspellings, ask for permission to add attributes; if granted, proceed as above.

### Customize Models - Add Derived attributes

Here is a sample derived attribute, `proper_salary`:

```python

# add derived attribute: https://github.com/thomaxxl/safrs/blob/master/examples/demo_pythonanywhere_com.py
@add_method(models.Employee)
@jsonapi_attr
def __proper_salary__(self):  # type: ignore [no-redef]
    import database.models as models
    import decimal
    if isinstance(self, models.Employee):
        rtn_value = self.Salary
        if rtn_value is None:
          rtn_value = decimal.Decimal('0')
        rtn_value = decimal.Decimal('1.25') * rtn_value
        self._proper_salary = int(rtn_value)
        return self._proper_salary
    else:
        rtn_value = decimal.Decimal('0')
        self._proper_salary = int(rtn_value)
        return self._proper_salary

@add_method(models.Employee)
@__proper_salary__.setter
def _proper_salary(self, value):  # type: ignore [no-redef]
    self._proper_salary = value
    print(f'_proper_salary={self._proper_salary}')
    pass

models.Employee.ProperSalary = __proper_salary__

```

When customizing SQLAlchemy models:

* Don't use direct comparisons with database fields in computed properties
* Convert to Python values first using float(), int(), str()
* Use property() function instead of @jsonapi_attr for computed properties
* Always add error handling for type conversions

### Adding events
LogicBank rules are the preferred approach to logic, but you will sometimes need to add events.  This is done in `logic/declare_logic.py` (important: the function MUST come first):

```python
# Example: Log email activity after SysEmail is committed

def sys_email_after_commit(row: models.SysEmail, old_row: models.SysEmail, logic_row: LogicRow):
    """
    After SysEmail is committed, log 'email sent' 
    unless the customer has opted out
    """
    if not row.customer.email_opt_out:
        logic_row.log(f"📧 Email sent to {row.customer.name} - Subject: {row.subject}")
    else:
        logic_row.log(f"🚫 Email blocked for {row.customer.name} - Customer opted out")

Rule.commit_row_event(on_class=SysEmail, calling=sys_email_after_commit)
```

LogicBank event types include:
- `Rule.commit_row_event()` - fires after transaction commits
- `Rule.after_insert()` - fires after row insert
- `Rule.after_update()` - fires after row update  
- `Rule.after_delete()` - fires after row delete

All events receive `(row, old_row, logic_row)` parameters and should use `logic_row.log()` for logging.

## 📁 Key Directories

- `logic/` - Business rules (declarative)
- `api/` - REST API customization
- `security/` - Authentication/authorization
- `database/` - Data models and schemas
- `ui/admin/` - Admin interface configuration
- `ui/app/` - Alternative Angular admin app

## 💡 Helpful Context

- This uses Flask + SQLAlchemy + SAFRS for JSON:API
- Admin UI is React-based with automatic CRUD generation
- Business logic uses LogicBank (declarative rule engine)
- Everything is auto-generated from database introspection
- Focus on CUSTOMIZATION, not re-creation
- Use CoPilot to assist with logic translation and API generation