Retrospective self-correction miner (sprint 3.97): finds the 'caught mistake -> mechanical fix' shape across the already-indexed, already-redacted session-transcripts corpus, counts it, pairs each error with its narrated fix where one exists, and persists bounded candidates -- never auto-filing anything.
| Tier | tools |
| Role | unclassified (baselined) |
| Path | crates/tools/session-error-audit |
| Edition | 2021 |
| Targets | tools-session-error-audit, tools_session_error_audit, cli_test |
| Public items | 17 across 3 modules |
| Tests | 20 |
What it is for
tools-session-error-audit (sprint 3.97): finds the "caught mistake -> mechanical fix" shape retrospectively across the already-indexed, already-redacted session-transcripts corpus. See the sprint doc (docs/userstories/sprint-3.97-session-error-audit.md) for the full design.
Capabilities
AssistantChunk
Row types shared by scan.rs (pure pairing logic) and persist.rs (the
| Item |
|---|
pub struct AssistantChunk |
ErrorHit
Row types shared by scan.rs (pure pairing logic) and persist.rs (the
| Item |
|---|
pub struct ErrorHit |
PairedCandidate
Row types shared by scan.rs (pure pairing logic) and persist.rs (the
| Item |
|---|
pub struct PairedCandidate |
SignalSeed
Row types shared by scan.rs (pure pairing logic) and persist.rs (the
| Item |
|---|
pub struct SignalSeed |
persist (other)
US-3.97.1/3.97.2's write side: the error_candidate upsert against
| Item |
|---|
pub const MODULE_NAME: & str |
async fn apply_migrations(pool : & PgPool) -> Result <u32, application_core::MigrationError> |
async fn status_of(pool : & PgPool, source_ref : & str, chunk_id : Uuid, error_signal : & str,) -> Result <(String, Option <String>), sqlx::Error> |
PersistReport
US-3.97.1/3.97.2's write side: the error_candidate upsert against
| Item |
|---|
pub struct PersistReport |
async fn upsert_candidates(pool : & PgPool, candidates : & PairedCandidate, vocabulary_version : & str,) -> Result <PersistReport, sqlx::Error> |
scan (other)
US-3.97.1/3.97.2: the read-side scan + pairing logic. Pure where
| Item |
|---|
fn parse_signal_seeds(tsv : & str) -> Vec <SignalSeed> |
fn find_error_hits(chunks : & AssistantChunk, signals : & SignalSeed) -> Vec <ErrorHit> |
fn pair_fixes(errors : & ErrorHit, chunks : & AssistantChunk, fix_signals : & SignalSeed, window : i32,) -> Vec <PairedCandidate> |
fn dedup_by_content_hash(chunks : Vec <AssistantChunk>) -> Vec <AssistantChunk> |
pub const DEFAULT_CHUNK_LIMIT: i64 |
async fn latest_indexed_at(pool : & PgPool,) -> Result <Option <chrono::DateTime <chrono::Utc>>, sqlx::Error> |
ScanReadError
US-3.97.1/3.97.2: the read-side scan + pairing logic. Pure where
| Item |
|---|
pub enum ScanReadError |
async fn load_assistant_chunks(pool : & PgPool, limit : i64,) -> Result <Vec <AssistantChunk>, ScanReadError> |
How to use it
No examples/ target and no doctest in this crate's rustdoc. The tests listed under Verification are the closest executable usage.
Module structure
tools_session_error_audit
modelpersistscan
flowchart TD n_tools_session_error_audit["tools_session_error_audit"] n_tools_session_error_audit --> n_model["model"] n_tools_session_error_audit --> n_persist["persist"] n_tools_session_error_audit --> n_scan["scan"]
Public surface
`model`
| Item | What it is |
|---|---|
pub struct SignalSeed | One docs/reference/session-error-signals.tsv / session-fix-signals.tsv row: phrase\tcategory\tadded_at\tprovenance |
pub struct AssistantChunk | One assistant-role knowledge_chunk row, as read from tools_org_knowledge |
pub struct ErrorHit | One error signal hit, before fix-pairing. |
pub struct PairedCandidate | A ErrorHit plus whatever fix-pairing found (or explicitly didn't -- paired = false is a stored fact, never an omitted row, per US-3.97.2's own AC). |
`persist`
| Item | What it is |
|---|---|
pub const MODULE_NAME: & str | This story's own module name in forge_module_migrations (application_core::apply_module_migrations's per-module namespace) -- distinct from sprint 3.96's "org-knowledge-corpus"/ "infrastructure-knowledge-index" modules in the SAME shared forge_corpus_source database. |
async fn apply_migrations(pool : & PgPool) -> Result <u32, application_core::MigrationError> | Apply this story's own migration into pool (already the forge_corpus_source connection) |
pub struct PersistReport | What one scan run's persistence pass did. |
async fn upsert_candidates(pool : & PgPool, candidates : & PairedCandidate, vocabulary_version : & str,) -> Result <PersistReport, sqlx::Error> | Upsert every paired candidate into error_candidate, one transaction (Gate 1.5.6 §4: any per-row error rolls the WHOLE batch back, same contract as sprint 3.96's corpus ingest commands) |
async fn status_of(pool : & PgPool, source_ref : & str, chunk_id : Uuid, error_signal : & str,) -> Result <(String, Option <String>), sqlx::Error> | Read one candidate's (status, filed_as) back -- used by tests (and stats) to prove a rescan never clobbers a human-reviewed row |
`scan`
| Item | What it is |
|---|---|
fn parse_signal_seeds(tsv : & str) -> Vec <SignalSeed> | Parse phrase\tcategory\tadded_at\tprovenance rows (#-prefixed and blank lines skipped) -- same shape/skip rules as sprint 3.96's docs/reference/*.tsv seed-file parsers (ontology.rs::parse_vocabulary, edges.rs::parse_capability_index_crates) |
fn find_error_hits(chunks : & AssistantChunk, signals : & SignalSeed) -> Vec <ErrorHit> | Case-insensitive substring match of every seed phrase against every chunk |
fn pair_fixes(errors : & ErrorHit, chunks : & AssistantChunk, fix_signals : & SignalSeed, window : i32,) -> Vec <PairedCandidate> | For each error hit, search the SAME source_ref's chunks with turn_index in (error.turn_index, error.turn_index + window] (a fix narration comes AFTER the mistake is caught, never at or before it) for the first fix-signal match, ordered by turn_index (nearest fix wins) |
fn dedup_by_content_hash(chunks : Vec <AssistantChunk>) -> Vec <AssistantChunk> | Edge case 3: subagent/parent duplication -- de-dup by content_hash, keeping the first-seen chunk per hash (stable input order) |
pub const DEFAULT_CHUNK_LIMIT: i64 | Gate 1.5.6 §1: bounded LIMIT on every read query against tools_org_knowledge -- this crate is read-only there and never writes back. |
pub enum ScanReadError | — |
async fn load_assistant_chunks(pool : & PgPool, limit : i64,) -> Result <Vec <AssistantChunk>, ScanReadError> | Load every assistant-role knowledge_chunk row for corpus = 'session-transcripts', bounded by limit and QUERY_TIMEOUT -- the ONLY read this crate ever runs against tools_org_knowledge (US-3.97.1's own AC: the meta->>'role'='assistant' filter, invariant: never reads raw session JSONL, only this already-redacted index) |
async fn latest_indexed_at(pool : & PgPool,) -> Result <Option <chrono::DateTime <chrono::Utc>>, sqlx::Error> | The corpus's own staleness high-water mark -- reported every run (edge case 4: never a silent stale scan) |
No pub use re-exports: every item above is declared in this crate.
Boundary
Reaches into application.
Shares tier tools with 84 other crates: tools-advisory-reach, tools-archive-guard, tools-artifact-scaffold, tools-ask-ai-core, tools-ask-ais, tools-ask-gemini, tools-book, tools-book-report, … (84 total).
_What this crate deliberately does NOT own is a judgment. No committed registry records one for it, so none is stated here._
Where it sits
| Tier (ontology) | tools |
| Architectural role (taxonomy) | unclassified (baselined) |
| Location | crates/tools/session-error-audit |
| Vocabulary in force (lexicon) | current |
Tier flow. Which tiers this crate's own edges cross.
flowchart LR n_tools["tools"] --> n_application["application"]
Dependencies
Runtime, in this workspace.
| Crate | Tier | Optional | Only on |
|---|---|---|---|
| `application-core` | application | no | always |
Runtime, from outside the workspace.
| Crate | Requirement | Features | Optional | Only on |
|---|---|---|---|---|
chrono | ^0.4 | serde | no | always |
clap | ^4 | derive | no | always |
serde | ^1 | derive, derive | no | always |
serde_json | ^1 | — | no | always |
sqlx | ^0.8 | runtime-tokio, postgres, chrono, uuid, json | no | always |
thiserror | ^2 | — | no | always |
tokio | ^1 | full, macros, rt-multi-thread | no | always |
url | ^2 | — | no | always |
uuid | ^1 | v4, v7, serde, js, v4, serde | no | always |
Development, in this workspace.
| Crate | Tier | Optional | Only on |
|---|---|---|---|
| `foundation-test-support` | foundation | no | always |
| `tools-cli-conformance` | tools | no | always |
Build. None.
Depended on by. Nothing in this workspace.
Signal flow — what reaches this crate, and what it reaches.
flowchart LR SELF["tools-session-error-audit"] SELF -->|development| n_foundation_test_support["foundation-test-support"] SELF -->|development| n_tools_cli_conformance["tools-cli-conformance"] SELF -->|runtime| n_application_core["application-core"] classDef self fill:#1f883d,stroke:#1f883d,color:#fff; class SELF self;
Feature flags
No Cargo features are defined: every capability is unconditional, so no consumer can receive a half-wired crate.
Targets
| Kind | Name | Source |
|---|---|---|
| bin | tools-session-error-audit | `src/main.rs` |
| lib | tools_session_error_audit | `src/lib.rs` |
| test | cli_test | `tests/cli_test.rs` |
Error model
| Error type | Named by |
|---|---|
ScanReadError | load_assistant_chunks |
Operational characteristics
| Property | Evidence |
|---|---|
| async public surface | yes |
| async runtime | yes |
| database access | yes |
| network I/O | none detected |
| unsafe code | none detected |
| environment variables | yes |
No unsafe block, unsafe fn, unsafe impl or unsafe trait was found by the parser anywhere in this crate's source.
Configuration
| Variable | Read in |
|---|---|
DATABASE_URL | src/persist.rs |
FORGE_CORPUS_SOURCE_APP_DB | src/main.rs |
ORG_KNOWLEDGE_DB | src/main.rs |
TEST_DATABASE_URL | src/persist.rs |
Related capabilities
No workspace crate depends on this one.
Verification
| Kind | Count |
|---|---|
| Unit tests | 19 |
| Integration tests | 1 |
| Examples | 0 |
| Doctests | 0 |
Evidence by module. How often each public module is named by something executable.
| Module | Tests | Examples | Consumers |
|---|---|---|---|
model | 4 | 0 | 0 |
persist | 5 | 0 | 0 |
scan | 8 | 0 | 0 |
What the tests establish, by name:
scan_finds_and_persists_the_real_paired_candidate_then_stats_reports_it—tests/cli_test.rscli_definition_conforms—src/main.rsread_seed_file_errors_loudly_on_a_missing_file—src/main.rsread_seed_file_reads_a_real_small_file—src/main.rsread_seed_file_refuses_a_file_over_the_cap—src/main.rsupsert_is_idempotent_and_never_clobbers_human_set_status—src/persist.rsupserted_count_is_zero_when_the_batch_rolls_back—src/persist.rsdedup_by_content_hash_keeps_first_occurrence—src/scan.rsexcerpt_around_stays_bounded_on_a_long_chunk—src/scan.rsfind_error_hits_finds_no_match_when_absent—src/scan.rsfind_error_hits_locates_the_correct_span_when_lowercasing_changes_byte_length—src/scan.rsfind_error_hits_matches_case_insensitively—src/scan.rsload_assistant_chunks_reads_the_real_corpus_assistant_only—src/scan.rsload_assistant_chunks_respects_the_limit_bound—src/scan.rslower_with_map_round_trips_a_byte_length_changing_character—src/scan.rspair_fixes_finds_the_nearest_forward_match_within_window—src/scan.rspair_fixes_never_matches_backward_or_at_the_error_turn_itself—src/scan.rspair_fixes_only_searches_the_same_source_ref—src/scan.rspair_fixes_out_of_window_stays_unpaired_explicitly—src/scan.rsparse_signal_seeds_skips_comments_and_blanks—src/scan.rs
Documentation coverage
| Measure | Documented | Total |
|---|---|---|
| Public items with rustdoc | 16 | 17 |
Public modules with a //! block | 3 | 3 |
pie showData
title Public items with rustdoc
"Documented" : 16
"No rustdoc detected" : 1
Metrics
| Metric | Value |
|---|---|
| Rust source files | 5 |
| Source lines | 1336 |
| Code lines | 1048 |
| Public API items | 17 |
| Public modules | 3 |
| Tests | 20 |
| Examples | 0 |
| Cargo features | 0 |
| Direct runtime dependencies | 10 |
| Workspace reverse dependencies | 0 |
pie showData
title Public API by kind
"constant" : 2
"enum" : 1
"function" : 9
"struct" : 5
pie showData
title Rust source composition
"Code" : 1048
"Blank or comment" : 288
Generation
Rendered by tools-corpus corpus readme from repository evidence alone, renderer schema 2, lexicon current. No model, network service or database was consulted. Regenerate with tools-corpus corpus readme --write; verify with --check.