Contract conflict decision sheet
Tick exactly one box per conflict. (on record) marks the recommendation
made in the contract analysis that preceded this sheet;
conflicts marked OPEN have no recorded recommendation yet. Conflict numbers are stable identifiers referenced from other documents, so gaps in the sequence are intentional.
Once filled in, this sheet drives the migration commits — every unticked or
double-ticked conflict blocks the work.
1. Step ids (the uses: string)
C01 — Negotiate
-
connector/consumer/negotiate_contract— current engine name stays (on record) -
connector/consumer/negotiate— engine renames
C02 — Transfer
-
connector/consumer/transfer_data— current engine name stays (on record) -
connector/consumer/initiate_transfer— engine renames
C03 — Create shell
-
digital-twin-registry/provider/create_shell_descriptor— current engine name stays (on record) -
digital-twin-registry/register_shell— engine renames
C04 — Get shell (see also C27 — a lookup is semantically a search)
-
digital-twin-registry/provider/get_shell_descriptor— current engine name stays (on record) -
digital-twin-registry/lookup_shell— engine renames
digital-twin-registry/lookup_shell -> digital-twin-registry/consumer/dataplane/lookup_shell
C05 — Create submodel descriptor
-
digital-twin-registry/provider/create_submodel_descriptor— current engine name stays (on record) -
digital-twin-registry/add_submodel— engine renames
C06 — Conditional branching — OPEN
Tests have no way to branch on a condition: no flow/if step (with a flow/condition composer for its condition) exists in the engine.
-
Implement
flow/if(and condition composer) in the engine -
Leave conditional branching out until there is a concrete need
C07 — HTTP step stutter — OPEN
-
Rename to
http/request -
Keep
http/http_request
C08 — Mock module inconsistency — OPEN
mock/wait/http_request carries a module; mock/api, mock/discovery, mock/dtr do not.
-
All four carry a module (e.g.
mock/api/…,mock/registry/dtr, …) -
None carries a module (
mock/wait_http_requestor similar flattening) -
Keep as-is (accept the inconsistency, document it)
2. Parameter names (same value, two spellings)
C10 — negotiate_contract: the asset being negotiated
-
asset_id— engine renamestarget; exportcatalog_target→catalog_asset_id(on record) -
target— current engine spelling stays
C11 — negotiate_contract: policy vs offer id (semantic, not spelling)
-
policy(ODRL document) — engine wins; fed from a catalog output (on record) -
offer_id(string) — engine gains offer-id-based negotiation
C12 — transfer_data: which id starts the transfer
-
negotiation_id— engine wins; the step polls a negotiation (on record) -
agreement_id— engine reworked to accept an agreement id
Resolved 2026-08-11, refactored. transfer_data never issued a
POST /v2/transferprocesses — it polls for an EDR already produced once the
negotiation finalized, keyed by negotiation_id. Its body was: resolve
negotiation_id → transfer_id, then call consumer.get_edr(transfer_id=...)
— exactly what connector/consumer/get_edr does on its own. The duplicate
fetch/error-handling logic is now one function,
used by both steps: get_edr calls it directly; transfer_data resolves
negotiation_id → transfer_id and then delegates to it. GetEdrParams gained
verify for parity with transfer_data, and get_edr's token extraction now
goes through data_address_token() so it picks up the authCode legacy
spelling the same way transfer_data already did.
C13 — pull_data_filtered_by_policy
-
policies— current engine spelling stays (on record) -
expected_policies— engine renames -> use always expected_policies as key in consumer methods that filter by policy
C14 — create_contract_definition id (engine disagrees with itself: takes contract_id, returns contract_def_id)
-
contract_definition_id— both sides change (on record) -
contract_ideverywhere -
contract_def_ideverywhere
C15 — create_submodel_descriptor: the shell path parameter
-
aas_identifier— engine/AAS-spec name stays (on record) -
shell_id— engine renames
C16 — util/validate_path & util/json_path_extract: the value being read
-
input— engine renamessource(ADR-0025) (on record) -
source— current engine spelling stays
C17 — mock/wait/http_request: which endpoint to wait on
-
endpoint_id— current engine name stays (on record) -
mock— engine renames and receives an instance of the mock step with all infos needed to manage it in runtime
C18 — connector/dataplane/http_request: endpoint + token params
-
dataplane_url+edr_token— params take the name of the export that feeds them (on record) -
endpoint+token— current engine spelling stays
C19 — the filter parameter — OPEN (doc and canonical examples disagree)
The contract analysis chose filter_expression; the canonical examples write filters:.
-
filter_expression— migrate the examples -
filters— flip the doc; engine renames the field, alias dies anyway
3. Engine-internal aliases (second spelling dies with the migration)
C20 — counter-party address
-
counter_party_addressstays;provider_urldies (on record) -
provider_urlstays;counter_party_addressdies
C21 — counter-party id
-
counter_party_idstays;bpnldies (on record) -
bpnlstays;counter_party_iddies
C22 — filter operands
-
operand_left/operand_righton input; camelCase remains serialization-only (on record) -
Accept camelCase on input too (keeps the alias — violates the rule)
C23 — contract-definition policy field
-
usage_policy_idstays;contract_policy_iddies (on record) -
contract_policy_idstays;usage_policy_iddies; engine renames
C24 — notification/consumer/send fields
-
dataplane_url,edr_token,contentstay;endpoint_url,auth_token,payloaddie (on record) -
The other spellings win
C25 — validate/schema: the schema parameter
-
schemastays;json_schemadies (on record) -
json_schemastays;schemadies
4. Shape conflicts
C26 — create_asset / create_policy / create_shell_descriptor / create_submodel_descriptor
-
One document parameter (
asset,policy,shell_descriptor,submodel_descriptor); assembling the document is left to the test author (on record) -
Flat fields; engine assembles the document internally
-
Both accepted (dual shape — violates the rule)
- -> We can offer the two options via parameters but like connector/provider/wizard/create_asset for example and connector/provider/create_asset receives directly the json payload
C27 — DTR lookup semantics (get-one vs search)
-
Two steps: keep
get_shell_descriptor(aas_identifier), adddigital-twin-registry/provider/query_shell_descriptors(specific_asset_ids)(on record) -
One step with either parameter (dual shape — violates the rule)
-
Search only; drop get-by-identifier from the catalog
Naming superseded by the C04 note. The search step is not a local-registry
read like get_shell_descriptor — it reaches a counterparty's registry
through an EDC dataplane (dataplane_url + edr_token, same convention as
C18), so it doesn't belong under digital-twin-registry/provider/* (which calls the
locally-seeded AasService directly, no dataplane params at all). Final id
is the one from the C04 note, kept literal as an intentional 4-segment
exception to the category/module/function convention:
digital-twin-registry/consumer/dataplane/lookup_shell, params
specific_asset_ids + dataplane_url + edr_token.
5. Capability conflicts (implement or delete)
C28 — transfer_type (HttpData-PUSH, AmazonS3-PUSH) on transfer — engine is PULL-only
-
Leave out until the engine supports PUSH (on record)
-
Implement PUSH transfer types in the engine now
C29 — asset_selector criteria array on create_contract_definition
-
Implement in the engine (EDC API takes it natively) (on record) -> the asset selector takes an array of filter criteria
-
Leave out; single
asset_idremains the only form
C30 — query_params on http/http_request
-
Implement in the engine (on record)
-
Leave out; query strings go in the URL
C31 — response_headers on mock/api
-
Implement in the engine (on record)
-
Leave out
C32 — validate/semantic_schema (no test uses it, weaker than validate/schema)
-
Delete from the engine (on record)
-
Keep it
6. Output conflicts (dead returns: today)
C33 — negotiate_contract outputs
-
Engine adds
agreement_id+state(polls the negotiation) (on record) -
Neither is added;
negotiation_idis the only output
C34 — transfer_data outputs
-
Engine adds
state, deletesdata_address("older spelling ofdataplane_endpoint") (on record) -
Keep
data_addresstoo (two names for one value — violates the rule) - keep onlt data adress remove dataplane endpoimnt — and add
statetoo (parity with C33's negotiate output)
C35 — query_catalog output shape
-
Engine wraps:
catalog(raw JSON-LD) +datasets—returns:never spellsdcat:dataset(on record) -> ctalog is complete and dataset gets filtered -
Raw document stays the output;
returns:readsdcat:datasetverbatim
C36 — pull_data_filtered missing agreement_id
-
Engine adds it (its by-policy sibling already publishes it) (on record) -> found for retriving the edr
-
Not added
C37 — DTR step outputs
-
id+id_short; theidShortserialization alias dies; theshell_id/shell_descriptor(s)/submodel_idspellings die (on record) -
shell_id/shell_descriptor(s)/submodel_idwin; engine renames
C38 — mock/api output
-
Structured:
endpoint_id,base_url,url— replaces the bare string (on record) -
Bare string stays; read as
value - mock class instance is returned (with all information about the mock), base mock ulr and full mock url are returned with the complete api from the engine (engine url + unique path generated for this mock)
C39 — mock/wait/http_request outputs
-
method,path,headers,body,query_params,elapsed_ms— norequest_prefix, engine adds the last two (on record) -
request_*spellings win; engine renames and adds
C40 — universal extraction fallbacks — OPEN
value, request, response, exports, status_code, headers, body,
duration_ms, response_body, response_headers resolve on every step but are
declared in no output model.
-
Formalize: fold into declared output models so the generated schema is complete
-
Restrict: only declared outputs resolve; fallbacks removed
-
Keep implicit (the generated schema for
returns:stays incomplete) - Always when there is a request and response we should log it, incomming or outcommming, but onl outputs can be used when specified. The request and reponse may be important for debug, but not always going to be used by other steps.
7. Execution contract
C46 — SSE execution contract — OPEN
Execution events carry no explicit kind, so a client has to infer their meaning by string-sniffing (e.g. treating any step_type containing assert as an assertion failure); there is no shared event schema.
-
Typed, versioned event schema; explicit
kindfield on events -
Keep heuristic parsing
- Harmonize this to emmit events in an event manager, and be able to receive in formation from each step when execution or the state machine from their execution changes.
C47 — StepParams extras
-
extra="forbid"— unknownwith:keys become compile-time errors (on record) -> when compiling we need to give errors if the syntax of the step's inputs and outputs is not correct. -
Keep
extra="allow"(unknown keys silently dropped)