Skip to content

refactor(global-db): remove persist probe and dedupe cursor authority - #649

Merged
ScriptedAlchemy merged 4 commits into
codex/tracedecay-total-redesign-planfrom
codex/globaldb-audit-fixes
Aug 22, 2026
Merged

refactor(global-db): remove persist probe and dedupe cursor authority#649
ScriptedAlchemy merged 4 commits into
codex/tracedecay-total-redesign-planfrom
codex/globaldb-audit-fixes

Conversation

@ScriptedAlchemy

Copy link
Copy Markdown
Owner

Fixes four code-quality audit findings in crates/tracedecay-global-db from the review of the collision-coverage work. One commit per finding.

Findings

B2 (blocker) — cfg(test) probe embedded in the production adapter

observation_adapter.rs carried ObservationPersistProbeV1, a probe_count! macro pair, a cfg-gated persist_probe field on GlobalDbObservationStore, and probe call sites threaded through the production persist path — the production struct's shape differed under cfg(test).

All of it is deleted. The assertion moved to a real seam: the adapter's runtime dispatch boundary is now the ObservationRuntimeDispatch trait (production impl DatabaseRuntimeClientV1; GlobalDbObservationStore<R = DatabaseRuntimeClientV1> — identical shape in every build, production only ever constructs the default). The test harness wraps that seam in CountingObservationRuntime, a counting double that forwards every read/submit unchanged. The no-rework guarantees stay proven, not weakened: zero stored-observation reads imply no stored-row decode and therefore no collision classification or payload-revision probe (both require the row), and zero submits imply no canonical command digest (every digest call site is unreachable without a stored-row read or a submit). The reworked tests keep every zero-delta assertion and add non-vacuity anchors (the first collision's stored-row read and the re-admission's own frontier cursor read are observed through the counted seam).

M1 (major) — hand-mirrored cursor-advance authority

record_refusal_with_coverage duplicated the runtime cursor-advance authority "statement for statement". There is now one spelling: repository::observation_cursor_authority in tracedecay-rusqlite-runtime (cursor read, advance-ledger record, ledger read-back + verification predicate, cursor commit). Both executors — ObservationExecutor::execute_write/execute_cursor_advance on the runtime writer's savepoint and the adapter's refusal transaction on the guarded engine transaction — execute exactly these statements. The atomicity contract is preserved exactly: marker insert, admission_refused ledger row, in-transaction ledger verification, and cursor move remain one transaction with the in-transaction frontier compare-and-set, and any failure rolls everything back. failed_coverage_advance_leaves_no_visible_refusal_marker and eof_refusal_converges_new_generation_rescans_without_reopening are green and untouched by this commit.

D9 (medium, behavioral) — swallowed constructor error

refused_scan_frontier ended in ObservationCursorAdvance::for_ordering(...).ok(), so a construction failure silently became "not at the scan frontier" — no coverage recorded, refused record re-read forever. It now returns ObservationStoreResult<Option<_>>: Ok(None) stays the not-at-frontier verdict (covered replay / stale expected view, both pinned by existing tests), and any construction failure propagates as the typed store error. The failure path is not reachable through validated writes — ObservationWrite::new already validates the exact expected→next cursor_transition_covers transition the advance re-derives from the same identity, expected cursor, and range, and AdmissionRefused with no receipt always satisfies the reason/receipt check — so no regression test can construct the failing input; the typed surfacing exists to make any future weakening of that invariant loud instead of an infinite re-read loop, and the function doc records the proof.

D6 (medium) — quadruplicated ownership-cache aggregation

reconcile_collided_observation_provenance (rebuild.rs) re-implemented the aggregation that initially populates temp.observation_projection_output_state. Both now render from one definition: output_state_aggregation_sql in state.rs (with an optional provenance filter), executed unfiltered by cache initialization and scoped to one output by the new reaggregate_output_state_for_output, which rebuild.rs's reconciliation calls. Statement semantics and index usage unchanged.

Verification

  • cargo test -p tracedecay-global-db: 399 passed, 4 failed — the failures are exactly the four known pre-existing base failures (registered_database_lease_keeps_runtime_alive_after_map_owner_drops, registered_project_graph_binding_retains_only_the_database_weak_proxy, registered_legacy_relations::…::installation_requires_typed_reset_without_mutating_legacy_profile_shape, concurrent_registered_mounts_singleflight_to_one_runtime); zero new failures, all 18 observation_collision_tests plus reset/adapter tests green.
  • cargo test -p tracedecay-rusqlite-runtime: all targets green (290 lib tests + integration targets, 0 failed).
  • cargo clippy -p tracedecay-global-db --all-targets -- -D warnings: clean.
  • cargo clippy -p tracedecay-rusqlite-runtime --all-targets -- -D warnings: clean.
  • cargo fmt -p tracedecay-global-db -- --check and cargo fmt -p tracedecay-rusqlite-runtime -- --check: clean.
  • All four commit messages pass commitlint (the .githooks/commit-msg hook was active).

Files touched are confined to crates/tracedecay-global-db and crates/tracedecay-rusqlite-runtime (the M1 seam).

The observation adapter embedded a cfg(test)-only persist probe: a
counter struct, a probe_count! macro pair, a cfg-gated field on
GlobalDbObservationStore, and call sites threaded through the
production persist path, so the production struct's shape differed
under cfg(test).

Delete the probe entirely and assert at the real seam instead: the
adapter's runtime dispatch boundary is now the ObservationRuntimeDispatch
trait (production impl: DatabaseRuntimeClientV1, identical struct shape
in every build), and the test harness wraps it in a counting double.
Zero stored-observation reads prove no decode, collision
classification, or payload-revision probe (all require the stored row),
and zero submits prove no canonical command digest; the collision tests
keep every no-rework assertion and gain non-vacuity anchors showing the
counted seam observes the very calls under assertion.
refused_scan_frontier ended in `.ok()`, so an ObservationCursorAdvance
construction failure silently became "not at the scan frontier": no
coverage recorded, and the refused record re-read forever — the exact
loop terminal refusal coverage exists to break.

Return ObservationStoreResult<Option<..>>: Ok(None) stays the
not-at-frontier verdict (covered replay, stale expected view — both
pinned by existing tests), while any construction failure now
propagates as the typed store error. For validated writes the failure
is unreachable — ObservationWrite::new already proves the exact
expected-to-next transition the advance re-derives — so no valid flow
changes; the doc records that invariant and the error path guards
against it ever being weakened.
record_refusal_with_coverage hand-mirrored the runtime cursor-advance
authority "statement for statement" — a duplicate spelling that would
drift the moment either side changed.

Extract the shared statements into one canonical set,
repository::observation_cursor_authority in tracedecay-rusqlite-runtime
(cursor read, advance-ledger record, ledger read-back verification
predicate, cursor commit). Both executors of the authority — the
runtime write path (ObservationExecutor::execute_write /
execute_cursor_advance) and the adapter's atomic refusal-marker +
coverage transaction — now execute exactly these statements; only the
transport differs (rusqlite savepoint vs guarded engine transaction).

The atomicity contract is unchanged: marker insert, admission_refused
ledger row, in-transaction ledger verification, and cursor move stay
one transaction with the in-transaction frontier compare-and-set, and
any failure rolls the whole transaction back.
reconcile_collided_observation_provenance repeated the correlated
owner-lookup subquery four times inside one INSERT, re-implementing the
aggregation that initially populates
temp.observation_projection_output_state in state.rs — two spellings of
the same ownership derivation that would drift independently.

Render both from one definition: output_state_aggregation_sql in
state.rs is now the only spelling of the aggregation, taking an
optional provenance filter. Cache initialization executes it
unfiltered; the new reaggregate_output_state_for_output executes it
scoped to one exact output, and rebuild.rs's collided-provenance
reconciliation calls that helper instead of carrying its own copy.
Statement semantics, index usage, and error operations are unchanged.
@changeset-bot

changeset-bot Bot commented Aug 22, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 6492579

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@ScriptedAlchemy
ScriptedAlchemy merged commit b445ed7 into codex/tracedecay-total-redesign-plan Aug 22, 2026
8 of 13 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6492579c68

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

/// prove the terminal-refusal fast path repeats no stored-row read (and thus
/// no decode, classification, or revision probing) and no submit (and thus no
/// canonical command digest) by counting here.
pub(crate) trait ObservationRuntimeDispatch: Clone + Send + Sync {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Remove the test-only runtime dispatch port

In every production build this abstraction has no caller beyond the forwarding DatabaseRuntimeClientV1 implementation: the file explicitly says the generic runtime exists so tests can observe it, while the only alternate implementation and constructor are cfg(test). This threads a generic through both store traits and expands the public adapter type solely for test instrumentation; keep the production adapter concrete and gather this evidence without a test-only production seam.

AGENTS.md reference: AGENTS.md:L81-L83

Useful? React with 👍 / 👎.

Comment on lines +621 to +624
after.submits - before.submits,
0,
"re-admitted terminal collision must not re-probe the payload revision"
"re-admitted terminal collision must not submit a runtime write, so it never \
canonicalizes or hashes a command again"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restore direct command-digest instrumentation

When a re-admission performs command canonicalization or hashing but exits before dispatch_submit—for example, while constructing metadata or an idempotency identity—this counter remains unchanged because CountingObservationRuntime increments it only after those digest sites. The removed probe counted digest execution directly, so this replacement no longer proves the asserted no-hash fast path and can let a rework regression pass; instrument the canonicalization boundary instead of inferring it from submission.

AGENTS.md reference: AGENTS.md:L125-L127

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant