From 6840b928f95c20ab3b64c579bbce1b5e30e9e158 Mon Sep 17 00:00:00 2001 From: "claude@clouddev1" Date: Thu, 28 May 2026 12:39:25 +0000 Subject: [PATCH] =?UTF-8?q?test:=20/runda=20round=202=20=E2=80=94=20pin=20?= =?UTF-8?q?TeachingEcho=20kind=20+=20cat-3=20prose=20wiring?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Second Devil's-Advocate pass over the now-complete ADR-0038 closes three minor test-coverage gaps the polish (2aab457) left behind. No production code changes; src/app.rs only, +98 lines of tests. * bucket_a_success_events_render_the_teaching_echo_beneath_ok and bucket_b_multi_line_echo_renders_one_line_per_statement_beneath_ok only checked line *text*. After the polish, every echo line is pushed via `push_teaching_echo` and carries `OutputKind::TeachingEcho` — the kind is what makes `ui::render_output_line` fire the dim-prefix + advanced-lex branch. Without a kind assertion, a future refactor that regressed `push_teaching_echo` to emit `System` would leave the text intact but silently break the styling. The `assert_echo_beneath_ok` helper now pins kind == TeachingEcho on every event arm covered by the bucket_a test, and the bucket_b test asserts the same for each of the three multi-statement lines. * add_column_client_side_notes_render_as_category_three_prose (new) pins the broader-scope polish: `handle_dsl_add_column_success`'s illuminating client_side_notes (shortid / serial auto-fill, per `client_side.auto_fill_*` keys) now route through `push_category_three_prose`, producing a System line with a whole-text Hint span. The user-confirmed scope extension was recorded in ADR-0038's Status block; this test makes the wiring enforceable. The closely-related caveat path was already pinned by polished_echo_carries_teaching_echo_kind_and_caveat_a_hint_span; this completes the cat-3 prose coverage symmetrically. Tests: 2020 passed / 0 failed / 1 ignored (pre-existing); clippy clean (`--all-targets -D warnings`, nursery). Nothing to escalate. --- src/app.rs | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/src/app.rs b/src/app.rs index 4ff1832..d503771 100644 --- a/src/app.rs +++ b/src/app.rs @@ -3011,6 +3011,19 @@ mod tests { .expect("an echo line"); assert_eq!(echo_idx, ok_idx + 1, "echo sits immediately beneath [ok]: {texts:?}"); assert!(texts[echo_idx].contains(expected), "echo carries the SQL: {texts:?}"); + // ADR-0038 §4 polish: every success arm now wires the echo as + // `OutputKind::TeachingEcho` so `ui::render_output_line` fires + // the dim-prefix + advanced-lex custom branch. Pinning this + // here guards every event-arm wiring covered by this test — + // a future refactor that regressed `push_teaching_echo` to + // emit `System` would leave the text intact but break the + // styling, and would be caught here. + assert_eq!( + app.output[echo_idx].kind, + OutputKind::TeachingEcho, + "echo line carries TeachingEcho kind: {:?}", + app.output[echo_idx], + ); } fn empty_data() -> DataResult { @@ -3122,6 +3135,79 @@ mod tests { assert_echo_beneath_ok(&app, "ALTER TABLE T ALTER COLUMN c SET DATA TYPE text"); } + #[test] + fn add_column_client_side_notes_render_as_category_three_prose() { + // ADR-0038 §4 polish (broader scope): the existing illuminating + // `client_side_notes` on an `AddColumnResult` (e.g. the shortid + // / serial auto-fill messages) now route through + // `push_category_three_prose` — a System line with a whole-text + // Hint span — so every category-3 prose line renders dim + // consistently per §6, not just the new DontConvert caveat. + // + // The broader scope was user-confirmed in the polish session + // (see ADR-0038 Status); this test pins that wiring so a + // regression to plain `note_system` would be caught. + use crate::db::{AddColumnResult, ColumnDescription}; + + let mut app = App::new(); + app.update(AppEvent::DslAddColumnSucceeded { + command: Command::AddColumn { + table: "Customers".to_string(), + column: "code".to_string(), + ty: Type::ShortId, + not_null: false, + unique: false, + default: None, + check: None, + }, + result: AddColumnResult { + description: TableDescription { + name: "Customers".to_string(), + columns: vec![ColumnDescription { + name: "code".to_string(), + user_type: Some(Type::ShortId), + sqlite_type: "TEXT".to_string(), + notnull: false, + primary_key: false, + unique: false, + default: None, + check: None, + }], + outbound_relationships: Vec::new(), + inbound_relationships: Vec::new(), + indexes: Vec::new(), + unique_constraints: Vec::new(), + check_constraints: Vec::new(), + }, + // A representative illuminating note — the wording is + // the one the worker would emit via the + // `client_side.auto_fill_add_shortid` i18n key. + client_side_notes: vec![ + "[client-side] 5 row(s) given auto-generated shortid values. In raw SQL this would need an explicit UPDATE to populate.".to_string(), + ], + }, + echo: None, // simple-mode submission, no echo + }); + + let note_line = app + .output + .iter() + .find(|l| l.text.starts_with("[client-side]")) + .expect("the illuminating client_side note"); + assert_eq!(note_line.kind, OutputKind::System); + let runs = note_line + .styled_runs + .as_ref() + .expect("client_side note carries a styled-runs payload after the polish"); + assert_eq!(runs.len(), 1); + assert_eq!(runs[0].class, OutputStyleClass::Hint); + assert_eq!( + runs[0].byte_range, + (0, note_line.text.len()), + "the dim span covers the whole prose body — same shape as the caveat", + ); + } + #[test] fn polished_echo_carries_teaching_echo_kind_and_caveat_a_hint_span() { // ADR-0038 §4 styled-runs polish: the App-side wiring places @@ -3310,6 +3396,18 @@ mod tests { texts[ok_idx + 2].contains("Executing SQL: DROP INDEX Customers_Email_Day_idx"), "second echo line: {texts:?}", ); + // ADR-0038 §4 polish: every one of the multi-statement echo lines + // carries TeachingEcho — the polish styling fires per line. A + // regression that pushed the multi-line case as System would + // leave the text intact but break the per-line styling. + for (offset, label) in [(1, "first"), (2, "second"), (3, "third")] { + assert_eq!( + app.output[ok_idx + offset].kind, + OutputKind::TeachingEcho, + "{label} echo line carries TeachingEcho: {:?}", + app.output[ok_idx + offset], + ); + } assert!( texts[ok_idx + 3] .contains("Executing SQL: ALTER TABLE Customers DROP COLUMN Email"),