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?

The six sections below cover the checks I make before accepting an Oracle change.
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:

Separate questions, separate evidence. This diagram is a verification checklist, not a test log.
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.
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.
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:
This checks the API’s transaction behavior. It does not provide a rollback strategy for schema changes.
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.
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:
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.