How I Verify Oracle Changes Made by Codex

Posted on October 12, 2026 · 9 mins read

I built a small lab with Codex and Oracle. In it, I implemented TaskHub, a simple application for managing lists and user tasks. I describe the system in TaskHub: A Lab for AI Agents and Oracle. Here, I explain how I verify a database change before accepting it.

The previous posts covered the work leading up to this point. From Specification to Working Oracle Code: My Codex Workflow explained how I divide the specification into small implementation steps. What I Put Into a Codex Development Task covered the constraints, acceptance criteria, tests, and evidence for each step.

This post starts after Codex has applied a change. How do I know that it actually worked?

Six sections of the post, illustrated with icons for code, Oracle state, behavior, security, regression, and evidence

The six sections below cover the checks I make before accepting an Oracle change.

1. The Change Is Not Done When the Code Exists

Codex can write PL/SQL, modify database objects, and apply scripts. It can then report success. I still need to check what happened in Oracle.

Code generation is not proof that a database change works.

The source can exist while a package body is invalid. A package can compile while accepting an operation it should reject. A valid operation can work while an ownership check is missing.

I treat these as separate checks:

Code existence, Oracle validity, behavior, rejections, security, and regression require separate checks

Separate questions, separate evidence. This diagram is a verification checklist, not a test log.

2. Start with the State in Oracle

I first check that the expected objects exist in the intended schema. Then I check their status and compilation errors. A script finishing successfully is not enough.

These read-only queries illustrate the checks. I use the saved connection for the schema being inspected. The USER_ views describe that schema’s own objects.

SELECT object_name, object_type, status
FROM user_objects
WHERE status = 'INVALID'
ORDER BY object_type, object_name;

SELECT name, type, line, position, attribute, text
FROM user_errors
ORDER BY name, type, sequence;

No invalid objects does not mean all required objects exist. I also compare the expected names and types with Oracle’s object inventory. TaskHub has separate data-owner and API schemas. Checking one does not cover the other.

Oracle documents USER_OBJECTS and USER_ERRORS alongside their ALL_ equivalents. ATTRIBUTE distinguishes compilation errors from warnings.

3. Check Behavior, Including the Rejections

The Tasks / Subtasks API development stage is a useful example. It added operations to create, update, and soft-delete application tasks. Compilation alone cannot verify the hierarchy rules or status changes.

For each test, I want the setup and the expected result. I then compare the actual result and the data left by the operation. The table below describes the checks. It is not a captured test log.

Case Evidence I want to inspect
Create a valid subtask The returned identifier and the stored parent relationship.
Set DONE, then leave DONE COMPLETED_AT is set, then cleared.
Add a fourth hierarchy level The expected rejection, with no extra application task created.
Use a priority outside 1..3 The expected rejection, with no invalid value stored.
Soft-delete a parent The parent and its descendants are soft-deleted.

An error alone does not make a negative test pass. A privilege error might stop the call before it reaches the business rule. I check that the rejection matches the intended rule. I also check that the rejected operation left no unintended change.

4. Verify the Caller and the Transaction Boundary

TaskHub uses three schemas. TASKHUB_OWNER owns the tables. TASKHUB_API contains the business logic. TASKHUB_APP is the restricted database user used by the application.

A call may work through a development connection with broader permissions. That does not tell me what TASKHUB_APP can do. I check application access through that database user.

I also check which application user is set in the session context. The database user and the application user serve different purposes. I need both to interpret the security test.

The checks cover filtered reads and ownership rules. An application user should see only the permitted data. Operations on another user’s data must be rejected without exposing it.

I inspect the grants too. They should match the intended permissions. A passing API test does not prove that direct table access is restricted.

The API must also leave transaction control to the caller. For a DML operation, I check this in four steps:

  1. Make a valid change through the API.
  2. Confirm the change is visible in the same transaction.
  3. Issue a rollback.
  4. Verify that the test data has returned to its earlier state.

This checks the API’s transaction behavior. It does not provide a rollback strategy for schema changes.

5. Check What the Change Could Have Broken

The new API depends on the existing context, read views, and list operations. I run relevant regression checks against those parts too. The new feature may work while earlier behavior has broken.

I select these checks from the dependencies and public contracts affected by the change. Passing them supports the current checkpoint. It does not prove that the entire application is defect-free. A broader security review and a clean rebuild remain separate checks.

6. Inspect the Evidence Before Closing the Stage

A statement from Codex that “all tests passed” is not the evidence. The actual results of the checks are the evidence.

By evidence, I mean the recorded results I can inspect. These include query output, returned values, Oracle errors, and data-state checks. They show what ran and what happened.

For each test, I want to see:

  • The check: the script or query that ran and its test setup.
  • The context: the database connection and application user used.
  • The expectation: what should happen according to the specification.
  • The actual result: returned values or errors, plus the data state after the operation.
  • The version: the code revision that was tested.

For example, consider the test that attempts to add a fourth hierarchy level. I want to inspect the attempted operation and the error Oracle returned. I also want the query result showing that no extra application task was created. A line saying “hierarchy test: PASS” does not show those results.

If Codex fixes the implementation, the previous output describes the earlier version. The affected checks must run again. Relevant regression checks must run too.

Codex may write both the implementation and the tests. Both can repeat the same misunderstanding. I review the assertions against the specification. Rejection cases and security boundaries need particular attention.

This is the verification approach I currently use. It is not the only possible approach. It gives me a reviewable checkpoint before the next implementation stage.

Codex can execute the checks and collect their results. I decide whether the evidence is sufficient to accept the change.