# Project export: RuleMigration

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: OpenAI Build Week
- Tagline: RuleMigration uses Codex to migrate a real legacy Drools engine to Java 21 and KIE Rule Units, preserving behavior through characterization tests and human-reviewed, incremental changes.
- Devpost: https://devpost.com/software/rulebridge
- GitHub: https://github.com/malet-pr/ruleUnitsMigration
- Video: https://www.youtube.com/embed/j_dPpm02uXI?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 1 GitHub contributor(s) — Nuria Malet Quintar (3 commits)

## Devpost submission (written by the team)

### Inspiration

RuleMigration began with a problem I know well from my work as a Java developer: legacy business-rule systems are difficult to modernize because the code is only part of the truth. The real behavior is distributed across Java classes, database-backed rules, execution phases, mutable state, and years of accumulated assumptions.

### What it does

This is a business rules engine. Each work-order entering the system represent work done that needs to be homologated before it's send to the accountant departament to be process for pay. The engine uses a number of rules that can modify the the "activities" to be paid by removing, adding, replacing, or modifying them. Rules are grouped by priority (agenda-groups). Within each group, rules do not follow a particular order. The agenda-groups run sequentially and in order. At the end of the process, a mutated work-order is ready for human analyst to inspect them. They have the final decission on what will be paid.

### How we built it

Before using Codex, I had to make the legacy fragment runnable and safe to share. I removed unrelated production structures, replaced all data with synthetic data, prepared a local Oracle environment, and selected a smaller set of rules. Codex did considerably more than accelerate boilerplate. It: analyzed the reduced legacy implementation; created characterization tests; produced an incremental migration plan; implemented the migration in 19 reviewed steps. ChatGPT acted as a technical reviewer and migration-planning partner throughout the project. It helped to interpret Codex’s findings, challenge scope growth, identify missing runtime and operational concerns, and distinguish what the tests actually proved from what still required manual verification.

### Challenges we ran into

During step 11, Codex started to have problem, many failed tests, many compiling issues. He requested authorization to enter Maven .m2 repository to analyze some of the dependencies. He used that information to refactor many classes. At that point I increased effort to high and asked Codex to revise this step again. He found a few problems with the previous implementation and fixed them. From that point on, I kept Codex at high effort level. Another challenge was explaining to Codex some of the domain reasons why rules should behave the way they do, what constituted legitimate defects, which were actually domain decissions that should persist in the new rules service.

### Accomplishments we're proud of

The first, and most important, is that the migrated engine works, preserving the required behavior. Later, Codex, guided by me, introduced a few improvements with respect to the legacy project allowed by the move from traditional DRL with conventional KIE sessions to the Rule Unit model.

### What we learned

By the end of the project we learned that the migration was possible, even desirable in a future because of the characteristics of the Rule Unit model that fits better with the nature of the original rules engine. However, the strongest result that both codex and I arrived independently is that this migration posses significant risks and should not be the first step of the engine's modernization. A first step should be migrate Java, Spring Boot, and Drools to newer versions, but keep the traditional DRL and KIE session implementation. Once that step is stable, then we can consider a second step with Rule Units.

### What's next

for RuleBridge What this prototype does not prove It is not connected to a shared or production-like Oracle environment. The administrative refresh and work-order execution endpoints are not authenticated or authorized. It does not provide final OCP manifests, secret injection, health groups, monitoring, alerting, or an operational rollback runbook. It has not undergone production-scale performance or repeated-refresh memory qualification.

## README (from the GitHub repository)

# RuleMigration

## Hackathon summary

### Problem investigated

RuleMigration investigates the feasibility of migrating a small, representative
portion of a legacy rules-engine service from Java 11 and Drools 7 to Java 21
and Drools 10 while preserving its observed behavior.

The proprietary legacy baseline used during characterization is not included in
this public repository. The repository contains the migrated implementation,
independently created rules, synthetic data, tests, and reproducible development
infrastructure.

### What Codex migrated

Codex analyzed the reduced legacy baseline, created characterization tests, and
developed an incremental migration path from Java 11, Spring Boot 2.7.10,
Drools/KIE 7.48.0.Final, Maven 3.9.16, and Oracle XE 21c to Java 21,
Spring Boot 3.5.10, Drools 10.2.0, Maven 3.9.16, and Oracle XE 21c through
Testcontainers.

The migration was then implemented in 19 human-reviewed steps. Codex also
identified and corrected one defect during its analysis previous revision and approval from the human developer. Codex also corrected another known behavioral defect in the migrated application.

Codex implemented the migrated service, database schema, and a 104-test unit and integration suite, and documented most of the resulting code and operational workflow. Codex wrote the detailed technical runbook and endpoint documentation in this README based on priorities and constraints provided by the human developer.

RuleMigration successfully migrated the selected legacy behavior to KIE Rule Units. The completed prototype then demonstrated that adopting Rule Units in the same production step as the Java and Drools upgrade would create too many simultaneous changes and exposed enough complexity and operational risk to support a different production recommendation.. The recommended production path is therefore incremental: first migrate to Java 21 and Drools 10 using conventional KIE sessions, stabilize that platform, and evaluate Rule Units in a later phase.


### ChatGPT participation

Before the hackathon, ChatGPT helped define a realistic experimental scope and
assisted with SQL scripts for generating synthetic data.

During the hackathon, ChatGPT acted as a discussion partner for architecture,
testing strategy, submission planning, and review of Codex's proposed changes.
It did not directly modify the repository.

### Human participation

The human developer selected the scope, reviewed all architectural and behavioral
decisions, validated characterization outcomes, approved each migration step,
identified unacceptable semantic changes, and decided which Codex recommendations
to accept, reject, or revise.

Codex produced analysis, tests, implementation changes, and documentation, but
the migration contract and final engineering decisions remained human-controlled.

## How to run

The migrated Rule Units project requires Java 21 and docker running. The specific Java version used is Amazon Corretto 21.0.4.
To run tests, cd into the application root.

For fast verification that excludes every Oracle `*IntegrationTest`:

```bash
./mvnw -Dtest='*Test,!**/*IntegrationTest' test
```

This runs the unit, characterization, DRL rendering, runtime-compilation,
snapshot, refresh, and mocked-persistence tests. It normally completes in
seconds and does not require Docker.

For the complete verification suite:

```bash
./mvnw clean test
```

The complete suite requires Docker to be running and accessible to the current
user. Testcontainers starts disposable Oracle XE containers from
`gvenzl/oracle-xe:21-slim-faststart`; the full run normally takes several
minutes because Oracle must start for the integration-test classes.

Neither command connects to or changes the prepared manual Oracle database. All
Oracle integration data is created inside disposable Testcontainers instances.

## Start the application locally with Testcontainers

The supported hackathon launch path starts the complete migrated application
and its own disposable Oracle XE container. Docker must be running. No database
URL, username, password, schema installation, or fixed Oracle host port is
required:

```bash
./mvnw -Dspring-boot.run.main-class=org.acme.ruleunits.local.LocalTestcontainersApplication \
  spring-boot:test-run
```

The launcher lives on the test classpath because Testcontainers and synthetic
fixtures are development infrastructure; the application, controllers, and rule
engine being launched are the production classes. It starts
`gvenzl/oracle-xe:21-slim-faststart`, lets Testcontainers select a random free
host port for Oracle, and prints that mapped port without printing credentials.
It then creates the verified minimal schema and loads the sample work orders and
active version-17 rule set from `src/test/resources/sql`.

The application listens on `http://localhost:8080`. Stop it with `Ctrl+C`; its
Oracle container and all synthetic data are discarded. The launcher makes its
generated datasource settings authoritative, so stale `SPRING_DATASOURCE_*`
variables cannot redirect it to the prepared legacy database. That database is
not contacted or modified.


### Refresh rules

The application starts on port 8080 by default. Startup creates the Spring/JPA
bean graph but does not load or compile the rule set; normal work-order execution
loads it lazily on first use. The administrative operation forces a full reload:

```bash
curl --fail-with-body -i -X POST \
  http://localhost:8080/admin/rules/refresh
```

A successful publication returns HTTP 200 and a sanitized body similar to:

```json
{
  "ruleSetName": "ACTIVITY_RULES",
  "attemptedVersion": 17,
  "correlationId": "<generated UUID>",
  "status": "PUBLISHED",
  "failurePhase": null,
  "failureType": null,
  "summary": null
}
```

A failed load, validation, assembly, compilation, or publication returns HTTP
503 with the attempted version when known, correlation ID, failure phase,
exception type, and fixed summary. It never returns generated DRL or detailed
compiler diagnostics. If an earlier snapshot exists, that last-known-good
snapshot remains available despite the 503.

In Postman, create a request with method `POST`, URL
`http://localhost:8080/admin/rules/refresh`, no request body, and no prototype
authorization header. The endpoint is intentionally unprotected for this
exercise. Do not expose it outside a controlled development environment;
production authentication and authorization must be decided together with the
Actuator security policy.

### Execute work-order rules

The mutating work-order endpoint is disabled by default. The local Testcontainers
launcher enables it; for an external Oracle launch, the
`RuleMigration_RULES_EXECUTION_ENDPOINT_ENABLED=true` setting above does so.
The configured group code defaults to `A`; the controller itself does not
hardcode that value, so additional group executors can be registered later.

The request is a JSON array of work-order numbers:

```bash
curl --fail-with-body -i -X POST \
  'http://localhost:8080/reglas/correr-reglas?agrupador=A' \
  -H 'Content-Type: application/json' \
  --data '["matching","missing","matching","nonmatching"]'
```

Every found, nonempty work order produces legacy-compatible INFO logs in the
same terminal or IntelliJ Run console. Only active activity occurrences are
shown, duplicates are retained, and each entry uses `code-quantity`:

```text
### Evaluando OT: matching
Estado inicial: OT: matching - ACTIVIDADES: [6T8121-1, L81494-1, L81494-1, ZN8450-1]
Estado final: OT: matching - ACTIVIDADES: [FG2802-1]
```

A successful request returns HTTP 200 with the legacy-compatible body `true`.
The submitted list is limited to 100 entries by default before deduplication.
Repeated numbers are reduced to their first occurrence while preserving request
order. Missing work orders and work orders with no activities are silently
ignored. If all entries are ignored, the rules are not initialized.

All found work orders run sequentially using

[README truncated for size]

## Detected evidence (automated analysis)

Indexed codebase: 157 recognized source files, 441 KB.
- Java (language) — detected in the code
- SQL (language) — detected in the code
- Docker (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (120 of 172)

```
.gitignore
database/ct_ot_rule_incident_schema.sql
database/ct_rule_definition_schema.sql
docs/hackathon-log/2026-07-16-codex-session.md
docs/hackathon-log/2026-07-18-codex-session.md
docs/hackathon-log/2026-07-19-final.md
docs/hackathon-log/2026-07-19-session-2.md
docs/oracle-rule-definition-runtime-loading-design.md
LICENSE
README.md
ruleunits/.gitattributes
ruleunits/.gitignore
ruleunits/.mvn/wrapper/maven-wrapper.properties
ruleunits/mvnw
ruleunits/mvnw.cmd
ruleunits/pom.xml
ruleunits/README.md
ruleunits/src/main/java/org/acme/ruleunits/a3/AccumulateUnit.java
ruleunits/src/main/java/org/acme/ruleunits/action/AddActivity.java
ruleunits/src/main/java/org/acme/ruleunits/action/DeactivateActivitiesExceptOne.java
ruleunits/src/main/java/org/acme/ruleunits/action/DeactivateActivityCategory.java
ruleunits/src/main/java/org/acme/ruleunits/action/DeactivateAllActivities.java
ruleunits/src/main/java/org/acme/ruleunits/action/InvalidActivityAdditionException.java
ruleunits/src/main/java/org/acme/ruleunits/action/ReplaceActivity.java
ruleunits/src/main/java/org/acme/ruleunits/action/RuleAction.java
ruleunits/src/main/java/org/acme/ruleunits/action/RuleActionApplier.java
ruleunits/src/main/java/org/acme/ruleunits/api/RuleExecutionEndpointError.java
ruleunits/src/main/java/org/acme/ruleunits/api/RuleSetRefreshController.java
ruleunits/src/main/java/org/acme/ruleunits/api/RuleSetRefreshResponse.java
ruleunits/src/main/java/org/acme/ruleunits/api/WorkOrderRulesController.java
ruleunits/src/main/java/org/acme/ruleunits/catalog/ActivityCatalog.java
ruleunits/src/main/java/org/acme/ruleunits/compilation/CompiledRuleSet.java
ruleunits/src/main/java/org/acme/ruleunits/compilation/DrlRenderingException.java
ruleunits/src/main/java/org/acme/ruleunits/compilation/RenderedRuleSet.java
ruleunits/src/main/java/org/acme/ruleunits/compilation/RenderedRuleStage.java
ruleunits/src/main/java/org/acme/ruleunits/compilation/RuleSetCompilationException.java
ruleunits/src/main/java/org/acme/ruleunits/compilation/RuntimeRuleSetCompiler.java
ruleunits/src/main/java/org/acme/ruleunits/compilation/TraditionalDrlRenderer.java
ruleunits/src/main/java/org/acme/ruleunits/config/RuleUnitsRuntimeConfiguration.java
ruleunits/src/main/java/org/acme/ruleunits/definition/ReplacementActionDefinition.java
ruleunits/src/main/java/org/acme/ruleunits/definition/RequiredActivityCondition.java
ruleunits/src/main/java/org/acme/ruleunits/definition/RuleSetAssembler.java
ruleunits/src/main/java/org/acme/ruleunits/definition/RuleTemplate.java
ruleunits/src/main/java/org/acme/ruleunits/definition/TemplateRuleDefinition.java
ruleunits/src/main/java/org/acme/ruleunits/domain/ActivityOccurrence.java
ruleunits/src/main/java/org/acme/ruleunits/domain/ActivityOrigin.java
ruleunits/src/main/java/org/acme/ruleunits/domain/WorkOrderEvaluation.java
ruleunits/src/main/java/org/acme/ruleunits/domain/WorkOrderType.java
ruleunits/src/main/java/org/acme/ruleunits/loading/ActiveRuleSetNotFoundException.java
ruleunits/src/main/java/org/acme/ruleunits/loading/LoadedRuleAction.java
ruleunits/src/main/java/org/acme/ruleunits/loading/LoadedRuleCondition.java
ruleunits/src/main/java/org/acme/ruleunits/loading/LoadedRuleDefinition.java
ruleunits/src/main/java/org/acme/ruleunits/loading/LoadedRuleSetDefinition.java
ruleunits/src/main/java/org/acme/ruleunits/loading/LoadedRuleStageDefinition.java
ruleunits/src/main/java/org/acme/ruleunits/loading/LoadedRuleTemplate.java
ruleunits/src/main/java/org/acme/ruleunits/loading/OracleRuleDefinitionLoader.java
ruleunits/src/main/java/org/acme/ruleunits/loading/RuleDefinitionValidationException.java
ruleunits/src/main/java/org/acme/ruleunits/loading/RuleSetDefinitionSource.java
ruleunits/src/main/java/org/acme/ruleunits/loading/RuleSetDefinitionValidator.java
ruleunits/src/main/java/org/acme/ruleunits/oracle/ActivityDefinitionEntity.java
ruleunits/src/main/java/org/acme/ruleunits/oracle/ActivityDefinitionJpaRepository.java
ruleunits/src/main/java/org/acme/ruleunits/oracle/definition/RuleActionEntity.java
ruleunits/src/main/java/org/acme/ruleunits/oracle/definition/RuleConditionEntity.java
ruleunits/src/main/java/org/acme/ruleunits/oracle/definition/RuleDefinitionEntity.java
ruleunits/src/main/java/org/acme/ruleunits/oracle/definition/RuleSetEntity.java
ruleunits/src/main/java/org/acme/ruleunits/oracle/definition/RuleSetJpaRepository.java
ruleunits/src/main/java/org/acme/ruleunits/oracle/definition/RuleSetStatus.java
ruleunits/src/main/java/org/acme/ruleunits/oracle/definition/RuleStageEntity.java
ruleunits/src/main/java/org/acme/ruleunits/oracle/definition/RuleTemplateEntity.java
ruleunits/src/main/java/org/acme/ruleunits/oracle/definition/RuleTemplateJpaRepository.java
ruleunits/src/main/java/org/acme/ruleunits/oracle/OracleActivityCatalog.java
ruleunits/src/main/java/org/acme/ruleunits/oracle/OracleRuleIncidentRecorder.java
ruleunits/src/main/java/org/acme/ruleunits/oracle/OracleWorkOrderRepository.java
ruleunits/src/main/java/org/acme/ruleunits/oracle/RuleEntity.java
ruleunits/src/main/java/org/acme/ruleunits/oracle/RuleIncidentEntity.java
ruleunits/src/main/java/org/acme/ruleunits/oracle/RuleIncidentJpaRepository.java
ruleunits/src/main/java/org/acme/ruleunits/oracle/RuleJpaRepository.java
ruleunits/src/main/java/org/acme/ruleunits/oracle/RuleTypeEntity.java
ruleunits/src/main/java/org/acme/ruleunits/oracle/RuleTypeJpaRepository.java
ruleunits/src/main/java/org/acme/ruleunits/oracle/TaskEntity.java
ruleunits/src/main/java/org/acme/ruleunits/oracle/WorkOrderActivityEntity.java
ruleunits/src/main/java/org/acme/ruleunits/oracle/WorkOrderEntity.java
ruleunits/src/main/java/org/acme/ruleunits/oracle/WorkOrderJpaRepository.java
ruleunits/src/main/java/org/acme/ruleunits/orchestration/DynamicRulesOrchestrator.java
ruleunits/src/main/java/org/acme/ruleunits/orchestration/LazyInitializingRulesEngine.java
ruleunits/src/main/java/org/acme/ruleunits/orchestration/RuleGroupExecutor.java
ruleunits/src/main/java/org/acme/ruleunits/orchestration/RuleGroupExecutorRegistry.java
ruleunits/src/main/java/org/acme/ruleunits/orchestration/RulesExecutionResult.java
ruleunits/src/main/java/org/acme/ruleunits/orchestration/RuleStageExecutionException.java
ruleunits/src/main/java/org/acme/ruleunits/orchestration/SelectedRulesOrchestrator.java
ruleunits/src/main/java/org/acme/ruleunits/orchestration/WorkOrderRulesBatch.java
ruleunits/src/main/java/org/acme/ruleunits/orchestration/WorkOrderRulesEngine.java
ruleunits/src/main/java/org/acme/ruleunits/orchestration/WorkOrderStageSaver.java
ruleunits/src/main/java/org/acme/ruleunits/persistence/ActivityRecord.java
ruleunits/src/main/java/org/acme/ruleunits/persistence/RuleIncidentRecorder.java
ruleunits/src/main/java/org/acme/ruleunits/persistence/RuleProcessingStatus.java
ruleunits/src/main/java/org/acme/ruleunits/persistence/WorkOrderMapper.java
ruleunits/src/main/java/org/acme/ruleunits/persistence/WorkOrderProcessingOutcome.java
ruleunits/src/main/java/org/acme/ruleunits/persistence/WorkOrderRecord.java
ruleunits/src/main/java/org/acme/ruleunits/persistence/WorkOrderRepository.java
ruleunits/src/main/java/org/acme/ruleunits/persistence/WorkOrderRulesService.java
ruleunits/src/main/java/org/acme/ruleunits/ra1/Ra1Unit.java
ruleunits/src/main/java/org/acme/ruleunits/ra2/Ra2Unit.java
ruleunits/src/main/java/org/acme/ruleunits/ra3/Ra3Unit.java
ruleunits/src/main/java/org/acme/ruleunits/refresh/RuleSetRefreshCoordinator.java
ruleunits/src/main/java/org/acme/ruleunits/refresh/RuleSetRefreshPhase.java
ruleunits/src/main/java/org/acme/ruleunits/refresh/RuleSetRefreshResult.java
ruleunits/src/main/java/org/acme/ruleunits/refresh/RuleSetRefreshStatus.java
ruleunits/src/main/java/org/acme/ruleunits/refresh/RuleSetRuntimeService.java
ruleunits/src/main/java/org/acme/ruleunits/RuleunitsApplication.java
ruleunits/src/main/java/org/acme/ruleunits/runtime/ra1/Ra1RuntimeUnit.java
ruleunits/src/main/java/org/acme/ruleunits/runtime/ra2/Ra2RuntimeUnit.java
ruleunits/src/main/java/org/acme/ruleunits/runtime/ra3/Ra3RuntimeUnit.java
ruleunits/src/main/java/org/acme/ruleunits/smoke/SmokeMessage.java
ruleunits/src/main/java/org/acme/ruleunits/smoke/SmokeUnit.java
ruleunits/src/main/java/org/acme/ruleunits/snapshot/CompiledRuleSetSnapshot.java
ruleunits/src/main/java/org/acme/ruleunits/snapshot/RuleExecutionUnavailableException.java
ruleunits/src/main/java/org/acme/ruleunits/snapshot/RuleSetLease.java
ruleunits/src/main/java/org/acme/ruleunits/snapshot/RuleSetSnapshotManager.java
ruleunits/src/main/java/org/acme/ruleunits/snapshot/SnapshotRetirementFailure.java
[52 more files omitted for size]
```

### Dependencies

No dependency index available.

### Recent commits (newest first)

- fix readme
- improves README.md file
- Add MIT License to the project
- initial commit

## Key source files (fetched from GitHub, selected and truncated for size)

### docs/oracle-rule-definition-runtime-loading-design.md

```markdown
# Oracle rule-definition and runtime-loading design

## Scope

This document records the boundary for storing, assembling, validating, loading,
compiling, and publishing database-provided Rule Unit DRL. Oracle access, runtime
compilation, atomic snapshots, lazy initialization, and the administrative HTTP
boundary are implemented through Increment 17. A cache library, production
endpoint authorization, and distributed coordination are not implemented.

Work-order persistence remains a separate boundary. Increment 7 provided the
mocked boundary; Increment 8 implemented and tested its Oracle JPA adapters.
Increments 9 through 17 implement the versioned definition, loader, compiler,
snapshot, refresh, dynamic execution, Spring lifecycle, and HTTP boundaries.

## Proposed rule-definition mappings

### RULE_SET

- `ID`: primary key.
- `NAME`: business name.
- `VERSION`: monotonically increasing version within the name.
- `STATUS`: `DRAFT`, `VALID`, `ACTIVE`, or `RETIRED`.
- `VALIDATED_AT`, `ACTIVATED_AT`: lifecycle timestamps.
- `VALIDATION_MESSAGE`: sanitized validation result.

Only one version of a named rule set may be active. Activation must be atomic
and must only accept a successfully validated version.

### RULE_TYPE

- `ID`: primary key.
- `RULE_SET_ID`: owning rule-set version.
- `CODE`: for example `RA1`, `RA2`, or `RA3`.
- `STAGE_ORDER`: explicit cross-stage execution order.
- `ACTIVE`: activation flag.
- `UNIT_PACKAGE`, `UNIT_NAME`: Java/DRL Rule Unit identity.

Rule type is the natural grouping key for loading and compiling a stage.

### RULE_TEMPLATE

- `ID`: primary key.
- `TEMPLATE_KEY`, `TEMPLATE_VERSION`: stable identity for an immutable template revision.
- `DRL_TEMPLATE`: CLOB containing the reviewed DRL template.
- `SHAPE`: for example `REPLACE_REQUIRED_ACTIVITIES`,
  `DEACTIVATE_CATEGORY`, or `ACCUMULATE_LEAVE_ONE`.
- `ACTIVE`: activation flag.

Templates contain reviewed DRL structure. Values supplied by rule rows are
validated and substituted into known placeholders; arbitrary fragments are not
accepted as condition or consequence values.

### RULE_DEFINITION

- `ID`: primary key.
- `RULE_TYPE_ID`, `RULE_TEMPLATE_ID`: owning stage and template.
- `RULE_NAME`: unique within the Rule Unit.
- `WORK_ORDER_TYPE`, `JOB_TYPE`: optional structured conditions.
- `ACTIVE`: activation flag.
- `RULE_ORDER`: deterministic assembly order only; it does not impose agenda
  order within a Rule Unit.

### RULE_CONDITION

- `ID`: primary key.
- `RULE_DEFINITION_ID`: owning rule.
- `POSITION`: ordered position within the repeated condition family.
- `CONDITION_TYPE`: for example `REQUIRED_ACTIVITY`,
  `ACTIVE_CATEGORY`, or `ACCUMULATED_ACTIVITY`.
- `OPERATOR`: a constrained allow-listed operator.
- `VALUE`: validated condition value.
- `NUMERIC_VALUE`: optional threshold such as the accumulate count.

The unique key `(RULE_DEFINITION_ID, POSITION)` preserves variable-length
condition order.

### RULE_ACTION

- `ID`: primary key.
- `RULE_DEFINITION
[truncated — 8721 more characters]
```

### docs/hackathon-log/2026-07-16-codex-session.md

```markdown
# Codex session record — 2026-07-16

## Repository analysis completed

- Read the root and legacy `AGENTS.md` instructions.
- Mapped the Oracle schema, fixtures, reset process, and application connection.
- Identified the legacy stack: Java 11, Spring Boot 2.7.10, Maven 3.9.16, Drools/KIE 7.48.0.Final, and Oracle XE 21c.
- Traced the selected rules from request/work-order input through database DRL loading, classpath headers, KIE construction, agenda execution, queued actions, and persistence.
- Confirmed from code, read-only Oracle queries, and the sample log that rule types run RA1 → RA2 → RA3.
- Confirmed that duplicate activity occurrences are distinct and that only work-order activity state is materially changed in the reduced project.
- Treated `ruleunits/` as an unvalidated migration placeholder.

## Corrections and clarifications provided

- Any migration will continue to use Oracle; the PostgreSQL dependency is accidental.
- Saving the work-order aggregate is reduced-project plumbing. The full system also records which rule set was applied to the work order.
- The selected rules do not execute concurrently.
- No order is enforced among rules inside one agenda group.
- An “original activity” is an occurrence not added by a rule; this distinction is used later in the system.
- The sample run is repeatable after resetting one table in the database.
- Inactive activities satisfying RA3 category matching is a legacy defect and should be corrected in a migrated implementation.

## Characterization tests added

Added `SelectedLegacyRulesCharacterizationTests`, using mocked repositories with the production DRL assembly, Drools 7 KIE builder/session, adapters, action service, and orchestration.

1. `preservesDuplicateOccurrencesReplacedByRa1WhenRa2RunsLater`
   - Freezes one-for-one replacement of duplicate `L81494` occurrences.
   - Confirms RA1-created `097079` occurrences survive RA2 and retain RA1 attribution.
2. `ra1CategoryRuleDeactivatesCat2BeforeRa2AddsItsActivity`
   - Freezes RA1 CAT2 deactivation followed by RA2 processing.
   - Confirms each original occurrence records the rule that deactivated it.
3. `ra3CanMatchAnOriginalCat3ActivityDeactivatedByRa2`
   - Documents the legacy defect where RA3 sees an inactive original CAT3 activity.
   - This is a legacy baseline, not the desired migrated outcome.
4. `leavesANonMatchingWorkOrderUnchangedButStillSavesIt`
   - Freezes unchanged activity state and the save boundary for valid nonmatching work orders.
5. `silentlyIgnoresAMissingWorkOrder`
   - Freezes current handling of missing work orders: no save and overall success.

The empty Spring Initializr test was removed.

## Agreed migration contract

- Preserve duplicate activity occurrences and replace each matching occurrence independently.
- Preserve accurate applied rule attribution.
- Preserve explicit RA1 → RA2 → RA3 sequencing.
- Do not introduce ordering within a rule stage.
- Preserve the distinction between original and rule-create
[truncated — 2125 more characters]
```

### database/ct_ot_rule_incident_schema.sql

```sql
CREATE SEQUENCE LEGACY.CTS_OT_RULE_INCIDENT
    START WITH 1 INCREMENT BY 1 NOCYCLE CACHE 20 NOORDER;

CREATE TABLE LEGACY.CT_OT_RULE_INCIDENT (
    ID_OT_RULE_INCIDENT NUMBER(19,0) NOT NULL,
    ID_ORDEN_TRABAJO NUMBER(19,0) NOT NULL,
    RULE_NAME VARCHAR2(255 CHAR),
    RULE_STAGE VARCHAR2(20 CHAR) NOT NULL,
    RULE_ERROR_CODE VARCHAR2(100 CHAR) NOT NULL,
    RULE_ERROR_DETAIL VARCHAR2(1000 CHAR),
    RULE_PROCESSED_AT TIMESTAMP(6) NOT NULL,
    STATUS VARCHAR2(20 CHAR) DEFAULT 'OPEN' NOT NULL,
    RESOLVED_AT TIMESTAMP(6),
    PROCESSING_ATTEMPT_ID VARCHAR2(36 CHAR) NOT NULL,
    CONSTRAINT PK_OT_RULE_INCIDENT PRIMARY KEY (ID_OT_RULE_INCIDENT),
    CONSTRAINT FK_OT_RULE_INCIDENT_OT FOREIGN KEY (ID_ORDEN_TRABAJO)
        REFERENCES LEGACY.CT_ORDEN_TRABAJO (ID_ORDEN_TRABAJO),
    CONSTRAINT FK_OT_RULE_INCIDENT_RULE FOREIGN KEY (RULE_NAME)
        REFERENCES LEGACY.CT_REGLA (NOMBRE),
    CONSTRAINT CK_OT_RULE_INCIDENT_STATUS CHECK (STATUS IN ('OPEN', 'RESOLVED'))
);

CREATE INDEX LEGACY.IX_OT_RULE_INCIDENT_OT_STATUS
    ON LEGACY.CT_OT_RULE_INCIDENT (ID_ORDEN_TRABAJO, STATUS);
CREATE INDEX LEGACY.IX_OT_RULE_INCIDENT_RULE_STATUS
    ON LEGACY.CT_OT_RULE_INCIDENT (RULE_NAME, STATUS);
CREATE INDEX LEGACY.IX_OT_RULE_INCIDENT_PROCESSED
    ON LEGACY.CT_OT_RULE_INCIDENT (RULE_PROCESSED_AT);
CREATE INDEX LEGACY.IX_OT_RULE_INCIDENT_CODE_STATUS
    ON LEGACY.CT_OT_RULE_INCIDENT (RULE_ERROR_CODE, STATUS);

```

### ruleunits/pom.xml

```xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.5.10</version>
        <relativePath/>
    </parent>
    <groupId>org.acme</groupId>
    <artifactId>ruleunits</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>kjar</packaging>
    <name>ruleunits</name>
    <description>RuleBridge KIE Rule Units migration</description>
    <properties>
        <java.version>21</java.version>
        <drools.version>10.2.0</drools.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.oracle.database.jdbc</groupId>
            <artifactId>ojdbc11</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-ruleunits-engine</artifactId>
            <version>${drools.version}</version>
        </dependency>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-wiring-dynamic</artifactId>
            <version>${drools.version}</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.testcontainers</groupId>
            <artifactId>junit-jupiter</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.testcontainers</groupId>
            <artifactId>oracle-xe</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.kie</groupId>
                <artifactId>kie-maven-plugin</artifactId>
                <version>${drools.version}</version>
                <extensions>true</extensions>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

```

### database/ct_rule_definition_schema.sql

```sql
CREATE SEQUENCE LEGACY.CTS_RULE_SET START WITH 1 INCREMENT BY 1 NOCYCLE CACHE 20 NOORDER;
CREATE SEQUENCE LEGACY.CTS_RULE_STAGE START WITH 1 INCREMENT BY 1 NOCYCLE CACHE 20 NOORDER;
CREATE SEQUENCE LEGACY.CTS_RULE_TEMPLATE START WITH 1 INCREMENT BY 1 NOCYCLE CACHE 20 NOORDER;
CREATE SEQUENCE LEGACY.CTS_RULE_DEFINITION START WITH 1 INCREMENT BY 1 NOCYCLE CACHE 20 NOORDER;
CREATE SEQUENCE LEGACY.CTS_RULE_CONDITION START WITH 1 INCREMENT BY 1 NOCYCLE CACHE 20 NOORDER;
CREATE SEQUENCE LEGACY.CTS_RULE_ACTION START WITH 1 INCREMENT BY 1 NOCYCLE CACHE 20 NOORDER;

CREATE TABLE LEGACY.CT_RULE_SET (
    ID_RULE_SET NUMBER(19,0) NOT NULL,
    RULE_SET_NAME VARCHAR2(100 CHAR) NOT NULL,
    RULE_SET_VERSION NUMBER(19,0) NOT NULL,
    STATUS VARCHAR2(20 CHAR) NOT NULL,
    VALIDATED_AT TIMESTAMP(6),
    ACTIVATED_AT TIMESTAMP(6),
    VALIDATION_MESSAGE VARCHAR2(1000 CHAR),
    CONSTRAINT PK_RULE_SET PRIMARY KEY (ID_RULE_SET),
    CONSTRAINT UK_RULE_SET_NAME_VERSION UNIQUE (RULE_SET_NAME, RULE_SET_VERSION),
    CONSTRAINT CK_RULE_SET_VERSION CHECK (RULE_SET_VERSION > 0),
    CONSTRAINT CK_RULE_SET_STATUS CHECK (STATUS IN ('DRAFT', 'VALID', 'ACTIVE', 'RETIRED')),
    CONSTRAINT CK_RULE_SET_ACTIVE_VALID CHECK (STATUS <> 'ACTIVE' OR VALIDATED_AT IS NOT NULL)
);

CREATE UNIQUE INDEX LEGACY.UK_RULE_SET_SINGLE_ACTIVE
    ON LEGACY.CT_RULE_SET (
        CASE WHEN STATUS = 'ACTIVE' THEN RULE_SET_NAME END
    );

CREATE TABLE LEGACY.CT_RULE_STAGE (
    ID_RULE_STAGE NUMBER(19,0) NOT NULL,
    ID_RULE_SET NUMBER(19,0) NOT NULL,
    STAGE_CODE VARCHAR2(20 CHAR) NOT NULL,
    STAGE_ORDER NUMBER(10,0) NOT NULL,
    UNIT_PACKAGE VARCHAR2(255 CHAR) NOT NULL,
    UNIT_NAME VARCHAR2(255 CHAR) NOT NULL,
    ACTIVE CHAR(1 CHAR) DEFAULT 'S' NOT NULL,
    CONSTRAINT PK_RULE_STAGE PRIMARY KEY (ID_RULE_STAGE),
    CONSTRAINT FK_RULE_STAGE_SET FOREIGN KEY (ID_RULE_SET) REFERENCES LEGACY.CT_RULE_SET (ID_RULE_SET),
    CONSTRAINT UK_RULE_STAGE_CODE UNIQUE (ID_RULE_SET, STAGE_CODE),
    CONSTRAINT UK_RULE_STAGE_ORDER UNIQUE (ID_RULE_SET, STAGE_ORDER),
    CONSTRAINT CK_RULE_STAGE_ORDER CHECK (STAGE_ORDER > 0),
    CONSTRAINT CK_RULE_STAGE_ACTIVE CHECK (ACTIVE IN ('S', 'N'))
);

CREATE TABLE LEGACY.CT_RULE_TEMPLATE (
    ID_RULE_TEMPLATE NUMBER(19,0) NOT NULL,
    TEMPLATE_KEY VARCHAR2(100 CHAR) NOT NULL,
    TEMPLATE_VERSION NUMBER(19,0) NOT NULL,
    SHAPE VARCHAR2(100 CHAR) NOT NULL,
    DRL_TEMPLATE CLOB NOT NULL,
    ACTIVE CHAR(1 CHAR) DEFAULT 'S' NOT NULL,
    CONSTRAINT PK_RULE_TEMPLATE PRIMARY KEY (ID_RULE_TEMPLATE),
    CONSTRAINT UK_RULE_TEMPLATE_KEY_VERSION UNIQUE (TEMPLATE_KEY, TEMPLATE_VERSION),
    CONSTRAINT CK_RULE_TEMPLATE_VERSION CHECK (TEMPLATE_VERSION > 0),
    CONSTRAINT CK_RULE_TEMPLATE_ACTIVE CHECK (ACTIVE IN ('S', 'N'))
);

CREATE TABLE LEGACY.CT_RULE_DEFINITION (
    ID_RULE_DEFINITION NUMBER(19,0) NOT NULL,
    ID_RULE_STAGE NUMBER(19,0) NOT NULL,
    ID_RULE_TEMPLATE NUMBER(19,0) NOT NULL,
    RULE_NAME VARCHAR2(255 CHAR) NOT NULL,
    RULE_ORDER NUMBER(10,0) NOT NULL,
    WORK_ORDER_TYPE VARCHAR2(20 CHAR),
    JOB_TYPE VARCHAR2(255 CHAR),
    ACTIVE CHAR(1 CHAR) DEFAULT 'S' NOT NULL,
    CONSTRAINT PK_RULE_DEFINITION PRIMARY KEY (ID_RULE_DEFINITION),
    CONSTRAINT FK_RULE_DEFINITION_STAGE FOREIGN KEY (ID_RULE_STAGE) REFERENCES LEGACY.CT_RULE_STAGE (ID_RULE_STAGE),
    CONSTRAINT FK_RULE_DEFINITION_TEMPLATE FOREIGN KEY (ID_RULE_TEMPLATE) REFERENCES LEGACY.CT_RULE_TEMPLATE (ID_RULE_TEMPLATE),
    CONSTRAINT UK_RULE_DEFINITION_NAME UNIQUE (ID_RULE_STAGE, RULE_NAME),
    CONSTRAINT UK_RULE_DEFINITION_ORDER UNIQUE (ID_RULE_STAGE, RULE_ORDER),
    CONSTRAINT CK_RULE_DEFINITION_ORDER CHECK (RULE_ORDER > 0),
    CONSTRAINT CK_RULE_DEFINITION_ACTIVE CHECK (ACTIVE IN ('S', 'N'))
);

CREATE TABLE LEGACY.CT_RULE_CONDITION (
    ID_RULE_CONDITION NUMBER(19,0) NOT NULL,
    ID_RULE_DEFINITION NUMBER(19,0) NOT NULL,
    POSITION NUMBER(10,0) NOT NULL,
    CONDITION_TYPE VARCHAR2(100 CHAR) NOT NULL,
    OPERATOR VARCHAR2(50 CHAR) NOT NULL,
    CONDITION_VALUE VARCHAR2(1000 CHAR),
    NUMERIC_VALUE NUMBER(19,0),
    CONSTRAINT PK_RULE_CONDITION PRIMARY KEY (ID_RULE_CONDITION),
    CONSTRAINT FK_RULE_CONDITION_DEF FOREIGN KEY (ID_RULE_DEFINITION) REFERENCES LEGACY.CT_RULE_DEFINITION (ID_RULE_DEFINITION),
    CONSTRAINT UK_RULE_CONDITION_POS UNIQUE (ID_RULE_DEFINITION, POSITION),
    CONSTRAINT CK_RULE_CONDITION_POS CHECK (POSITION > 0)
);

CREATE TABLE LEGACY.CT_RULE_ACTION (
    ID_RULE_ACTION NUMBER(19,0) NOT NULL,
    ID_RULE_DEFINITION NUMBER(19,0) NOT NULL,
    POSITION NUMBER(10,0) NOT NULL,
    ACTION_TYPE VARCHAR2(100 CHAR) NOT NULL,
    OLD_ACTIVITY_CODE VARCHAR2(255 CHAR),
    NEW_ACTIVITY_CODE VARCHAR2(255 CHAR),
    CATEGORY VARCHAR2(255 CHAR),
    CONSTRAINT PK_RULE_ACTION PRIMARY KEY (ID_RULE_ACTION),
    CONSTRAINT FK_RULE_ACTION_DEF FOREIGN KEY (ID_RULE_DEFINITION) REFERENCES LEGACY.CT_RULE_DEFINITION (ID_RULE_DEFINITION),
    CONSTRAINT UK_RULE_ACTION_POS UNIQUE (ID_RULE_DEFINITION, POSITION),
    CONSTRAINT CK_RULE_ACTION_POS CHECK (POSITION > 0)
);

```

### ruleunits/src/test/resources/sql/oracle-rule-definition-clean.sql

```sql
DELETE FROM CT_RULE_ACTION;
DELETE FROM CT_RULE_CONDITION;
DELETE FROM CT_RULE_DEFINITION;
DELETE FROM CT_RULE_STAGE;
DELETE FROM CT_RULE_TEMPLATE;
DELETE FROM CT_RULE_SET;

```

### ruleunits/src/test/resources/sql/oracle-clean.sql

```sql
DELETE FROM CT_OT_RULE_INCIDENT;
DELETE FROM CT_OT_ACTIVIDAD;
DELETE FROM CT_ORDEN_TRABAJO;
DELETE FROM CT_REGLA;
DELETE FROM CT_REGLA_TIPO;
DELETE FROM CT_ACTIVIDAD;
DELETE FROM CT_TAREA;

```

### ruleunits/src/test/resources/sql/oracle-stage15-data.sql

```sql
INSERT INTO CT_ACTIVIDAD VALUES (9,'SS8192',NULL,'S');
INSERT INTO CT_ACTIVIDAD VALUES (10,'Q79984',NULL,'S');
INSERT INTO CT_ACTIVIDAD VALUES (11,'AZ9593',NULL,'S');
INSERT INTO CT_ACTIVIDAD VALUES (12,'DS7068',NULL,'S');
INSERT INTO CT_ACTIVIDAD VALUES (13,'G99427',NULL,'S');
INSERT INTO CT_REGLA VALUES (5,'RA1-test-1-2');
INSERT INTO CT_REGLA VALUES (6,'RA1-test-1-3');
INSERT INTO CT_ORDEN_TRABAJO VALUES (13,'variant','F',2);
INSERT INTO CT_ORDEN_TRABAJO VALUES (14,'guarded','F',3);
INSERT INTO CT_OT_ACTIVIDAD VALUES (8,'S',1,12,13,NULL,NULL);
INSERT INTO CT_OT_ACTIVIDAD VALUES (9,'S',1,8,13,NULL,NULL);
INSERT INTO CT_OT_ACTIVIDAD VALUES (10,'S',1,7,14,NULL,NULL);
INSERT INTO CT_OT_ACTIVIDAD VALUES (11,'S',1,8,14,NULL,NULL);

```

### ruleunits/src/test/resources/sql/oracle-data.sql

```sql
INSERT INTO CT_TAREA VALUES (1,'KPVG961');
INSERT INTO CT_TAREA VALUES (2,'OTHER');
INSERT INTO CT_TAREA VALUES (3,'JM5G513');
INSERT INTO CT_ACTIVIDAD VALUES (1,'6T8121','CAT3','S');
INSERT INTO CT_ACTIVIDAD VALUES (2,'L81494','CAT2','S');
INSERT INTO CT_ACTIVIDAD VALUES (3,'ZN8450',NULL,'S');
INSERT INTO CT_ACTIVIDAD VALUES (4,'097079','CAT2','S');
INSERT INTO CT_ACTIVIDAD VALUES (5,'FG2802',NULL,'S');
INSERT INTO CT_ACTIVIDAD VALUES (6,'I51434','CAT1','S');
INSERT INTO CT_ACTIVIDAD VALUES (7,'E60387','CAT3','S');
INSERT INTO CT_ACTIVIDAD VALUES (8,'KO6502',NULL,'S');
INSERT INTO CT_REGLA_TIPO VALUES (1,'RA1');
INSERT INTO CT_REGLA_TIPO VALUES (2,'RA2');
INSERT INTO CT_REGLA_TIPO VALUES (3,'RA3');
INSERT INTO CT_REGLA VALUES (1,'RA1-test-1');
INSERT INTO CT_REGLA VALUES (2,'RA1-test-2');
INSERT INTO CT_REGLA VALUES (3,'RA2-test-1');
INSERT INTO CT_REGLA VALUES (4,'RA3-test-1');
INSERT INTO CT_ORDEN_TRABAJO VALUES (10,'matching','F',1);
INSERT INTO CT_ORDEN_TRABAJO VALUES (11,'nonmatching','A',2);
INSERT INTO CT_ORDEN_TRABAJO VALUES (12,'blocked','F',3);
INSERT INTO CT_OT_ACTIVIDAD VALUES (1,'S',1,1,10,NULL,NULL);
INSERT INTO CT_OT_ACTIVIDAD VALUES (2,'S',1,2,10,NULL,NULL);
INSERT INTO CT_OT_ACTIVIDAD VALUES (3,'S',1,2,10,NULL,NULL);
INSERT INTO CT_OT_ACTIVIDAD VALUES (4,'S',1,3,10,NULL,NULL);
INSERT INTO CT_OT_ACTIVIDAD VALUES (5,'S',1,6,11,NULL,NULL);
INSERT INTO CT_OT_ACTIVIDAD VALUES (6,'S',1,7,12,NULL,NULL);
INSERT INTO CT_OT_ACTIVIDAD VALUES (7,'S',1,8,12,NULL,NULL);

```

### ruleunits/src/test/resources/sql/oracle-schema.sql

```sql
CREATE SEQUENCE CTS_OT_ACTIVIDAD START WITH 100 INCREMENT BY 1 NOCYCLE;
CREATE SEQUENCE CTS_OT_RULE_INCIDENT START WITH 1 INCREMENT BY 1 NOCYCLE;
CREATE TABLE CT_TAREA (ID_TAREA NUMBER(19) PRIMARY KEY, CODIGO VARCHAR2(255) NOT NULL);
CREATE TABLE CT_ACTIVIDAD (ID_ACTIVIDAD NUMBER(19) PRIMARY KEY, CODIGO VARCHAR2(255) UNIQUE,
 CATEGORIA VARCHAR2(255), ACTIVO CHAR(1));
CREATE TABLE CT_REGLA_TIPO (ID_REGLA_TIPO NUMBER(19) PRIMARY KEY, NOMBRE_CORTO VARCHAR2(255) UNIQUE);
CREATE TABLE CT_REGLA (ID_REGLA NUMBER(19) PRIMARY KEY, NOMBRE VARCHAR2(255) UNIQUE NOT NULL);
CREATE TABLE CT_ORDEN_TRABAJO (ID_ORDEN_TRABAJO NUMBER(19) PRIMARY KEY, NRO_OT VARCHAR2(255) UNIQUE,
 TIPO_OT CHAR(1), ID_TAREA NUMBER(19) REFERENCES CT_TAREA(ID_TAREA));
CREATE TABLE CT_OT_ACTIVIDAD (ID_OT_ACTIVIDAD NUMBER(19) PRIMARY KEY, ACTIVO CHAR(1), CANTIDAD NUMBER(10),
 ID_ACTIVIDAD NUMBER(19) REFERENCES CT_ACTIVIDAD(ID_ACTIVIDAD),
 ID_ORDEN_TRABAJO NUMBER(19) REFERENCES CT_ORDEN_TRABAJO(ID_ORDEN_TRABAJO),
 ID_REGLA_TIPO NUMBER(19) REFERENCES CT_REGLA_TIPO(ID_REGLA_TIPO),
 ID_REGLA_APLICADA NUMBER(19) REFERENCES CT_REGLA(ID_REGLA));
CREATE TABLE CT_OT_RULE_INCIDENT (
 ID_OT_RULE_INCIDENT NUMBER(19) PRIMARY KEY,
 ID_ORDEN_TRABAJO NUMBER(19) NOT NULL REFERENCES CT_ORDEN_TRABAJO(ID_ORDEN_TRABAJO),
 RULE_NAME VARCHAR2(255) REFERENCES CT_REGLA(NOMBRE),
 RULE_STAGE VARCHAR2(20) NOT NULL, RULE_ERROR_CODE VARCHAR2(100) NOT NULL,
 RULE_ERROR_DETAIL VARCHAR2(1000), RULE_PROCESSED_AT TIMESTAMP(6) NOT NULL,
 STATUS VARCHAR2(20) DEFAULT 'OPEN' NOT NULL, RESOLVED_AT TIMESTAMP(6),
 PROCESSING_ATTEMPT_ID VARCHAR2(36) NOT NULL);

```

[145 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]