Repository navigation
fix(OMN-19968): the llm-cost writer speaks the shared usage-source vocabulary on SQLite and Postgres - #3183
Conversation
…cabulary on SQLite and Postgres node_projection_llm_cost wrote the retired labels API/ESTIMATED/MISSING, while omnibase_infra migration 077 (OMN-10382) moved the shared usage_source_type to measured/estimated/unknown (EnumUsageSource). On any database infra has migrated, 0001's typname guard matched the shared type and created nothing, so every write of 'MISSING' or 'API' was refused; the ticket's own lab step failed 6 passed, 2 failed on the lakshman lane at 07:46Z. - row_llm_call_metrics maps provider-reported usage to measured, ESTIMATED to estimated, and MISSING/UNKNOWN/absent/unrecognised to unknown (retired labels folded in, case-insensitive). - The SQLite schema defaults to 'unknown', and existing SQLite rows are moved onto the shared vocabulary in place. - Migration 0003 renames an omnimarket-created usage_source_type's labels in place (RENAME VALUE, no table rewrite), resolving the type through search_path; a no-op where the shared vocabulary is already present. - Tests and fixtures use the shared values; a new test file pins the mapping, the SQLite reconciliation and the migration's uniqueness.
✅ Architectural Review — PASSEDErrors: 0 What this checks
No architectural violations found. Static architectural lint — no model inference (OMN-14176). |
✅ Hostile Reviewer — PASSEDBlocking findings (critical/error): 0 Gate semantics
Powered by omniintelligence.review_pairing.cli_review — node-based adversarial review via HandlerLlmCliSubprocess (OMN-8524) |
…3183 OCC companion by node_pr_lifecycle_fix_effect (OMN-13317 F1 / OMN-13990 / OMN-14285). Product PR head 6c26fd7eced89036122cc17842bd43a7947a119f.
…nimarket#3183 The declared checks were executed for real in the OmniNode-ai/omnimarket checkout at the PR head by the product-repo OCC receipt runner, and the results written append-only into this companion. Producer-minted PENDING receipts are superseded by a net-new record; no existing receipt was edited. Ticket: OMN-16859 (AC3b) Onex-Workflow: OCC Receipt Runner Onex-Run: https://github.com/OmniNode-ai/omnimarket/actions/runs/36861941150
) * evidence(OMN-19968): author OCC companion for OmniNode-ai/omnimarket#3183 OCC companion by node_pr_lifecycle_fix_effect (OMN-13317 F1 / OMN-13990 / OMN-14285). Product PR head 6c26fd7eced89036122cc17842bd43a7947a119f. * evidence(OMN-19968): self-bind OCC#12139 + rebind contract_sha256 * evidence(OMN-16859): executed test_passes receipts for OmniNode-ai/omnimarket#3183 The declared checks were executed for real in the OmniNode-ai/omnimarket checkout at the PR head by the product-repo OCC receipt runner, and the results written append-only into this companion. Producer-minted PENDING receipts are superseded by a net-new record; no existing receipt was edited. Ticket: OMN-16859 (AC3b) Onex-Workflow: OCC Receipt Runner Onex-Run: https://github.com/OmniNode-ai/omnimarket/actions/runs/36861941150 --------- Co-authored-by: omnimarket-bot <bot@omninode.ai> Co-authored-by: onexbot-occ-writer[bot] <307849072+onexbot-occ-writer[bot]@users.noreply.github.com>
|
OCC autobind rebound this PR's evidence-source stamp line to The receipt gate's own eligibility validator, run against the change-control tree the gate pins for Reported by |
…the parity tests The repo-evidence gate (OMN-20070) requires a PR that cites OMN-19968 to carry contracts/OMN-19968.yaml, with every acceptance criterion bound by binds_ac to a test_passes item naming an existing test file. AC1 binds to the rows_equal parity tests in tests/test_omn19968_writer_store_parity.py (the four writers, real SQLite adapter against real Postgres; the Postgres half skips without a Postgres). AC2 binds to the postgres_only_sql tests (a recording SQLite connection refuses $n placeholders, ::jsonb and enum casts on every writer's path). node_dod_verify --execution-audience hosted on this head: PASS, 2 of 2 verified, both behavior-proving.
…fails at the merge base The repo-evidence gate overlays a PR's tests on the merge-base source and requires every bound test to fail there. The parity tests already pass on dev (they were delivered by #3067 and #3148), so binding them read as always-pass. AC1 now binds to tests/unit/test_omn19968_usage_source_vocabulary.py, the test this change adds: against the merge-base source (2c6dabe) it fails 17 of 17, on this head it passes. AC2 is not changed by this PR and is no longer claimed here.
…ndors migration 0003 The Sibling Release Compatibility Gate (OMN-20381) refused node_projection_llm_cost/migrations/0003_usage_source_shared_vocabulary.sql: it reads the omnibase-infra pin from uv.lock and requires every node migration a change adds to be byte-identical in that release. The pin was 0.38.61, which lacks it; omnibase_infra#4420 (98620a57) vendored it and is first released in v0.38.63. Raise the floor to >=0.38.63,<0.39.0 in dependencies and override-dependencies, and refresh uv.lock for omnibase-infra only (uv 0.12.22, the version CI installs: lock revision stays 5, 10 lines change, no other package moves). The gate's comparison run locally: v0.38.61 lacks 0003, v0.38.63 is byte-identical. Onex-Lane: omn19981-evidence Onex-Session: bf37a08791cf43ccab41e737a008f469
…v0.38.63 tests/ci/test_sibling_pins_omn20001.py::test_infra_checkout_pins_match_lock failed on this PR's CI (Tests split 2/20, run 37138844983): six workflows still checked out omnibase_infra at v0.38.61 after the lock moved to 0.38.63. Move every such checkout, and the messages that name the version, to v0.38.63, and the one test that pins the overlay-parity checkout ref. These are the same edits omnimarket#3309 makes for the same pin. tests/ci, tests/seam_goldens and the pricing tests on this branch and on dev at the merge base 76e1673 fail the same 23 tests locally (release staleness and others; identical sets, environmental here) and nothing else. The pin test passes; restoring one v0.38.61 ref fails it. Onex-Lane: omn19981-evidence Onex-Session: bf37a08791cf43ccab41e737a008f469
|
Answers to the two hostile-review notes on this head (job 111263134881, both info, from gpt-oss-review):
Thank you! |
…ge-source-vocab dev raised the omnibase-infra floor to 0.38.64 (omnimarket#3293), past the 0.38.63 this branch pinned for migration 0003. Nine files conflicted on that one value (pyproject.toml, uv.lock, six workflows and one CI test); each takes dev's version, so this branch no longer changes any of them. Onex-Lane: omn19968-usage-vocab Onex-Session: b4a9c00fa6f045f4b54fca18b2cdd0e7
|
Thanks, @Patel230 (Lakshman), for omnimarket#3183 on ticket OMN-19968, which was squash-merged as 5de6e9d on 2026-10-04T23:13:51Z by the landing lane under the operator ruling of 2026-10-04T23:07:50Z that overrode the report-only landing policy for the collaborator pull requests listed in the standups ask. We really appreciate your contribution! |
… the merge base's contract does not carry repo-evidence / dod-verify refused 0ebc5ef: after #3183 merged, contracts/OMN-19968.yaml on dev binds only the usage-source vocabulary check, so every check this PR bound was "carried unchanged from the merge base" and the PR bound no evidence of its own (run 37257169127). Add a check on the read-lock tests; the selected six fail on origin/dev cce192a and pass here. Onex-Lane: omn19981-evidence Onex-Session: bf37a08791cf43ccab41e737a008f469
Dev's llm_call_metrics relabel (#3183) runs an UPDATE on every connect once that table has usage_source, which every store written by the current release does. The sqlite3 module opens a transaction before that UPDATE and leaves it open until _connect commits at the end. The usage-by-model-day reconcile sits between the two and issues BEGIN IMMEDIATE, so on such a store it raised "cannot start a transaction within a transaction": the first open after upgrading failed, and concurrent first opens (dev's #3319 test) failed 4 of 5 runs. The reconcile now commits that open transaction before taking the write lock. The relabel is idempotent and _connect committed it anyway, so nothing is lost; the new test asserts the relabel is kept, and a rollback in place of the commit fails it. Onex-Lane: omn20006-usage-page Onex-Session: d99c149d-35af-4f1e-b791-28a28187bfc4
…rite lock (#3370) * fix(OMN-19968): the llm-cost writer speaks the shared usage-source vocabulary on SQLite and Postgres node_projection_llm_cost wrote the retired labels API/ESTIMATED/MISSING, while omnibase_infra migration 077 (OMN-10382) moved the shared usage_source_type to measured/estimated/unknown (EnumUsageSource). On any database infra has migrated, 0001's typname guard matched the shared type and created nothing, so every write of 'MISSING' or 'API' was refused; the ticket's own lab step failed 6 passed, 2 failed on the lakshman lane at 07:46Z. - row_llm_call_metrics maps provider-reported usage to measured, ESTIMATED to estimated, and MISSING/UNKNOWN/absent/unrecognised to unknown (retired labels folded in, case-insensitive). - The SQLite schema defaults to 'unknown', and existing SQLite rows are moved onto the shared vocabulary in place. - Migration 0003 renames an omnimarket-created usage_source_type's labels in place (RENAME VALUE, no table rewrite), resolving the type through search_path; a no-op where the shared vocabulary is already present. - Tests and fixtures use the shared values; a new test file pins the mapping, the SQLite reconciliation and the migration's uniqueness. * test(OMN-19968): repo-owned evidence contract binding AC1 and AC2 to the parity tests The repo-evidence gate (OMN-20070) requires a PR that cites OMN-19968 to carry contracts/OMN-19968.yaml, with every acceptance criterion bound by binds_ac to a test_passes item naming an existing test file. AC1 binds to the rows_equal parity tests in tests/test_omn19968_writer_store_parity.py (the four writers, real SQLite adapter against real Postgres; the Postgres half skips without a Postgres). AC2 binds to the postgres_only_sql tests (a recording SQLite connection refuses $n placeholders, ::jsonb and enum casts on every writer's path). node_dod_verify --execution-audience hosted on this head: PASS, 2 of 2 verified, both behavior-proving. * test(OMN-19968): bind AC1 to the usage-source vocabulary test, which fails at the merge base The repo-evidence gate overlays a PR's tests on the merge-base source and requires every bound test to fail there. The parity tests already pass on dev (they were delivered by #3067 and #3148), so binding them read as always-pass. AC1 now binds to tests/unit/test_omn19968_usage_source_vocabulary.py, the test this change adds: against the merge-base source (2c6dabe) it fails 17 of 17, on this head it passes. AC2 is not changed by this PR and is no longer claimed here. * fix(OMN-19968): pin omnibase-infra 0.38.63, the first release that vendors migration 0003 The Sibling Release Compatibility Gate (OMN-20381) refused node_projection_llm_cost/migrations/0003_usage_source_shared_vocabulary.sql: it reads the omnibase-infra pin from uv.lock and requires every node migration a change adds to be byte-identical in that release. The pin was 0.38.61, which lacks it; omnibase_infra#4420 (98620a57) vendored it and is first released in v0.38.63. Raise the floor to >=0.38.63,<0.39.0 in dependencies and override-dependencies, and refresh uv.lock for omnibase-infra only (uv 0.12.22, the version CI installs: lock revision stays 5, 10 lines change, no other package moves). The gate's comparison run locally: v0.38.61 lacks 0003, v0.38.63 is byte-identical. Onex-Lane: omn19981-evidence Onex-Session: bf37a08791cf43ccab41e737a008f469 * fix(OMN-19968): the workflows check out omnibase_infra at the locked v0.38.63 tests/ci/test_sibling_pins_omn20001.py::test_infra_checkout_pins_match_lock failed on this PR's CI (Tests split 2/20, run 37138844983): six workflows still checked out omnibase_infra at v0.38.61 after the lock moved to 0.38.63. Move every such checkout, and the messages that name the version, to v0.38.63, and the one test that pins the overlay-parity checkout ref. These are the same edits omnimarket#3309 makes for the same pin. tests/ci, tests/seam_goldens and the pricing tests on this branch and on dev at the merge base 76e1673 fail the same 23 tests locally (release staleness and others; identical sets, environmental here) and nothing else. The pin test passes; restoring one v0.38.61 ref fails it. Onex-Lane: omn19981-evidence Onex-Session: bf37a08791cf43ccab41e737a008f469 * fix(OMN-19968): a read through the SQLite adapter no longer takes a write lock #3183 moved old usage_source labels onto the shared vocabulary with an UPDATE run on every connection. An UPDATE takes a write lock even when it matches nothing, so every read waited behind any writer (or failed with 'database is locked') and a read-only store raised. The relabel is now a one-time store step, like migration 0003 on Postgres: it runs once, in one transaction with its record in omnimarket_sqlite_store_steps, and a store that has recorded it opens with reads only. A read-only store is read as it is, with one warning; any other error propagates. The decision reads the adapter's own step record, not llm_call_metrics. A look-first read of that table was refused by the OMN-17446 registry hook: this module is shared by nodes that do not own the table, and a shared module deciding from another node's time-retained relation is the shape that hook guards against. Onex-Lane: omn19968-readlock-followup Onex-Session: d99c149d-35af-4f1e-b791-28a28187bfc4 * chore(OMN-19968): bump project.version to 0.4.293, past published v0.4.292 The release identity gate (OMN-16344) refuses packaged source changes on a version that is already published. v0.4.292 was released 2026-10-04T15:18Z; this matches the open bot bump omnimarket#3375 (pyproject.toml and uv.lock, identical lines). Onex-Lane: ci-fix2-OMN-19968 Onex-Session: d99c149d-35af-4f1e-b791-28a28187bfc4 * fix(OMN-19968): drop the connect-time relabel that the dev merge kept beside the recorded step omnimarket#3183 landed on dev with the relabel inside _reconcile_legacy_llm_call_metrics, which runs on every connect and so takes a write lock on every read. This branch moves it into the once-per-store step; git merged both, so the old UPDATE came back and six of the read-lock tests failed on the merged tree. Keep only the step. Dev is at 0.4.299, which is already published, and this change touches packaged source, so project.version moves to 0.4.300 (release-identity gate, OMN-16344). Onex-Lane: omn19981-evidence Onex-Session: bf37a08791cf43ccab41e737a008f469 * test(OMN-19968): bind the read-lock tests in the repo contract, which the merge base's contract does not carry repo-evidence / dod-verify refused 0ebc5ef: after #3183 merged, contracts/OMN-19968.yaml on dev binds only the usage-source vocabulary check, so every check this PR bound was "carried unchanged from the merge base" and the PR bound no evidence of its own (run 37257169127). Add a check on the read-lock tests; the selected six fail on origin/dev cce192a and pass here. Onex-Lane: omn19981-evidence Onex-Session: bf37a08791cf43ccab41e737a008f469 --------- Co-authored-by: onexbot-occ-writer[bot] <307849072+onexbot-occ-writer[bot]@users.noreply.github.com>
…timates (#3378) * feat(OMN-20006): usage-by-model-day keeps measured cost apart from estimates The Usage page must count runs whose cost was not measured and leave them out of the cost it shows (AC3), and must never show 0 for a cost nobody measured (AC4). The projection stored every call's cost as a number and had no idea how that number was obtained, so no page could do either. Each call now carries its usage_source (unknown when the event does not say, so an estimate is never taken for a measurement). Each day-and-model row serves measured_cost_usd, the sum over measured calls and NULL when there were none, and unmeasured_call_count. cost_usd and call_count keep their meaning. Migration 0002 is additive; old rows read unknown/NULL/0. The exposure now declares tenant_column, so the server scopes a read to the reading tenant instead of the page filtering rows in the browser. The local onex delegate path writes the usage rows too, keyed by the run's correlation id and dated by the terminal's emitted_at; a failure there is logged and swallowed like the call-metrics write. A local store also lacked projection_cursor, so a served read of this exposure answered 503 projection_column_missing on every local install. The store now adds the missing columns on connect and stamps the cursor on each insert and recount from a one-row sequence table, as Postgres's BIGSERIAL does from its sequence. The consumers opt-out is deleted: the omnidash Usage page is the reader. Version 0.4.294: packaged source changed (0.4.293 is published). Onex-Lane: omn20006-usage-page Onex-Session: d99c149d-35af-4f1e-b791-28a28187bfc4 * fix(OMN-20006): shorten the AC1 dod_evidence id to the 50-character limit The ticket_contract model caps dod_evidence ids at 50 characters. The AC1 id was 51, so contract-validation failed on the PR before any check ran. The id is a label only; nothing else references it. Onex-Lane: omn20006-ci Onex-Session: d99c149d-35af-4f1e-b791-28a28187bfc4 * test(OMN-20006): unpack the tenant-scoped exposure by length, not by tuple target CodeQL flagged the single-target tuple unpack of the loader's result as a length mismatch (alert on tests/test_omn19978_usage_by_model_day.py:386) and failed the PR's CodeQL check. The sibling test already asserts the length and indexes, so this one does the same and still fails if the loader returns two exposures. Onex-Lane: omn20006-ci Onex-Session: d99c149d-35af-4f1e-b791-28a28187bfc4 * fix(OMN-20006): promote ModelUsageCallEvent to omnimarket.models so the dispatch port stops reaching into a sibling node The local delegation dispatch port imported ModelUsageCallEvent from node_projection_usage_by_model_day.models, tripping test_no_new_cross_node_model_reach_ins. The model now lives in omnimarket.models.model_usage_call_event; the node's module re-exports it. Onex-Lane: omn20006-reachin Onex-Session: d99c149d-35af-4f1e-b791-28a28187bfc4 * chore(OMN-20006): bump to 0.4.300, past the published 0.4.299 After merging dev, v0.4.299 is reachable from this branch and dev itself reads 0.4.299, so the release-identity gate (OMN-16344) refuses a src/ change at that version: check_release_identity.py --base origin/dev exited 1 at the merge commit and 0 after this bump. 0.4.300 is the number the other open omnimarket PRs and the post-release bump PR already use. Onex-Lane: omn20006-usage-page Onex-Session: d99c149d-35af-4f1e-b791-28a28187bfc4 * fix(OMN-20006): an existing local store opens again after the dev merge Dev's llm_call_metrics relabel (#3183) runs an UPDATE on every connect once that table has usage_source, which every store written by the current release does. The sqlite3 module opens a transaction before that UPDATE and leaves it open until _connect commits at the end. The usage-by-model-day reconcile sits between the two and issues BEGIN IMMEDIATE, so on such a store it raised "cannot start a transaction within a transaction": the first open after upgrading failed, and concurrent first opens (dev's #3319 test) failed 4 of 5 runs. The reconcile now commits that open transaction before taking the write lock. The relabel is idempotent and _connect committed it anyway, so nothing is lost; the new test asserts the relabel is kept, and a rollback in place of the commit fails it. Onex-Lane: omn20006-usage-page Onex-Session: d99c149d-35af-4f1e-b791-28a28187bfc4 * fix(OMN-20006): run the usage-by-model-day reconcile as a one-time store step #3370 (OMN-19968) turned the llm_call_metrics relabel into a one-time store step: it runs in its own write transaction that commits it with its row in omnimarket_sqlite_store_steps, a store that has recorded it opens with reads only, a read-only store is read as it is with a warning, and a busy store raises. This PR's usage reconcile still ran as its own connect-time write, outside that mechanism, so a read-only store written before this change raised "attempt to write a readonly database" on every read of every table. The reconcile is now the store step omn20006_usage_by_model_day_measured_cost (the SQLite counterpart of usage_by_model_day migration 0002). _connect runs every pending step through one _apply_store_steps: each step's columns or relabel and its record commit together, the columns are read again under the step's write lock so racing first opens add each once, a read-only store gets one warning naming every step it lacks, and any other error raises. The schema-probe check and the in_transaction commit guard are gone; the guard was dead once #3370 moved the relabel out of the connect-time DDL, and its comment described code that no longer exists. Tests: tests/unit/projection/test_sqlite_usage_by_model_day_store_step_omn20006.py (five fail on the previous head). The OMN-19968 vocabulary tests read only their own step's record, since the store now records a second step. Onex-Lane: omn20006-usage-page Onex-Session: d99c149d-35af-4f1e-b791-28a28187bfc4 * fix(OMN-20006): book each delegation attempt's usage to its own model The local path wrote one usage call per run: the final model, the final attempt's tokens and the run's cumulative cost, always as measured. On an escalated run that put every rejected attempt's spend on the model that answered, so the Usage page's cost per model was wrong for that run even though the total was right, and an attempt whose cost was not measured was counted as measured because the last one was. The dispatch loop now records what each banked call consumed (model, tokens, cost, usage source) at the same two points it adds to the run's cumulative cost, so the two cannot drift. Each call that reached a provider becomes its own usage call with its own usage source; the per-model sum still equals the delegation row's cost_usd. A call that never reached a provider carries no tokens and no cost and is not a usage call. A single-call run keeps the correlation id as its key; several calls take <correlation id>:<n> in attempt order. Onex-Lane: omn20006-usage-page Onex-Session: d99c149d-35af-4f1e-b791-28a28187bfc4 * fix(OMN-20006): usage tokens follow metering's one definition AC1 binds the Usage page's token totals to onex metering --json, which reads delegation_events and so counts only the deciding attempt's tokens. Booking every attempt's tokens made an escalated run's usage tokens larger than metering's for the same window, which is AC1's falsifier. Cost stays split per attempt and per model; tokens now go on the deciding attempt's call only, and earlier attempts' calls carry 0. The token columns are NOT NULL on both stores, so 0 cannot be told apart from a measured zero without a schema change. Counting escalated-from attempts' tokens belongs in the metering summary, so the CLI and the page move together; that is a follow-up, not this change. Onex-Lane: omn20006-usage-page Onex-Session: d99c149d-35af-4f1e-b791-28a28187bfc4 * build(OMN-20006): pin omnibase-infra 0.38.67, the first release vendoring usage_by_model_day 0002 The Sibling Release Compatibility Gate (OMN-20381) refuses a node migration until the pinned omnibase_infra release carries it byte-identical. 0.38.67 (tag 2bbaaeb) vendors 0002_usage_by_model_day_measured_cost.sql via omnibase_infra#4559; 0.38.66 does not. The lock moves omnibase-infra only. Onex-Lane: omn20006-usage-page Onex-Session: d99c149d-35af-4f1e-b791-28a28187bfc4 * fix(OMN-20006): the clean-install delegate probe asks onex delegate for --json omnibase_infra#4609 (OMN-20124, in 0.38.67) prints the plain answer when stdout is redirected; JSON now comes only with --json. The probe parsed stdout as JSON without asking for it, so on 0.38.67 every field read None and the Customer Clean-Install and Sibling Release delegate gates failed on dev and on every PR. --json exists in 0.38.66 and 0.38.67, so the probe now works on both: local runs FAIL unchanged on 0.38.67, PASS with --json on 0.38.67 and on 0.38.66. Onex-Lane: omn20006-usage-page Onex-Session: d99c149d-35af-4f1e-b791-28a28187bfc4 * ci(OMN-20006): every omnibase_infra checkout pins v0.38.67, matching the lock The 0.38.67 bump moved pyproject.toml and uv.lock but left seven workflow and test references on v0.38.66, so test_infra_checkout_pins_match_lock failed (Tests split 2/20). The same files the 0.38.66 bump touched (omnimarket#3417) now name v0.38.67; tests/ci/test_sibling_pins_omn20001.py and test_ci_bus_overlay_parity.py pass (29). Onex-Lane: omn20006-usage-page Onex-Session: d99c149d-35af-4f1e-b791-28a28187bfc4 * fix(OMN-20006): store step rolls back any failure but catches only the read-only one CodeQL flagged the store step's except block (alert 1545), and our merge rule needs every review thread resolved. It caught BaseException to roll back, then re-raised everything except a read-only store. It now catches sqlite3.OperationalError for the read-only case, and keeps a bare "except BaseException: rollback; raise" so any other failure, an interrupt included, still releases the write lock before it propagates. The behaviour is unchanged. That rollback was never pinned: removing it passed every test. A new test holds the error and checks another writer can take the lock at once; it fails with "database is locked" when the rollback is removed. The thread-safety test now records Exception, not BaseException (alert 1546). Onex-Lane: omn20006-usage-page Onex-Session: d99c149d-35af-4f1e-b791-28a28187bfc4 --------- Co-authored-by: onexbot-occ-writer[bot] <307849072+onexbot-occ-writer[bot]@users.noreply.github.com>
Summary
node_projection_llm_costnow writes the shared usage-source vocabulary (measured/estimated/unknown) on both stores. It used to write the retiredAPI/ESTIMATED/MISSING, which every database omnibase_infra has migrated refuses. That is why this ticket's own lab step failed (OMN-19968, Amendment 2, AC8–AC11). Merges after OmniNode-ai/omnibase_infra#4420, which vendors this PR's migration.What changed
src/omnimarket/nodes/node_projection_llm_cost/handlers/row_llm_call_metrics.py:_usage_source()maps provider-reported usage tomeasured,ESTIMATEDtoestimated, andMISSING/UNKNOWN/ absent / unrecognised tounknown. The retired labels are folded in case-insensitively.usage_is_estimatedderives from it. The docstring that still described the old mapping is corrected.src/omnimarket/projection/sqlite_database.py:usage_sourcedefaults to'unknown', and existing SQLite rows carrying a retired label are moved onto the shared vocabulary in place.src/omnimarket/nodes/node_projection_llm_cost/migrations/0003_usage_source_shared_vocabulary.sql(new): renames an omnimarket-createdusage_source_type's labels in place (RENAME VALUE, no table rewrite) and sets the default to'unknown'. The type is resolved throughsearch_path(to_regtype), because 0001'stypnameguard matched a same-named type in any schema. That is how an infra-migrated database ended up rejecting this writer. On a database that already carries the shared vocabulary it changes nothing.tests/unit/test_omn19968_usage_source_vocabulary.py(17 cases) pins the mapping, the SQLite schema default and reconciliation, the migration's in-place renames and the migration number's uniqueness.Grepped for every remaining use of the retired values (spec approach step 2). Left on purpose: the reconcile
CASEinsqlite_database.py, the test inputs that feedAPI/ESTIMATEDto prove the mapping, a comment in savings migration 087 that quotes a producer's wire label, andEnumUsageSource._missing_(src/omnimarket/enums/enum_usage_source.py, from OMN-10382), whose legacy-alias table maps the same old labels to the same shared values this writer now uses. No reader treats'API'as a meaning of its own.How it was verified
Commit
6c26fd7ec(signed,G), ondevc603479d9.RED then GREEN, same base: the 8 changed test files fail on unfixed
dev(35 failed, 92 passed, including 17/17 of the new file) and pass on this branch (127 passed, re-run on6c26fd7ec).The tests can fail (AC11): two mutations in the worktree only, each restored byte-identical (
git hash-objectchecked):apiback toestimated→ 5 tests fail;MISSINGtoestimated→ 1 test fails.Related suites, dev versus branch at the same sha: every test file that touches
llm_call_metrics,usage_source,sqlite_databaseornode_projection_llm_cost(60 files) ondevce2f9cfbaand on the branch once2f9cfba: dev 1015 passed, branch 1032 passed (+17, the new file). The same single failure on both,tests/integration/test_cost_event_publisher_kafka.py::test_idempotency_key_is_stable_on_reprocess, is environmental: no Kafka atlocalhost:19092.Lab, the ticket's own step (AC10):
tests/test_omn19968_writer_store_parity.pyon the lakshman lane's PostgreSQL 16 on .201, in a throwaway container on the lane network (2026-10-01T10:51:49Z): 8 passed, 0 failed. The same file with the same method on unfixeddevat 07:46Z: 6 passed, 2 failed (invalid input value for enum usage_source_type: "MISSING").Migration 0003 on real PostgreSQL 16.15, lakshman lane (AC9), 10:08:06Z, throwaway databases dropped afterwards: 14 of 14 assertions in 4 starting states:
'unknown','API'refused afterwards, idempotent;Mutation control: removing the
MISSINGrename fails 3 assertions.mypy src/omnimarket/ --strict: no issues in 3966 files.ruff checkandruff format --check: clean.scripts/ci/check_wire_compatibility.pyover the changed files:WIRE_COMPAT_NO_WIRE_CHANGE. Positive control: a wire model file givesWIRE_COMPAT_PASS.scripts/check_release_identity.py --base origin/dev: 0.4.272 ahead of the published 0.4.271, so no bump is needed.check_node_metadata_dependencies.py: PASS.node_runtime_sweep --import-check: exit 0.Update 2026-10-03, the pin (commit
0e413dfbe, signedG): the Sibling Release Compatibility Gate (OMN-20381) refused migration 0003 because the pin, 0.38.61, is a release without it. The floor is nowomnibase-infra>=0.38.63,<0.39.0in both dependencies and override-dependencies; omnibase_infra#4420 (98620a57) is first released inv0.38.63.uv.lockwas refreshed for omnibase-infra only with uv 0.12.22, the version CI installs: revision stays 5, 10 lines change, no other package moves;uv lock --checkpasses.v0.38.61lacksdocker/migrations/forward/nodes/node_projection_llm_cost/0003_usage_source_shared_vocabulary.sql;v0.38.63carries it byte-identical.-k "llm_cost or llm_call or usage_source or metering or parity",-m "not kafka and not integration") on dev76e1673d0and on this branch merged with it: dev 795 passed, 5 skipped, 0 failed; branch 816 passed, 1 skipped, 0 failed."api"synonym fails 3 of the 17 vocabulary cases; restored, 17 pass.c47936adcand94eb9c2a1, were made by GitHub's update-branch and are signed by GitHub (verified: trueon the commits API); the local check cannot verify GitHub's key.Overlap-Reviewed: #3172 — both edit tests/test_projection_handlers.py in separate hunks: #3172 adds
model_cloud_baselineto two delegate-skill fixtures (near lines 488 and 847); this changes one expected usage_source value in TestLlmCostHandler (near line 208) from 'MISSING' to 'unknown'. No shared lines; each is needed for its own change and they merge in either order.Overlap-Reviewed: #3309 — it raises the same omnibase-infra floor to 0.38.63 for the repo (OMN-17427). This PR needs that floor for its own migration and cannot wait on #3309, which is red on other checks; the two produce the same pin, so whichever merges second takes either side of the pyproject and uv.lock hunks.
Overlap-Reviewed: #3308 — it bumps omnimarket's own version line in pyproject.toml and uv.lock (0.4.284 to 0.4.285); this PR changes the omnibase-infra dependency lines. Different lines, both needed.
Overlap-Reviewed: #3245 — it bumps omnimarket's own version line (0.4.282 to 0.4.283); same reasoning as #3308.
Overlap-Reviewed: #3293 — it adds nullable
finish_reasonandtruncatedtodelegation_eventsinsqlite_database.py; this PR changes onlyllm_call_metricsthere. Different tables, both needed.Failure paths
n/a: this change writes no receipt, verdict or report.
Open defects
none
Local gates
--no-verify, noSKIP=, no--no-gpg-sign, nocore.hooksPathoverride. Every pre-commit and pre-push hook ran.The pre-commit dependency health gate first failed because it ran under the system Python 3.9 (
datetime.UTCmissing). It passed once the worktree's own venv was first onPATH, as the workflow rules require; no hook was skipped.Not in this change
node_projection_tenant_credentials's SQLite path. Per the ticket's Amendment 1 it is proposed to move to OMN-19985, pending Jonah. AC7's reply on the ticket waits for Lakshman's YES.savings_estimates.usage_sourceand any other table's vocabulary (out of scope in the plan).Evidence-Ticket: OMN-19968
Evidence-Source: OCC#12273