Pipeline controller: plan 2 (hard +, error +50 %), backlog throttle, 2 trajectory workers, stop rules, summaries every 50; budget reserve

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Kral
2026-10-05 13:35:54 +02:00
parent 1c4667a0fc
commit 13360292dd
781 changed files with 50211 additions and 22 deletions

View File

@@ -0,0 +1,35 @@
{
"id": "G1016",
"pool": "train",
"object_type": "CLAS",
"category": "D",
"attempts": [
{
"stage": "bundle",
"errors": [
"reference/return_checker.testclasses.abap: name damaged_without_code_is_rejected has 32 characters (ABAP max 30)",
"seed/vehicle.tabl.abap: a table needs the annotation @AbapCatalog.tableCategory (for example #TRANSPARENT, #A)",
"seed/vehicle.tabl.abap: a table needs the annotation @AbapCatalog.deliveryClass (for example #TRANSPARENT, #A)"
],
"by_check": {
"static": 3
}
},
{
"stage": "validate",
"oracle": null,
"null": null
},
{
"stage": "validate",
"oracle": null,
"null": null
},
{
"stage": "validate",
"oracle": 0,
"null": 0
}
],
"accepted": false
}

View File

@@ -0,0 +1,143 @@
CLASS {{p}}t02_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
TYPES ty_reason TYPE c LENGTH 10.
DATA mo_cut TYPE REF TO {{p}}return_checker.
DATA mo_env TYPE REF TO if_osql_test_environment.
METHODS setup.
METHODS teardown.
METHODS valid_return
RETURNING VALUE(rs_return) TYPE {{p}}return_checker=>ty_return_data.
METHODS expect_reason
IMPORTING is_data TYPE {{p}}return_checker=>ty_return_data
iv_reason TYPE ty_reason.
METHODS ok_return FOR TESTING.
METHODS rejects_no_data FOR TESTING.
METHODS rejects_empty_date FOR TESTING.
METHODS rejects_date_order FOR TESTING.
METHODS rejects_mileage FOR TESTING.
METHODS rejects_fuel FOR TESTING.
METHODS rejects_damage FOR TESTING.
METHODS rejects_unknown FOR TESTING.
METHODS rejects_too_long FOR TESTING.
METHODS accepts_max_duration FOR TESTING.
METHODS checks_data_before_master FOR TESTING.
ENDCLASS.
CLASS {{p}}t02_hidden IMPLEMENTATION.
METHOD setup.
mo_env = cl_osql_test_environment=>create( VALUE #( ( '{{P}}VEHICLE' ) ) ).
DATA lt_vehicle TYPE STANDARD TABLE OF {{p}}vehicle WITH EMPTY KEY.
lt_vehicle = VALUE #( ( mandt = sy-mandt
vehicle_id = 'V-1001'
max_days = 5 )
( mandt = sy-mandt
vehicle_id = 'V-1002'
max_days = 30 ) ).
mo_env->insert_test_data( lt_vehicle ).
mo_cut = NEW {{p}}return_checker( ).
ENDMETHOD.
METHOD teardown.
mo_env->destroy( ).
ENDMETHOD.
METHOD valid_return.
rs_return = VALUE #( rental_id = 'R-4711'
vehicle_id = 'V-1001'
start_date = '20240101'
return_date = '20240103'
start_mileage = 10000
end_mileage = 10250
fuel_percent = 80
damage_code = ''
is_damaged = abap_false ).
ENDMETHOD.
METHOD expect_reason.
TRY.
mo_cut->check( is_data ).
cl_abap_unit_assert=>fail( msg = |no exception, expected { iv_reason }| ).
CATCH {{p}}cx_return_error INTO DATA(lo_error).
cl_abap_unit_assert=>assert_equals( exp = iv_reason act = lo_error->mv_reason ).
ENDTRY.
ENDMETHOD.
METHOD ok_return.
TRY.
mo_cut->check( valid_return( ) ).
CATCH {{p}}cx_return_error INTO DATA(lo_error).
cl_abap_unit_assert=>fail( msg = |unexpected reason { lo_error->mv_reason }| ).
ENDTRY.
ENDMETHOD.
METHOD rejects_no_data.
DATA(ls_return) = valid_return( ).
CLEAR ls_return-rental_id.
expect_reason( is_data = ls_return iv_reason = 'NO_DATA' ).
ENDMETHOD.
METHOD rejects_empty_date.
DATA(ls_return) = valid_return( ).
CLEAR ls_return-start_date.
expect_reason( is_data = ls_return iv_reason = 'NO_DATA' ).
ENDMETHOD.
METHOD rejects_date_order.
DATA(ls_return) = valid_return( ).
ls_return-return_date = '20231231'.
expect_reason( is_data = ls_return iv_reason = 'DATE_ORDER' ).
ENDMETHOD.
METHOD rejects_mileage.
DATA(ls_return) = valid_return( ).
ls_return-end_mileage = ls_return-start_mileage - 1.
expect_reason( is_data = ls_return iv_reason = 'MILEAGE' ).
ENDMETHOD.
METHOD rejects_fuel.
DATA(ls_return) = valid_return( ).
ls_return-fuel_percent = 101.
expect_reason( is_data = ls_return iv_reason = 'FUEL' ).
ENDMETHOD.
METHOD rejects_damage.
DATA(ls_return) = valid_return( ).
ls_return-is_damaged = abap_true.
CLEAR ls_return-damage_code.
expect_reason( is_data = ls_return iv_reason = 'DAMAGE' ).
ENDMETHOD.
METHOD rejects_unknown.
DATA(ls_return) = valid_return( ).
ls_return-vehicle_id = 'V-9999'.
expect_reason( is_data = ls_return iv_reason = 'UNKNOWN' ).
ENDMETHOD.
METHOD rejects_too_long.
DATA(ls_return) = valid_return( ).
ls_return-return_date = '20240110'.
expect_reason( is_data = ls_return iv_reason = 'TOO_LONG' ).
ENDMETHOD.
METHOD accepts_max_duration.
DATA(ls_return) = valid_return( ).
ls_return-return_date = '20240105'.
TRY.
mo_cut->check( ls_return ).
CATCH {{p}}cx_return_error INTO DATA(lo_error).
cl_abap_unit_assert=>fail( msg = |unexpected reason { lo_error->mv_reason }| ).
ENDTRY.
ENDMETHOD.
METHOD checks_data_before_master.
DATA(ls_return) = valid_return( ).
ls_return-vehicle_id = 'V-9999'.
ls_return-fuel_percent = 150.
expect_reason( is_data = ls_return iv_reason = 'FUEL' ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,28 @@
CLASS {{p}}cx_return_error DEFINITION PUBLIC INHERITING FROM cx_static_check FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_reason TYPE c LENGTH 10.
CONSTANTS:
BEGIN OF c_reason,
no_data TYPE ty_reason VALUE 'NO_DATA',
date_order TYPE ty_reason VALUE 'DATE_ORDER',
mileage TYPE ty_reason VALUE 'MILEAGE',
fuel TYPE ty_reason VALUE 'FUEL',
damage TYPE ty_reason VALUE 'DAMAGE',
unknown TYPE ty_reason VALUE 'UNKNOWN',
too_long TYPE ty_reason VALUE 'TOO_LONG',
END OF c_reason.
DATA mv_reason TYPE ty_reason READ-ONLY.
METHODS constructor
IMPORTING iv_reason TYPE ty_reason.
ENDCLASS.
CLASS {{p}}cx_return_error IMPLEMENTATION.
METHOD constructor.
super->constructor( ).
mv_reason = iv_reason.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,86 @@
CLASS {{p}}return_checker DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES:
BEGIN OF ty_return_data,
rental_id TYPE string,
vehicle_id TYPE string,
start_date TYPE d,
return_date TYPE d,
start_mileage TYPE i,
end_mileage TYPE i,
fuel_percent TYPE i,
damage_code TYPE string,
is_damaged TYPE abap_bool,
END OF ty_return_data.
METHODS constructor.
METHODS check
IMPORTING is_return_data TYPE ty_return_data
RAISING {{p}}cx_return_error.
PRIVATE SECTION.
METHODS has_missing_data
IMPORTING is_return_data TYPE ty_return_data
RETURNING VALUE(rv_missing) TYPE abap_bool.
METHODS duration_in_days
IMPORTING is_return_data TYPE ty_return_data
RETURNING VALUE(rv_days) TYPE i.
ENDCLASS.
CLASS {{p}}return_checker IMPLEMENTATION.
METHOD constructor.
ENDMETHOD.
METHOD check.
IF has_missing_data( is_return_data ) = abap_true.
RAISE EXCEPTION TYPE {{p}}cx_return_error
EXPORTING iv_reason = {{p}}cx_return_error=>c_reason-no_data.
ENDIF.
IF is_return_data-return_date < is_return_data-start_date.
RAISE EXCEPTION TYPE {{p}}cx_return_error
EXPORTING iv_reason = {{p}}cx_return_error=>c_reason-date_order.
ENDIF.
IF is_return_data-end_mileage < is_return_data-start_mileage.
RAISE EXCEPTION TYPE {{p}}cx_return_error
EXPORTING iv_reason = {{p}}cx_return_error=>c_reason-mileage.
ENDIF.
IF is_return_data-fuel_percent < 0 OR is_return_data-fuel_percent > 100.
RAISE EXCEPTION TYPE {{p}}cx_return_error
EXPORTING iv_reason = {{p}}cx_return_error=>c_reason-fuel.
ENDIF.
IF is_return_data-is_damaged = abap_true AND is_return_data-damage_code IS INITIAL.
RAISE EXCEPTION TYPE {{p}}cx_return_error
EXPORTING iv_reason = {{p}}cx_return_error=>c_reason-damage.
ENDIF.
DATA lv_max_days TYPE i.
SELECT SINGLE max_days FROM {{p}}vehicle
WHERE vehicle_id = @is_return_data-vehicle_id
INTO @lv_max_days.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE {{p}}cx_return_error
EXPORTING iv_reason = {{p}}cx_return_error=>c_reason-unknown.
ENDIF.
IF duration_in_days( is_return_data ) > lv_max_days.
RAISE EXCEPTION TYPE {{p}}cx_return_error
EXPORTING iv_reason = {{p}}cx_return_error=>c_reason-too_long.
ENDIF.
ENDMETHOD.
METHOD has_missing_data.
rv_missing = xsdbool( is_return_data-rental_id IS INITIAL
OR is_return_data-vehicle_id IS INITIAL
OR is_return_data-start_date IS INITIAL
OR is_return_data-return_date IS INITIAL ).
ENDMETHOD.
METHOD duration_in_days.
rv_days = is_return_data-return_date - is_return_data-start_date + 1.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,99 @@
CLASS ltc_return_checker DEFINITION FINAL FOR TESTING
DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO {{p}}return_checker.
DATA mo_env TYPE REF TO if_osql_test_environment.
METHODS setup.
METHODS teardown.
METHODS test_return
RETURNING VALUE(rs_return) TYPE {{p}}return_checker=>ty_return_data.
METHODS valid_return_is_accepted FOR TESTING.
METHODS missing_rental_id_is_rejected FOR TESTING.
METHODS unknown_vehicle_is_rejected FOR TESTING.
METHODS too_long_rental_is_rejected FOR TESTING.
METHODS damage_without_code_fails FOR TESTING.
ENDCLASS.
CLASS ltc_return_checker IMPLEMENTATION.
METHOD setup.
mo_env = cl_osql_test_environment=>create( VALUE #( ( '{{P}}VEHICLE' ) ) ).
DATA lt_vehicle TYPE STANDARD TABLE OF {{p}}vehicle WITH EMPTY KEY.
lt_vehicle = VALUE #( ( mandt = sy-mandt
vehicle_id = 'V-1001'
max_days = 5 ) ).
mo_env->insert_test_data( lt_vehicle ).
mo_cut = NEW {{p}}return_checker( ).
ENDMETHOD.
METHOD teardown.
mo_env->destroy( ).
ENDMETHOD.
METHOD test_return.
rs_return = VALUE #( rental_id = 'R-4711'
vehicle_id = 'V-1001'
start_date = '20240101'
return_date = '20240103'
start_mileage = 10000
end_mileage = 10250
fuel_percent = 80
damage_code = ''
is_damaged = abap_false ).
ENDMETHOD.
METHOD valid_return_is_accepted.
TRY.
mo_cut->check( test_return( ) ).
CATCH {{p}}cx_return_error INTO DATA(lo_error).
cl_abap_unit_assert=>fail( msg = |unexpected reason { lo_error->mv_reason }| ).
ENDTRY.
ENDMETHOD.
METHOD missing_rental_id_is_rejected.
DATA(ls_return) = test_return( ).
CLEAR ls_return-rental_id.
TRY.
mo_cut->check( ls_return ).
cl_abap_unit_assert=>fail( msg = 'NO_DATA expected' ).
CATCH {{p}}cx_return_error INTO DATA(lo_error).
cl_abap_unit_assert=>assert_equals( exp = 'NO_DATA' act = lo_error->mv_reason ).
ENDTRY.
ENDMETHOD.
METHOD unknown_vehicle_is_rejected.
DATA(ls_return) = test_return( ).
ls_return-vehicle_id = 'V-9999'.
TRY.
mo_cut->check( ls_return ).
cl_abap_unit_assert=>fail( msg = 'UNKNOWN expected' ).
CATCH {{p}}cx_return_error INTO DATA(lo_error).
cl_abap_unit_assert=>assert_equals( exp = 'UNKNOWN' act = lo_error->mv_reason ).
ENDTRY.
ENDMETHOD.
METHOD too_long_rental_is_rejected.
DATA(ls_return) = test_return( ).
ls_return-return_date = '20240120'.
TRY.
mo_cut->check( ls_return ).
cl_abap_unit_assert=>fail( msg = 'TOO_LONG expected' ).
CATCH {{p}}cx_return_error INTO DATA(lo_error).
cl_abap_unit_assert=>assert_equals( exp = 'TOO_LONG' act = lo_error->mv_reason ).
ENDTRY.
ENDMETHOD.
METHOD damage_without_code_fails.
DATA(ls_return) = test_return( ).
ls_return-is_damaged = abap_true.
CLEAR ls_return-damage_code.
TRY.
mo_cut->check( ls_return ).
cl_abap_unit_assert=>fail( msg = 'DAMAGE expected' ).
CATCH {{p}}cx_return_error INTO DATA(lo_error).
cl_abap_unit_assert=>assert_equals( exp = 'DAMAGE' act = lo_error->mv_reason ).
ENDTRY.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,16 @@
CLASS {{p}}seed_vehicle DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
ENDCLASS.
CLASS {{p}}seed_vehicle IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DELETE FROM {{p}}vehicle.
INSERT {{p}}vehicle FROM TABLE @( VALUE #(
( mandt = sy-mandt vehicle_id = 'V-1001' max_days = 5 )
( mandt = sy-mandt vehicle_id = 'V-1002' max_days = 30 )
( mandt = sy-mandt vehicle_id = 'V-1003' max_days = 3 ) ) ).
out->write( |Rows: { sy-dbcnt }| ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,10 @@
@EndUserText.label : 'Vehicle master data'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}vehicle {
key mandt : abap.clnt not null;
key vehicle_id : abap.char(10) not null;
max_days : abap.int4;
}

View File

@@ -0,0 +1,72 @@
# 1. Goal
A car rental company checks the return of a rental car. The return desk calls
the check before it closes the rental contract. The check reports the first
problem that it finds.
# 2. Open questions
None.
# 3. Context
- The table {{P}}VEHICLE is in package $TMP. It is active. The table contains
the master data of the rental vehicles:
- MANDT: client, key.
- VEHICLE_ID: CHAR 10, key. The identifier of the vehicle.
- MAX_DAYS: INT4. The maximum number of rental days for this vehicle.
- The seed class {{P}}SEED_VEHICLE fills the table with example data.
# 4. Contract
- Create the exception class {{P}}CX_RETURN_ERROR in package $TMP.
- The class inherits from CX_STATIC_CHECK.
- The class has the public attribute MV_REASON. MV_REASON has a character
type with length 10.
- MV_REASON has one of these values: NO_DATA, DATE_ORDER, MILEAGE, FUEL,
DAMAGE, UNKNOWN, TOO_LONG.
- Do not add other public methods.
- Create the class {{P}}RETURN_CHECKER in package $TMP.
- The class is public and final. It has a public constructor without
parameters.
- The class has this public type:
TYPES:
BEGIN OF ty_return_data,
rental_id TYPE string,
vehicle_id TYPE string,
start_date TYPE d,
return_date TYPE d,
start_mileage TYPE i,
end_mileage TYPE i,
fuel_percent TYPE i,
damage_code TYPE string,
is_damaged TYPE abap_bool,
END OF ty_return_data.
- The class has this public method:
METHODS check
IMPORTING is_return_data TYPE ty_return_data
RAISING {{P}}CX_RETURN_ERROR.
- Do not add other public methods.
# 5. Business rules
Check the return data. Apply the rules in this sequence. The check reports the
reason of the first rule that fails. If no rule fails, the check does not raise
an exception.
1. NO_DATA: RENTAL_ID or VEHICLE_ID is empty, or START_DATE or RETURN_DATE is
initial.
2. DATE_ORDER: RETURN_DATE is before START_DATE.
3. MILEAGE: END_MILEAGE is smaller than START_MILEAGE.
4. FUEL: FUEL_PERCENT is smaller than 0 or larger than 100.
5. DAMAGE: IS_DAMAGED is 'X' and DAMAGE_CODE is empty.
6. UNKNOWN: VEHICLE_ID is not in the table {{P}}VEHICLE.
7. TOO_LONG: the rental duration is larger than MAX_DAYS of the vehicle.
The rental duration is the number of calendar days from START_DATE to
RETURN_DATE. Both days are included. Example: start date 2024-01-01 and return
date 2024-01-03 give a duration of 3 days.
# 6. Constraints
- Release target: SAP_BASIS 816.
- Coding standards: Clean ABAP. Method length below 40 statements. No global
variables. No comment that restates the code.
- Out of scope: do not change {{P}}VEHICLE and {{P}}SEED_VEHICLE.
# 7. Acceptance
- The classes are active and have no syntax error.
- The hidden tests pass.
- Write your own ABAP Unit tests for {{P}}RETURN_CHECKER.

View File

@@ -0,0 +1,68 @@
{
"id": "G1016",
"category": "D",
"object_type": "CLAS",
"difficulty": 2,
"release_target": "v816",
"expected_outcome": "implement",
"budget": {
"max_tool_calls": 60,
"max_activations": 15
},
"seed": [
{
"type": "TABL",
"name": "{{P}}VEHICLE",
"file": "seed/vehicle.tabl.abap",
"description": "Vehicle master data with the maximum rental days"
},
{
"type": "CLAS",
"name": "{{P}}SEED_VEHICLE",
"file": "seed/seed_vehicle.clas.abap",
"description": "Fills {{P}}VEHICLE with example data",
"run": true
}
],
"contract": [
{
"type": "CLAS",
"name": "{{P}}CX_RETURN_ERROR"
},
{
"type": "CLAS",
"name": "{{P}}RETURN_CHECKER"
}
],
"out_of_scope": [
"{{P}}VEHICLE",
"{{P}}SEED_VEHICLE"
],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}T02_HIDDEN",
"file": "hidden/t02_hidden.clas.abap",
"description": "Hidden tests for the rental return check"
}
],
"reference": [
{
"type": "CLAS",
"name": "{{P}}CX_RETURN_ERROR",
"file": "reference/cx_return_error.clas.abap",
"description": "Exception for a rejected rental return"
},
{
"type": "CLAS",
"name": "{{P}}RETURN_CHECKER",
"file": "reference/return_checker.clas.abap",
"description": "Checks the return of a rental car",
"testclasses_file": "reference/return_checker.testclasses.abap"
}
],
"craft_checks": [
"method_length",
"db_operation_in_loop"
]
}