Week 16 of 2026

Development log of Tad Better Behavior

Allow an optional caption for snippet observations

On by Tad Lispy

It's often useful to explain what the snippet is about. A dedicated caption should be better than sending a text observation right before the snippet. In HTML or other rich export formats it can be rendered in a pretty and semantically correct way, i.e. with structural connection to the snippet.

index 96dc34a..eee3d46 100644
--- a/samples/basic.py
+++ b/samples/basic.py
@@ -58,8 +58,11 @@ def step_implementation_06(word: str, reverse: str, **kwargs):
=@step("The following tables map words to their lengths")
=def step_implementation_07(**kwargs):
=    for table in kwargs["tables"]:
-        send_text(f"Received a table with {len(table)} x {len(table[0])} cells")
-        send_snippet("json", json.dumps(table, indent=2))
+        send_snippet(
+            "json",
+            json.dumps(table, indent=2),
+            caption = f"A {len(table)} x {len(table[0])} table"
+        )
=        
=        # Skip the first row - it's a heading
=        for [word, length] in table[1:]:
index 86d94af..4787ef4 100644
--- a/spec/basic-usage.md
+++ b/spec/basic-usage.md
@@ -208,7 +208,7 @@ When a directory is given as the last argument, load all documents inside (recur
=          code blocks: 1, tables: 2
=          source: samples/basic.md:59-93
=
-          > Received a table with 6 x 2 cells
+          A 6 x 2 table:
=
=          \``` json
=          [
@@ -254,8 +254,7 @@ When a directory is given as the last argument, load all documents inside (recur
=          > Is 'minx' 4 characters long? I think it's 4.
=
=
-          > Received a table with 4 x 2 cells
-
+          A 4 x 2 table:
=
=          \``` json
=          [
index cf3096f..8e8f0db 100644
--- a/spec/tbb.py
+++ b/spec/tbb.py
@@ -193,14 +193,15 @@ def send_text(content):
=        "content": content,
=    })
=
-def send_snippet(language, content, meta = ""):
+def send_snippet(language, content, meta = "", caption = None):
=    """ Send a snippet of code to be displayed in a TBB report
=    """
=    send({
=        "type": "Snippet",
=        "language": language,
=        "content": content,
-        "meta": meta
+        "meta": meta,
+        "caption": caption,
=    })
=    
=
index 57da103..6bc03b3 100644
--- a/src/report.rs
+++ b/src/report.rs
@@ -177,11 +177,13 @@ impl<'a> ScenarioReport<'a> {
=                        language,
=                        meta,
=                        content,
+                        caption,
=                    } => {
=                        observations.push(Observation::Snippet {
=                            language,
=                            meta,
=                            content,
+                            caption,
=                        });
=                    }
=                    InterpreterMessage::Link { url, label } => {
@@ -292,6 +294,7 @@ pub enum Observation {
=        language: String,
=        meta: String,
=        content: String,
+        caption: Option<String>,
=    },
=    // Image,
=    // Audio,
@@ -310,7 +313,12 @@ impl Display for Observation {
=                language,
=                meta,
=                content,
+                caption,
=            } => {
+                if let Some(caption) = caption {
+                    writeln!(f, "{caption}:")?;
+                    writeln!(f, "")?;
+                }
=                writeln!(f, "``` {language} {meta}")?;
=                writeln!(f, "{content}")?;
=                writeln!(f, "```")
@@ -508,6 +516,7 @@ pub enum InterpreterMessage {
=        language: String,
=        meta: String,
=        content: String,
+        caption: Option<String>,
=    },
=    Link {
=        url: String,