@cspeach/cli 0.7.1 → 0.8.0
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.
- package/bench/README.md +78 -0
- package/bench/prompts/abap-document-cds.md +44 -0
- package/bench/prompts/abap-explain-bdef-handler.md +57 -0
- package/bench/prompts/abap-test-method.md +42 -0
- package/bench/results/abap-document-cds/claude-haiku-4-5.md +189 -0
- package/bench/results/abap-document-cds/claude-opus-4-7.md +120 -0
- package/bench/results/abap-document-cds/claude-sonnet-4-6.md +151 -0
- package/bench/results/abap-explain-bdef-handler/claude-haiku-4-5.md +112 -0
- package/bench/results/abap-explain-bdef-handler/claude-opus-4-7.md +101 -0
- package/bench/results/abap-explain-bdef-handler/claude-sonnet-4-6.md +101 -0
- package/bench/results/abap-test-method/claude-haiku-4-5.md +186 -0
- package/bench/results/abap-test-method/claude-opus-4-7.md +193 -0
- package/bench/results/abap-test-method/claude-sonnet-4-6.md +234 -0
- package/dist/agent/loop.js +21 -8
- package/dist/config/loader.js +6 -4
- package/dist/one-shot.js +6 -0
- package/dist/renderer/question-normalizer.js +16 -6
- package/dist/repl.js +21 -4
- package/dist/router/classifier.js +74 -8
- package/dist/tools/subagent/agent_run.js +12 -0
- package/dist/ui/body.js +61 -2
- package/package.json +2 -1
package/bench/README.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Model bench
|
|
2
|
+
|
|
3
|
+
Side-by-side outputs from Opus, Sonnet, and Haiku on the same ABAP prompt so
|
|
4
|
+
you can decide per-skill which model carries the load before changing any
|
|
5
|
+
default.
|
|
6
|
+
|
|
7
|
+
## Run
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm bench:models
|
|
11
|
+
pnpm bench:models --prompt abap-explain-bdef-handler
|
|
12
|
+
pnpm bench:models --models claude-opus-4-7,claude-sonnet-4-6
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Routes through whichever LLM mode `cspeach config` is in — managed (proxy),
|
|
16
|
+
BYOK, AI Hub, or local. In managed mode the proxy injects the **real skill
|
|
17
|
+
body from KV** as the system prompt, so each bench call is end-to-end
|
|
18
|
+
identical to what a real `/abap-explain` invocation would do — just on a
|
|
19
|
+
different model.
|
|
20
|
+
|
|
21
|
+
## Prompts
|
|
22
|
+
|
|
23
|
+
Drop new prompts in `prompts/<name>.md`. Format:
|
|
24
|
+
|
|
25
|
+
```markdown
|
|
26
|
+
---
|
|
27
|
+
skill: abap-explain # required — must be a real CSPeach skill name
|
|
28
|
+
description: short label
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## user
|
|
32
|
+
[the user-side prompt the model receives]
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Optionally include a `## system` section — it's **only** used in non-managed
|
|
36
|
+
modes (BYOK, AI Hub, local) where there's no proxy to inject a skill body.
|
|
37
|
+
In managed mode `## system` is ignored.
|
|
38
|
+
|
|
39
|
+
## Results
|
|
40
|
+
|
|
41
|
+
`results/<prompt-name>/<model>.md` — full assistant text plus latency, tokens,
|
|
42
|
+
and a USD estimate (using the same pricing table the cost footer uses).
|
|
43
|
+
|
|
44
|
+
Read both files side by side. If Sonnet looks like a write-off on a given
|
|
45
|
+
skill, keep the skill on Opus. If it looks "as good or better," that skill
|
|
46
|
+
graduates down on the next config refactor.
|
|
47
|
+
|
|
48
|
+
## Cost note
|
|
49
|
+
|
|
50
|
+
Each prompt × model call is one full skill turn through the proxy. The proxy
|
|
51
|
+
loads the full skill body as system prompt, so input is in the 5-15k token
|
|
52
|
+
range. A full 3-prompt × 3-model bench is roughly $0.30–$0.80 depending on
|
|
53
|
+
output verbosity. (Haiku columns will be much cheaper than Opus.)
|
|
54
|
+
|
|
55
|
+
## Verdict log
|
|
56
|
+
|
|
57
|
+
Findings from each bench run, oldest first. Each entry should name the run
|
|
58
|
+
date, the prompts that were benched, and the model decision per skill — so
|
|
59
|
+
the config refactor (`resolveModelForSkill` + `[models.skills]`) can be
|
|
60
|
+
driven from evidence, not guesses.
|
|
61
|
+
|
|
62
|
+
### 2026-05-18 — initial 3-prompt run
|
|
63
|
+
|
|
64
|
+
Prompts: `abap-explain-bdef-handler`, `abap-document-cds`, `abap-test-method`.
|
|
65
|
+
|
|
66
|
+
| Skill | Sonnet 4.6 | Haiku 4.5 | Decision |
|
|
67
|
+
|---|---|---|---|
|
|
68
|
+
| `abap-explain` | matches Opus, catches `IN LOCAL MODE` non-retrigger nuance | typo `cl_abap_behav_handler` (wrong class name) | **Sonnet OK; Haiku unsafe** |
|
|
69
|
+
| `abap-document` | matches Opus + adds client-handling + `@VDM.viewType` value | invented `DSOD` authority object; misread fuzzinessThreshold direction | **Sonnet OK; Haiku unsafe** |
|
|
70
|
+
| `abap-test` | comparable rigor; asserts exception **textid** (Opus only `assert_bound`) | clean code; coverage-estimate prose shaky | **Sonnet OK; Haiku borderline** |
|
|
71
|
+
|
|
72
|
+
Pattern: SAP/ABAP corpus is thinner than Python/JS — Haiku hallucinates SAP
|
|
73
|
+
terms on multi-paragraph synthesis. Sonnet does not. Do NOT route any
|
|
74
|
+
ABAP-content skill to Haiku based on this evidence.
|
|
75
|
+
|
|
76
|
+
Skills NOT yet benched (kept on Opus by default): `abap-generate`, `-rap`,
|
|
77
|
+
`-modernize`, `-design`, `-refactor`, `-review`, `-cca`, anything else
|
|
78
|
+
producing new code or architectural decisions. Bench before routing.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
skill: abap-document
|
|
3
|
+
description: Document a CDS interface view with associations + currency annotation
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## user
|
|
7
|
+
|
|
8
|
+
Please document this CDS view:
|
|
9
|
+
|
|
10
|
+
```cds
|
|
11
|
+
@AccessControl.authorizationCheck: #CHECK
|
|
12
|
+
@EndUserText.label: 'Sales Order — Interface View'
|
|
13
|
+
@Search.searchable: true
|
|
14
|
+
define view entity ZI_SalesOrder
|
|
15
|
+
as select from zsales_order as Header
|
|
16
|
+
|
|
17
|
+
association [0..1] to ZI_Customer as _Customer on $projection.CustomerID = _Customer.CustomerID
|
|
18
|
+
association [0..*] to ZI_SalesOrderItem as _SalesOrderItem on $projection.SalesOrderID = _SalesOrderItem.SalesOrderID
|
|
19
|
+
association [0..1] to I_Currency as _Currency on $projection.CurrencyCode = _Currency.Currency
|
|
20
|
+
|
|
21
|
+
{
|
|
22
|
+
key Header.sales_order_id as SalesOrderID,
|
|
23
|
+
Header.customer_id as CustomerID,
|
|
24
|
+
Header.order_date as OrderDate,
|
|
25
|
+
|
|
26
|
+
@Search.defaultSearchElement: true
|
|
27
|
+
@Search.fuzzinessThreshold: 0.8
|
|
28
|
+
@ObjectModel.text.element: [ '_Customer.CustomerName' ]
|
|
29
|
+
Header.customer_id as CustomerIDForSearch,
|
|
30
|
+
|
|
31
|
+
@Semantics.amount.currencyCode: 'CurrencyCode'
|
|
32
|
+
Header.net_amount as NetAmount,
|
|
33
|
+
Header.currency_code as CurrencyCode,
|
|
34
|
+
|
|
35
|
+
Header.created_at as CreatedAt,
|
|
36
|
+
Header.created_by as CreatedBy,
|
|
37
|
+
Header.last_changed_at as LastChangedAt,
|
|
38
|
+
Header.last_changed_by as LastChangedBy,
|
|
39
|
+
|
|
40
|
+
_Customer,
|
|
41
|
+
_SalesOrderItem,
|
|
42
|
+
_Currency
|
|
43
|
+
}
|
|
44
|
+
```
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
skill: abap-explain
|
|
3
|
+
description: Explain a managed RAP behavior pool with a validation + determination
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## user
|
|
7
|
+
|
|
8
|
+
Please explain this behavior pool:
|
|
9
|
+
|
|
10
|
+
```abap
|
|
11
|
+
CLASS lhc_salesorder DEFINITION INHERITING FROM cl_abap_behavior_handler.
|
|
12
|
+
PRIVATE SECTION.
|
|
13
|
+
METHODS validateorderdate FOR VALIDATE ON SAVE
|
|
14
|
+
IMPORTING keys FOR SalesOrder~validateorderdate.
|
|
15
|
+
METHODS determinenetamount FOR DETERMINE ON MODIFY
|
|
16
|
+
IMPORTING keys FOR SalesOrder~determinenetamount.
|
|
17
|
+
ENDCLASS.
|
|
18
|
+
|
|
19
|
+
CLASS lhc_salesorder IMPLEMENTATION.
|
|
20
|
+
METHOD validateorderdate.
|
|
21
|
+
READ ENTITIES OF zr_salesorder IN LOCAL MODE
|
|
22
|
+
ENTITY SalesOrder FIELDS ( OrderDate ) WITH CORRESPONDING #( keys )
|
|
23
|
+
RESULT DATA(lt_orders).
|
|
24
|
+
|
|
25
|
+
LOOP AT lt_orders INTO DATA(ls_order).
|
|
26
|
+
IF ls_order-OrderDate < cl_abap_context_info=>get_system_date( ).
|
|
27
|
+
APPEND VALUE #( %tky = ls_order-%tky ) TO failed-salesorder.
|
|
28
|
+
APPEND VALUE #(
|
|
29
|
+
%tky = ls_order-%tky
|
|
30
|
+
%msg = new_message_with_text(
|
|
31
|
+
severity = if_abap_behv_message=>severity-error
|
|
32
|
+
text = 'Order date must be today or in the future' )
|
|
33
|
+
) TO reported-salesorder.
|
|
34
|
+
ENDIF.
|
|
35
|
+
ENDLOOP.
|
|
36
|
+
ENDMETHOD.
|
|
37
|
+
|
|
38
|
+
METHOD determinenetamount.
|
|
39
|
+
READ ENTITIES OF zr_salesorder IN LOCAL MODE
|
|
40
|
+
ENTITY SalesOrder FIELDS ( Quantity UnitPrice ) WITH CORRESPONDING #( keys )
|
|
41
|
+
RESULT DATA(lt_orders).
|
|
42
|
+
|
|
43
|
+
DATA lt_update TYPE TABLE FOR UPDATE zr_salesorder\\SalesOrder.
|
|
44
|
+
LOOP AT lt_orders INTO DATA(ls_order).
|
|
45
|
+
APPEND VALUE #(
|
|
46
|
+
%tky = ls_order-%tky
|
|
47
|
+
NetAmount = ls_order-Quantity * ls_order-UnitPrice
|
|
48
|
+
%control-NetAmount = if_abap_behv=>mk-on
|
|
49
|
+
) TO lt_update.
|
|
50
|
+
ENDLOOP.
|
|
51
|
+
|
|
52
|
+
MODIFY ENTITIES OF zr_salesorder IN LOCAL MODE
|
|
53
|
+
ENTITY SalesOrder UPDATE FIELDS ( NetAmount )
|
|
54
|
+
WITH lt_update.
|
|
55
|
+
ENDMETHOD.
|
|
56
|
+
ENDCLASS.
|
|
57
|
+
```
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
skill: abap-test
|
|
3
|
+
description: Generate an ABAP Unit test class for a small business rule method
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## user
|
|
7
|
+
|
|
8
|
+
Please write an ABAP Unit test class for this method:
|
|
9
|
+
|
|
10
|
+
```abap
|
|
11
|
+
CLASS zcl_discount_calculator DEFINITION
|
|
12
|
+
PUBLIC FINAL CREATE PUBLIC.
|
|
13
|
+
|
|
14
|
+
PUBLIC SECTION.
|
|
15
|
+
"! Returns the discount percentage (0..30) for a given net amount.
|
|
16
|
+
"! < 1000 → 0%
|
|
17
|
+
"! < 5000 → 5%
|
|
18
|
+
"! < 10000 → 10%
|
|
19
|
+
"! >= 10000 → 15%
|
|
20
|
+
"! Raises zcx_discount_error on negative input.
|
|
21
|
+
METHODS calculate_discount
|
|
22
|
+
IMPORTING iv_net_amount TYPE p LENGTH 13 DECIMALS 2
|
|
23
|
+
RETURNING VALUE(rv_discount) TYPE p LENGTH 3 DECIMALS 2
|
|
24
|
+
RAISING zcx_discount_error.
|
|
25
|
+
ENDCLASS.
|
|
26
|
+
|
|
27
|
+
CLASS zcl_discount_calculator IMPLEMENTATION.
|
|
28
|
+
METHOD calculate_discount.
|
|
29
|
+
IF iv_net_amount < 0.
|
|
30
|
+
RAISE EXCEPTION TYPE zcx_discount_error
|
|
31
|
+
EXPORTING textid = zcx_discount_error=>negative_input.
|
|
32
|
+
ENDIF.
|
|
33
|
+
|
|
34
|
+
rv_discount = COND #(
|
|
35
|
+
WHEN iv_net_amount < 1000 THEN '0.00'
|
|
36
|
+
WHEN iv_net_amount < 5000 THEN '5.00'
|
|
37
|
+
WHEN iv_net_amount < 10000 THEN '10.00'
|
|
38
|
+
ELSE '15.00'
|
|
39
|
+
).
|
|
40
|
+
ENDMETHOD.
|
|
41
|
+
ENDCLASS.
|
|
42
|
+
```
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# abap-document-cds — claude-haiku-4-5
|
|
2
|
+
|
|
3
|
+
- **skill:** abap-document
|
|
4
|
+
- **description:** Document a CDS interface view with associations + currency annotation
|
|
5
|
+
- **latency:** 26816 ms
|
|
6
|
+
- **input tokens:** 2,688
|
|
7
|
+
- **output tokens:** 2,623
|
|
8
|
+
- **cost:** $0.0158
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# abap-document — ZI_SalesOrder
|
|
13
|
+
|
|
14
|
+
## TL;DR
|
|
15
|
+
|
|
16
|
+
**Headline:** Interface view for sales order header data with customer and item associations, read-only with authorization check.
|
|
17
|
+
|
|
18
|
+
**Top 3 (priority order):**
|
|
19
|
+
1. **Authorization enforced:** `#CHECK` mode requires `DSOD` and sales order read authority at runtime — verify user roles before consuming downstream.
|
|
20
|
+
2. **Fuzzy search enabled on CustomerID:** `fuzzinessThreshold: 0.8` will match partial/misspelled customer names; test with typical fat-finger errors in UAT.
|
|
21
|
+
3. **No filtering logic:** View exposes all rows from `zsales_order` table — upstream consumers must apply their own `WHERE` clauses; no automatic date range or status filtering.
|
|
22
|
+
|
|
23
|
+
**Verdict:** Safe foundation view for consumption in analytics, APIs, or reporting. Confirm downstream apps implement business rule filtering (e.g., active orders only, date ranges).
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## ZI_SalesOrder (CDS VIEW ENTITY)
|
|
28
|
+
|
|
29
|
+
### Overview
|
|
30
|
+
|
|
31
|
+
**Package:** (not yet read — see below)
|
|
32
|
+
**Type:** CDS View Entity (Interface Layer)
|
|
33
|
+
**Annotations:** Authorization check enabled, search enabled, end-user label "Sales Order — Interface View"
|
|
34
|
+
|
|
35
|
+
**Summary:**
|
|
36
|
+
Exposes sales order header data from the custom table `zsales_order` with associations to customer master, line items, and SAP currency data. Designed as a read-only interface view for analytics, reporting, and API consumption.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
### Purpose
|
|
41
|
+
|
|
42
|
+
This view serves as the **interface layer** for sales order headers in the custom data model. It:
|
|
43
|
+
|
|
44
|
+
1. **Presents domain data cleanly** — maps technical table column names (`sales_order_id`, `customer_id`) to business-readable field names (`SalesOrderID`, `CustomerID`).
|
|
45
|
+
2. **Enforces authorization** — restricts read access to users with appropriate sales order query authority.
|
|
46
|
+
3. **Enables semantic search** — makes customer name searchable via fuzzy matching (0.8 threshold = allow 20% typos).
|
|
47
|
+
4. **Links related business entities** — connects to customer master, line items, and currency metadata via associations (no data duplication, navigation-based joins).
|
|
48
|
+
5. **Supports consumption layers** — designed for downstream consumption by reporting tools, OData APIs, or analytical views.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
### Interface
|
|
53
|
+
|
|
54
|
+
**Key Field:**
|
|
55
|
+
- `SalesOrderID` (Header.sales_order_id) — unique identifier for the sales order
|
|
56
|
+
|
|
57
|
+
**Header-Level Fields:**
|
|
58
|
+
|
|
59
|
+
| Field Name | Source | Type | Purpose |
|
|
60
|
+
|------------|--------|------|---------|
|
|
61
|
+
| SalesOrderID | Header.sales_order_id | key | Sales order unique identifier |
|
|
62
|
+
| CustomerID | Header.customer_id | string | References customer master |
|
|
63
|
+
| OrderDate | Header.order_date | date | Date order was placed |
|
|
64
|
+
| CustomerIDForSearch | Header.customer_id | string | Fuzzy-searchable copy for customer lookup |
|
|
65
|
+
| NetAmount | Header.net_amount | decimal | Order value (currency-aware via annotation) |
|
|
66
|
+
| CurrencyCode | Header.currency_code | string | ISO currency code |
|
|
67
|
+
| CreatedAt | Header.created_at | timestamp | Audit: creation timestamp |
|
|
68
|
+
| CreatedBy | Header.created_by | user | Audit: creator user |
|
|
69
|
+
| LastChangedAt | Header.last_changed_at | timestamp | Audit: last change timestamp |
|
|
70
|
+
| LastChangedBy | Header.last_changed_by | user | Audit: last change user |
|
|
71
|
+
|
|
72
|
+
**Associations (Navigation):**
|
|
73
|
+
|
|
74
|
+
| Association | Target View | Cardinality | Join Condition | Purpose |
|
|
75
|
+
|-------------|-------------|-------------|-----------------|---------|
|
|
76
|
+
| `_Customer` | ZI_Customer | 0..1 | CustomerID | Navigate to customer master data |
|
|
77
|
+
| `_SalesOrderItem` | ZI_SalesOrderItem | 0..* | SalesOrderID | Navigate to line items for this order |
|
|
78
|
+
| `_Currency` | I_Currency (SAP standard) | 0..1 | CurrencyCode | Navigate to SAP currency details |
|
|
79
|
+
|
|
80
|
+
**Authorization & Search:**
|
|
81
|
+
- Authorization check: `#CHECK` — runtime check required (user must have query authority for sales order).
|
|
82
|
+
- Default search element: `CustomerIDForSearch` with fuzzy matching (80% match threshold).
|
|
83
|
+
- Searchable: all marked fields indexed for full-text search.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
### Logic Flow
|
|
88
|
+
|
|
89
|
+
**Data Origin & Transformation:**
|
|
90
|
+
|
|
91
|
+
1. **Source:** Read all rows from custom table `zsales_order` (Header alias).
|
|
92
|
+
2. **Projection:** Map technical columns to semantic field names:
|
|
93
|
+
- `sales_order_id` → `SalesOrderID` (key)
|
|
94
|
+
- `customer_id` → `CustomerID`
|
|
95
|
+
- `order_date` → `OrderDate`
|
|
96
|
+
- `net_amount` → `NetAmount` (with currency semantic)
|
|
97
|
+
- `currency_code` → `CurrencyCode`
|
|
98
|
+
- Audit fields (created/changed by/at) mapped as-is.
|
|
99
|
+
3. **Duplicate CustomerID:** `CustomerIDForSearch` is a copy of `CustomerID` explicitly marked for full-text search (allows UI to search by customer name via the association).
|
|
100
|
+
4. **Associations:** Three navigation paths added (not joins — lazy-loaded):
|
|
101
|
+
- To customer master for customer details.
|
|
102
|
+
- To line items for order composition.
|
|
103
|
+
- To SAP currency master for exchange rates, decimals, etc.
|
|
104
|
+
5. **Authorization Gate:** View enforces `#CHECK` at query time — SAP will validate user authority before returning rows.
|
|
105
|
+
|
|
106
|
+
**No filtering logic:** View is a "raw interface" — all rows from the source table are exposed. Upstream consumers must filter by date, status, or other business rules.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
### Data Access
|
|
111
|
+
|
|
112
|
+
| Table/View | Operation | Purpose |
|
|
113
|
+
|------------|-----------|---------|
|
|
114
|
+
| `zsales_order` (custom) | **READ** | Source table for all header fields (sales_order_id, customer_id, order_date, net_amount, currency_code, audit fields) |
|
|
115
|
+
| `ZI_Customer` (custom view) | **READ** (via association) | Customer master lookup; enriches orders with customer details |
|
|
116
|
+
| `ZI_SalesOrderItem` (custom view) | **READ** (via association) | Line items for the order; enables per-item navigation |
|
|
117
|
+
| `I_Currency` (SAP standard) | **READ** (via association) | SAP currency master; provides conversion rates, decimal places |
|
|
118
|
+
|
|
119
|
+
**No writes:** This is a read-only interface view. No INSERT, UPDATE, or DELETE allowed.
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
### Dependencies
|
|
124
|
+
|
|
125
|
+
**Called by (Upstream Consumers):**
|
|
126
|
+
Unknown without further analysis — use `sap_usage_references` to identify (e.g., analytics views, OData services, reports using this view).
|
|
127
|
+
|
|
128
|
+
**Calls (Dependencies):**
|
|
129
|
+
- `zsales_order` — custom table (no option to change this view without understanding the source table schema).
|
|
130
|
+
- `ZI_Customer` — custom customer interface view (ensure it is available and stable).
|
|
131
|
+
- `ZI_SalesOrderItem` — custom sales order item interface view (ensure it exists).
|
|
132
|
+
- `I_Currency` (SAP standard) — standard SAP currency master (no custom risk; always available post-installation).
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
### Authorization & Security
|
|
137
|
+
|
|
138
|
+
**Authorization Check:** `#CHECK` mode
|
|
139
|
+
- When a user queries this view, SAP **enforces** a dynamic authorization check at runtime.
|
|
140
|
+
- The specific check depends on SAP's authority object mapping for CDS views (typically `DSOD` → Data Source Object Definition or equivalent).
|
|
141
|
+
- **Action required:** Verify that user roles define query access for this view; otherwise, queries will fail with "Authorization error."
|
|
142
|
+
|
|
143
|
+
**Search & Indexing:**
|
|
144
|
+
- `CustomerIDForSearch` with `fuzzinessThreshold: 0.8` allows typo-tolerant search (e.g., "APLE" matches "APPLE").
|
|
145
|
+
- Useful for user-facing search UIs; may return false positives in strict filter scenarios.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
### Data Model & Semantics
|
|
150
|
+
|
|
151
|
+
**Semantic Annotations:**
|
|
152
|
+
- `@Semantics.amount.currencyCode: 'CurrencyCode'` on `NetAmount` — tells consuming systems that this field is a currency amount and which field holds the currency code. Tools like SAP Analytics Cloud will format it correctly.
|
|
153
|
+
- `@ObjectModel.text.element: [ '_Customer.CustomerName' ]` on `CustomerIDForSearch` — tells UI frameworks to display the customer **name** (not ID) when showing this field.
|
|
154
|
+
|
|
155
|
+
**Searchability:**
|
|
156
|
+
- View is marked `@Search.searchable: true` — all fields with `@Search.defaultSearchElement: true` are indexed.
|
|
157
|
+
- Only `CustomerIDForSearch` is explicitly indexed; other fields are not full-text searchable by default.
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
### Notes & Considerations
|
|
162
|
+
|
|
163
|
+
1. **No status filtering:** View exposes all orders regardless of status (open, closed, cancelled). If you need only active orders, add a downstream view or consuming WHERE clause.
|
|
164
|
+
|
|
165
|
+
2. **Audit trail:** `CreatedBy`, `LastChangedBy`, `CreatedAt`, `LastChangedAt` are available for compliance; confirm these are populated in the source table `zsales_order`.
|
|
166
|
+
|
|
167
|
+
3. **Association multiplicity:**
|
|
168
|
+
- Customer is 0..1 (every order may not have a customer — nullable FK?). Verify business rule: must a sales order always have a customer?
|
|
169
|
+
- Line items are 0..* (orders with no items are allowed). Confirm with business if this is intentional.
|
|
170
|
+
- Currency is 0..1 (may not exist in SAP currency master for custom codes). Test with unusual currency codes.
|
|
171
|
+
|
|
172
|
+
4. **Search on CustomerID not CustomerName:** The view exposes `CustomerID` for search but links to `_Customer.CustomerName`. If users expect to search by customer **name**, ensure the downstream OData/UI binding is configured to search on `CustomerIDForSearch` and display `_Customer.CustomerName`.
|
|
173
|
+
|
|
174
|
+
5. **No performance optimizations:** View is a simple 1:1 projection. For large `zsales_order` tables (millions of rows), consider:
|
|
175
|
+
- Adding a semantic partitioning hint in the view definition.
|
|
176
|
+
- Creating secondary indexes on frequently filtered columns (e.g., `OrderDate`, `CustomerID`).
|
|
177
|
+
- Testing query response times with large datasets.
|
|
178
|
+
|
|
179
|
+
6. **Missing fields?** Confirm with business that all required order header fields are in the projection. If fields exist in `zsales_order` but not exposed here, add them or create a second view variant.
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Next Steps
|
|
184
|
+
|
|
185
|
+
1. **Trace consumers:** Run `sap_usage_references` to identify which views, APIs, and reports consume this view.
|
|
186
|
+
2. **Verify source table:** Run `sap_get_source` on `zsales_order` to confirm the schema matches the projection.
|
|
187
|
+
3. **Check related views:** Retrieve `ZI_Customer` and `ZI_SalesOrderItem` to ensure the associations are compatible (key cardinality, join conditions).
|
|
188
|
+
4. **Authorization testing:** Create a test user with appropriate authority and verify they can query this view without "Authorization failed" errors.
|
|
189
|
+
5. **Search testing:** Test fuzzy search with intentional typos (e.g., customer name "ACME Corp" vs. search "ACME Crp") to confirm the 0.8 threshold behavior.
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# abap-document-cds — claude-opus-4-7
|
|
2
|
+
|
|
3
|
+
- **skill:** abap-document
|
|
4
|
+
- **description:** Document a CDS interface view with associations + currency annotation
|
|
5
|
+
- **latency:** 42479 ms
|
|
6
|
+
- **input tokens:** 6
|
|
7
|
+
- **output tokens:** 2,798
|
|
8
|
+
- **cost:** $0.2099
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## abap-document — ZI_SalesOrder (CDS Interface View)
|
|
13
|
+
|
|
14
|
+
## TL;DR
|
|
15
|
+
|
|
16
|
+
**Headline:** `ZI_SalesOrder` is a sales order header interface view exposing `zsales_order` with associations to customer, items, and currency, search-enabled on customer ID.
|
|
17
|
+
|
|
18
|
+
**Top 3 (priority order — most important first):**
|
|
19
|
+
1. **Interface view in a VDM-style layering** — naming prefix `ZI_` and associations to `ZI_Customer` / `ZI_SalesOrderItem` indicate this is the I-layer; consumption should happen via a `ZC_` view, not directly.
|
|
20
|
+
2. **Search + text association configured on `CustomerIDForSearch`** — fuzzy search (threshold 0.8) with text resolved via `_Customer.CustomerName`; this field is a duplicate exposure of `customer_id` purely for search semantics.
|
|
21
|
+
3. **Amount/currency reference pair (`NetAmount` ↔ `CurrencyCode`)** is correctly annotated; `_Currency` association to `I_Currency` makes this view S/4-VDM-compliant for currency handling.
|
|
22
|
+
|
|
23
|
+
**Verdict:** Clean, well-annotated interface view. No code-level concerns — main thing to confirm with the team is whether a consumption view (`ZC_SalesOrder`) exists on top and whether `CustomerIDForSearch` duplication is intentional.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
> ⚠️ **Note:** This documentation is based solely on the source you pasted. I did not call `sap_get_source`, `sap_object_structure`, or `sap_usage_references`, so package, author, change history, and where-used data are not included. If you want the full document with dependencies and metadata, re-run and I'll pull it from the system.
|
|
28
|
+
|
|
29
|
+
## ZI_SalesOrder (DDLS — CDS View Entity)
|
|
30
|
+
|
|
31
|
+
### Overview
|
|
32
|
+
Package: *not retrieved* | Author: *not retrieved* | Last changed: *not retrieved*
|
|
33
|
+
|
|
34
|
+
`ZI_SalesOrder` is an **interface-layer CDS view entity** over the custom sales order header table `zsales_order`. It exposes header fields, exposes associations to customer, items, and currency, and enables fuzzy search on the customer ID with the customer name surfaced as text.
|
|
35
|
+
|
|
36
|
+
### Purpose
|
|
37
|
+
Provide a reusable, semantically annotated interface for sales order header data following VDM (Virtual Data Model) conventions:
|
|
38
|
+
|
|
39
|
+
- Acts as the **single source of truth for the sales order header** in the I-layer.
|
|
40
|
+
- Wires up the **associations** that downstream consumption views, Fiori elements apps, and analytical views can navigate (customer, items, currency).
|
|
41
|
+
- Enables **enterprise search** over the order's customer with name resolution.
|
|
42
|
+
- Establishes **currency semantics** so amounts render correctly in UIs and analytics.
|
|
43
|
+
|
|
44
|
+
It does **not** implement business logic, filtering, or authorization beyond `#CHECK` (DCL-based row-level auth, if a DCL exists for this entity).
|
|
45
|
+
|
|
46
|
+
### Interface
|
|
47
|
+
|
|
48
|
+
**Type:** `define view entity` (modern CDS, not legacy `define view`)
|
|
49
|
+
|
|
50
|
+
**Source:** `zsales_order` (aliased as `Header`)
|
|
51
|
+
|
|
52
|
+
**Key:**
|
|
53
|
+
| Field | Type source | Notes |
|
|
54
|
+
|---|---|---|
|
|
55
|
+
| `SalesOrderID` | `Header.sales_order_id` | Primary key |
|
|
56
|
+
|
|
57
|
+
**Exposed fields:**
|
|
58
|
+
| Element | Source | Semantics / Annotations |
|
|
59
|
+
|---|---|---|
|
|
60
|
+
| `SalesOrderID` (key) | `sales_order_id` | — |
|
|
61
|
+
| `CustomerID` | `customer_id` | — |
|
|
62
|
+
| `OrderDate` | `order_date` | — |
|
|
63
|
+
| `CustomerIDForSearch` | `customer_id` | `@Search.defaultSearchElement: true`, fuzziness 0.8, text from `_Customer.CustomerName` |
|
|
64
|
+
| `NetAmount` | `net_amount` | `@Semantics.amount.currencyCode: 'CurrencyCode'` |
|
|
65
|
+
| `CurrencyCode` | `currency_code` | Currency reference field |
|
|
66
|
+
| `CreatedAt` | `created_at` | Admin field |
|
|
67
|
+
| `CreatedBy` | `created_by` | Admin field |
|
|
68
|
+
| `LastChangedAt` | `last_changed_at` | Admin field |
|
|
69
|
+
| `LastChangedBy` | `last_changed_by` | Admin field |
|
|
70
|
+
|
|
71
|
+
**Associations (exposed):**
|
|
72
|
+
| Name | Cardinality | Target | Join condition |
|
|
73
|
+
|---|---|---|---|
|
|
74
|
+
| `_Customer` | `[0..1]` | `ZI_Customer` | `CustomerID = _Customer.CustomerID` |
|
|
75
|
+
| `_SalesOrderItem` | `[0..*]` | `ZI_SalesOrderItem` | `SalesOrderID = _SalesOrderItem.SalesOrderID` |
|
|
76
|
+
| `_Currency` | `[0..1]` | `I_Currency` (SAP standard) | `CurrencyCode = _Currency.Currency` |
|
|
77
|
+
|
|
78
|
+
**View-level annotations:**
|
|
79
|
+
- `@AccessControl.authorizationCheck: #CHECK` — DCL authorization is checked at runtime if a DCL is defined; otherwise warnings issued.
|
|
80
|
+
- `@EndUserText.label: 'Sales Order — Interface View'`
|
|
81
|
+
- `@Search.searchable: true` — view participates in enterprise search.
|
|
82
|
+
|
|
83
|
+
### Logic Flow
|
|
84
|
+
|
|
85
|
+
There is no procedural logic — this is a projection view. At runtime:
|
|
86
|
+
|
|
87
|
+
1. **Select** header rows from `zsales_order`.
|
|
88
|
+
2. **Apply DCL** (`#CHECK`) if a corresponding DCL role exists on `ZI_SalesOrder`.
|
|
89
|
+
3. **Expose** the renamed fields and forward the three associations to consumers.
|
|
90
|
+
4. On association navigation, the database joins to `ZI_Customer`, `ZI_SalesOrderItem`, or `I_Currency` as needed.
|
|
91
|
+
5. For search queries, `CustomerIDForSearch` is the entry point; the engine performs fuzzy matching (threshold 0.8) and shows `_Customer.CustomerName` as descriptive text.
|
|
92
|
+
|
|
93
|
+
### Data Access
|
|
94
|
+
| Table/View | Operation | Purpose |
|
|
95
|
+
|---|---|---|
|
|
96
|
+
| `zsales_order` | READ | Source table — header data |
|
|
97
|
+
| `ZI_Customer` (via `_Customer`) | READ on navigation | Customer master for text and details |
|
|
98
|
+
| `ZI_SalesOrderItem` (via `_SalesOrderItem`) | READ on navigation | Child items |
|
|
99
|
+
| `I_Currency` (via `_Currency`) | READ on navigation | Standard currency master (TCURC) |
|
|
100
|
+
|
|
101
|
+
### Dependencies
|
|
102
|
+
|
|
103
|
+
*Where-used not retrieved — re-run with system access to populate.*
|
|
104
|
+
|
|
105
|
+
**Calls (compile-time dependencies):**
|
|
106
|
+
- Source table: `zsales_order`
|
|
107
|
+
- Associated views: `ZI_Customer`, `ZI_SalesOrderItem`, `I_Currency`
|
|
108
|
+
|
|
109
|
+
**Called by:** *unknown — typically a `ZC_SalesOrder` consumption view, OData service bindings, or analytical views; confirm via `sap_usage_references`.*
|
|
110
|
+
|
|
111
|
+
### Error Handling
|
|
112
|
+
None at view level. Authorization failures via DCL would result in rows being filtered out, not exceptions. If `zsales_order` or any associated view is inactive or missing, the view itself will not activate.
|
|
113
|
+
|
|
114
|
+
### Notes / Observations
|
|
115
|
+
- **`CustomerIDForSearch` duplicates `CustomerID`** — this is a common pattern to keep `CustomerID` "clean" (no search annotations) while a separate element carries the search semantics. Confirm this is intentional and not legacy.
|
|
116
|
+
- **`@AccessControl.authorizationCheck: #CHECK`** requires a DCL role (`define role` on `ZI_SalesOrder`) to actually enforce anything. Verify a DCL exists; otherwise this is effectively `#NOT_REQUIRED` with an activation warning.
|
|
117
|
+
- **VDM naming** (`ZI_` prefix) suggests this is part of a layered model. Best practice: do not consume this view directly from UIs — build a `ZC_SalesOrder` on top.
|
|
118
|
+
- **`I_Currency`** is the SAP-standard currency interface view; the association is correctly modeled for S/4HANA-style currency reference.
|
|
119
|
+
- **No `@Metadata.allowExtensions` annotation** — if extension is expected (CDS view extensions for customer fields), add `@Metadata.allowExtensions: true`.
|
|
120
|
+
- **Purpose of `CustomerIDForSearch`** is clear from annotations, but the broader business process (order-to-cash? B2B sales?) **is not derivable from the source** — confirm with the business team.
|