Covenants
Purpose of Covenants
Covenants in the Timvero platform are used to automatically monitor the state of a loan after it has been issued. They allow business rules to be formalized, defining acceptable behavior for the borrower or other related parties, and enable regular automated checks without human intervention.
Examples of business requirements implemented through covenants:
The borrower’s income must not fall below the level it was at the time of loan issuance.
The outstanding debt must not exceed a certain percentage of the income.
The collateral must maintain a value above a specified threshold.
Regular and Anchored Metrics
To evaluate covenant conditions, the Timvero platform uses metrics — calculated indicators associated with subjects (such as a loan participant, collateral, etc.).
There are two types of metrics:
Regular Metrics
These are current values, calculated based on the data available at the time the covenant is executed.
Examples: totalIncome, disposableIncome, ltvRatio.
Anchored Metrics
These are fixed (anchored) values, captured at the moment the covenant becomes active (e.g., when the loan is issued).
They serve as a reference point to assess changes over time.
Example: If the borrower’s totalIncome was $5,000 at the time of loan issuance, this value is stored as an Anchored Metric and compared to the current income on a monthly basis.
Metric Mapping in Covenants
A covenant links two types of metrics:
Metric Mapping — the logical name of the current (regular) metric
Anchored Metric Mapping — the logical name of the same metric, but in its anchored (fixed-at-start) form
This allows the platform to compare the current state with the initial baseline.
For example:
totalIncome >= anchored;
In this way, covenants with anchored metrics become a key tool for post-loan monitoring, enabling the platform to react in a timely manner to deviations from expected borrower behavior.
Covenant Configuration: Field Descriptions
Example of a Configured Covenant

Covenant Name
Type: String
Description: The name of the covenant. Used only in the UI and reports. Does not affect execution.
Holder Type
Type: Dropdown list
Description: The type of entity to which the covenant is applied (e.g., Credit).
Values are populated automatically based on all implementations of the CovenantHolderResolver interface.
Each Holder Type must implement the HasCovenant interface.
Subject Type
Type: Dropdown list
Description: Specifies whose metrics will be used when evaluating the covenant.
The list of available Subject Types is generated from the getCovenantSubjects() method of the resolver corresponding to the selected Holder Type.
Examples of values: Borrower, Guarantor, Collateral
These values correspond to SubjectRecord.name() in the resolver and determine which subjects will be extracted and evaluated.
Metric Mapping
Type: Dropdown list
Description: The name of the regular metric that will be calculated for each subject.
Values are populated based on the selected Subject Type:
The system locates the subject’s class
It looks up all registered metrics for that EntityType
Then displays the names of those metrics
Anchored Metric Mapping
Type: Dropdown list
Description: The name of the metric whose anchored value was previously saved.
Typically, this should match the Metric Mapping.
The same list of available metrics as in Metric Mapping is used.
Product Additives
Type: Dropdown list
Description: Restricts the covenant to only those credits where the selected product is used.
Periodicity
Type: Time unit (Months, Weeks, etc.)
Description: Interval between covenant executions. Used when Execution Type = Scheduled.
Number of Periods
Type: Integer
Description: Specifies the length of the interval in the unit defined by Periodicity.
Date Time Execution
Type: Date and time
Description: The time of the first covenant execution. Used when Execution Type is set to Scheduled.
Execution Type
Type: Scheduled | On demand | On event
Description: Defines the execution mode:
Scheduled — runs on a schedule according to Periodicity, Number Of Period, and Date Time Execution
On demand — manually triggered via API or UI (may not be implemented in the platform)
On event — reactive execution mode (may not be implemented in the platform)
Condition (expression)
Type: JavaScript
Description: The logic used to evaluate the covenant. Supports:
the anchored variable — the anchored value of the metric specified in Anchored Metric Mapping;
a variable named after the Metric Mapping — the current value of the metric;
the entity itself with its parameters, accessible via the alias entity.
Example from the screenshot above.
totalIncome >= anchored;
HasCovenant interface
HasCovenant is a marker interface that indicates an entity can act as a holder of covenants.
It is used by the platform to:
uniquely identify entities to which covenants apply;
standardize processing of these entities within resolvers (CovenantHolderResolver);
abstract business logic from specific types (e.g., Credit, Application, etc.).
Interface Signature
public interface HasCovenant {
Long getId();
}
getId() — уникальный идентификатор сущности.
How to Use
To make an entity participate in the covenant system, you need to:
Implement the HasCovenant interface.
public class Credit implements HasCovenant {
private Long id;
@Override
public Long getId() {
return id;
}
}
Makes an entity compatible with the covenant system;
Acts as a contract in resolvers and during covenant execution;
Enables flexible extension of the list of objects that covenants can be applied to.
For all implementations of HasCovenant, you must implement the interface CovenantHolderResolver<T extends HasCovenant>.
This interface is designed to link together:
the holder — the entity to which the covenant is attached (e.g., Credit);
the subject — an object associated with the holder whose metrics need to be checked (e.g., Participant);
the CovenantSpecification — the covenant rule.
To connect a holder to the covenant system, you need to implement three methods:
1. Stream<T> resolveTargets(CovenantSpecification specification)
Purpose: Finds all holder entities to which the given covenant applies.
Example implementation:
@Override
public Stream<Credit> resolveTargets(CovenantSpecification specification) {
return specification.getAdditives().stream()
.flatMap(a -> creditRepository.getAllByAdditiveId(a));
}
Filtering is performed based on product additives.
This method is used during batch covenant execution according to a schedule.
2. List<SubjectRecord<T>> getCovenantSubjects()
Purpose: Defines which subjects can be extracted from the holder. Returns meta-descriptions of the subjects (by key, type, and supplier function).
Example implementation:
@Override
public List<SubjectRecord<Credit>> getCovenantSubjects() {
return covenantSubjects;
}
private static final List<SubjectRecord<VisionCredit>> covenantSubjects = List.of(
SubjectRecordBuilder.<Credit>builder().name("BORROWER").subject(getBorrower()).build(),
SubjectRecordBuilder.<Credit>builder().name("GUARANTOR").subject(getGuarantors()).build(),
SubjectRecordBuilder.<Credit>builder().name("COLLATERAL").subject(getCollaterals()).build()
);
Each SubjectRecord defines:
a key (e.g., "BORROWER"),
the subject class,
a function to extract the subjects (e.g., credit -> List.of(credit.getApplication().getBorrowerParticipant()) or credit.getParticipants()).
3. Collection<CovenantSpecification> getCovenantSpecifications(T target)
Purpose: Returns all covenant rules that are applicable to a specific holder.
Example implementation:
@Override
public Collection<CovenantSpecification> getCovenantSpecifications(Credit credit) {
return covenantSpecificationRepository.findAllByAdditiveIdAndActiveTrue(
credit.getApplication().getCondition().getProductAdditive().getId()
);
}
SubjectRecordBuilder
To create a subject description, the builder pattern is used:
Example implementation:
SubjectRecord<Credit> borrower = SubjectRecordBuilder.<Credit>builder()
.name("BORROWER")
.subject(new SubjectSupplierRecord<>(
Participant.class,
credit -> List.of(credit.getApplication().getBorrowerParticipant())
))
.build();
The key (name) must be unique and must match the value specified in the Covenant Specification UI.
Anchored Metric Calculation
What is an Anchored Metric
An Anchored Metric is a metric value that is captured at the moment a covenant becomes active — for example, at the time a credit is issued. This value is stored separately from regular metrics and serves as a reference point for future covenant checks.
Anchored metrics are automatically calculated when an entity implementing HasCovenant (e.g., Credit) is created and when the applicable covenant has an Anchored Metric Mapping defined.
When a new object (such as Credit) is created, the Spring component CreateCreditChecker is triggered via the EntityChecker framework.
Example implementation:
@Component
public class CreateCreditChecker extends EntityChecker<Credit, UUID> {
@Autowired
private AnchoredMetricService anchoredMetricService;
@Override
protected void registerListeners(CheckerListenerRegistry<Credit> registry) {
registry.entityChange().inserted();
}
@Override
protected boolean isAvailable(Credit credit) {
return true;
}
@Override
protected void perform(Credit credit) {
anchoredMetricService.calculateAnchored(credit);
}
}
📌 Conditions
Anchored metrics are not recalculated automatically, except when explicitly triggered via recalculateAnchored(...).
If there was an error during initial anchoring (i.e. an exception), it can be detected using the method:
existsAnchoredException(...)
You can manually recalculate anchored metrics:
For the entire holder entity:
anchoredMetricService.recalculateAnchored(holder);
For a specific subject:
anchoredMetricService.recalculateAnchored(holder, subject);
CovenantExecution Lifecycle: Registration and Execution
1. Registering New Tasks (CovenantExecutionProducer)
The CovenantExecutionProducerTask component runs on a schedule and performs the following:
Retrieves all active CovenantSpecification records
For each specification, it calls produce(...), which:
Calculates the periodIndex — the index of the current execution period based on dateTimeExecution, numberOfPeriods, and periodicity
Checks if a CovenantExecution with the same periodIndex already exists
If not, it creates a new CovenantExecution record with status NEW
This scheduling is configured via application properties.
@Scheduled(initialDelayString = "${covenant.execution.producer.initialDelay}", fixedDelayString = "${covenant.execution.producer.fixedDelay}")
2. Processing New Tasks (CovenantExecutionConsumer)
The CovenantExecutionConsumer component is also triggered on a schedule and:
Finds the first CovenantExecution entry with status NEW (via findNewExecutionId())
Calls the runExecution(id) method to process the execution
It is configured via:
@Scheduled(initialDelayString = "${covenant.execution.consumer.initialDelay}", fixedDelayString = "${covenant.execution.consumer.fixedDelay}")
3. Выполнение задания (CovenantExecutionService.runExecution(...))
Execution Flow:
When execution starts:
The corresponding CovenantSpecification is loaded
The expression is compiled
Using the CovenantHolderResolver:
All applicable holder entities are retrieved via resolveTargets(...)
For each holder, subjects are resolved using subjectKey
For each subject:
The regular metric is calculated
If specified, the anchored metric is also retrieved
The expression is evaluated
A CovenantResult is saved with the evaluation state: CLEAN, VIOLATION, or EXCEPTION
All CovenantResults are linked to the current CovenantExecution
The status of CovenantExecution is updated to EVALUATED
✅ Testing Covenant Script with the Evaluate Button
The Timvero interface allows you to test a covenant’s logic before saving it using the Evaluate button. This helps ensure the expression works correctly for a given holder and subject pair.
🔹 How to Test a Covenant
1. Select Holder Type
Choose the type of object the covenant is attached to — for example, Credit.
2. Specify Subject Type
Select the type of subject whose metrics are being checked — for example, Borrower.
3. Configure Metric Mapping and Anchored Metric
Provide the name of the metric and, optionally, an anchored metric to compare against.
4. Choose an Entity in the Test Data Block
In the Entity field, select an object matching the chosen Holder Type (e.g., a specific credit).
You can begin typing the ID, client name, or description — the system will suggest matching options.
5. Write the Validation Expression
The script should be written in JavaScript. Example:
totalIncome >= anchored
6. Click the Evaluate Button
The result will appear in the Output block below, showing:
Execution time
Result: true, false, or an error if the expression is invalid
🔹 What’s Available in the Script
Variable
Description
subject
The object whose metrics are being evaluated — e.g., a Participant or Collateral.
holder
The main entity the covenant is attached to — e.g., a Credit.
metric
The current value of the selected regular metric.
anchored
The anchored (fixed) value of the metric, recorded when the covenant began.
🟣 Example

This means that the subject (e.g., a loan participant) has a current income (totalIncome) that is not lower than the income at the time of issuance (anchored), and the covenant is considered fulfilled.
Last updated
Was this helpful?