- 1126
let document = compile_markdown(source); - 1127
let nodes = serde_json::to_string(&document.blocks).expect("serialises"); - 1128
assert!(!nodes.contains("]("), "{nodes}"); - 1129
} - 1130
- 1131
use super::{ - 1132
DocumentBlock, InlineNode, OutputContent, OutputTimeline, PRESENTATION_SCHEMA_VERSION, - 1133
compile_markdown, safe_link, - 1134
}; - 1135
use std::collections::BTreeMap; - 1136
- 1137
#[test] - 1138
fn tight_lists_keep_inline_runs_together() { - 1139
let source = "- Stocks include **Axis Bank**, **Adani Ports**, and **HDFC Bank**."; - 1140
let document = compile_markdown(source); - 1141
let DocumentBlock::List { items, .. } = &document.blocks[0] else { - 1142
panic!("expected list"); - 1143
}; - 1144
assert_eq!(items[0].len(), 1); - 1145
let DocumentBlock::Paragraph { content, .. } = &items[0][0] else { - 1146
panic!("expected paragraph"); - 1147
}; - 1148
assert_eq!(content.len(), 7); - 1149
assert_eq!( - 1150
super::inline_text(content), - 1151
"Stocks include Axis Bank, Adani Ports, and HDFC Bank." - 1152
); - 1153
assert_eq!(document.source_markdown, source); - 1154
} - 1155
- 1156
#[test] - 1157
fn adaptive_output_roundtrips_with_fallback_for_replay_and_voice() { - 1158
let mut props = BTreeMap::new(); - 1159
props.insert("text".into(), serde_json::json!("Weekend plan")); - 1160
let content = OutputContent::Adaptive { - 1161
tree: vak_presentation::RenderTree { - 1162
schema_version: vak_presentation::RENDER_TREE_SCHEMA_VERSION, - 1163
spec_id: "plan.timeline".into(), - 1164
revision: 1, - 1165
digest: "digest".into(), - 1166
root: vak_presentation::RenderNode { - 1167
primitive: vak_presentation::Primitive::Title, - 1168
props, - 1169
children: Vec::new(), - 1170
}, - 1171
accessibility_summary: Some("Weekend plan".into()), - 1172
coverage: vak_presentation::Coverage::default(), - 1173
}, - 1174
fallback_text: "Weekend plan\n\nSaturday: travel".into(), - 1175
}; - 1176
let encoded = serde_json::to_string(&content).expect("serialize adaptive output"); - 1177
let decoded: OutputContent = - 1178
serde_json::from_str(&encoded).expect("replay adaptive output"); - 1179
assert_eq!(decoded, content); - 1180
let OutputContent::Adaptive { fallback_text, .. } = decoded else { - 1181
panic!("expected adaptive output"); - 1182
}; - 1183
assert!(fallback_text.contains("Saturday")); - 1184
} - 1185
- 1186
#[test] - 1187
fn compiled_adaptive_renderer_keeps_exact_fallback() { - 1188
let mut props = BTreeMap::new(); - 1189
props.insert("text".into(), serde_json::json!("Weekend plan")); - 1190
let compiled = vak_presentation::CompiledPresentation::Rich(vak_presentation::RenderTree { - 1191
schema_version: vak_presentation::RENDER_TREE_SCHEMA_VERSION, - 1192
spec_id: "plan.timeline".into(), - 1193
revision: 1, - 1194
digest: "digest".into(), - 1195
root: vak_presentation::RenderNode { - 1196
primitive: vak_presentation::Primitive::Title, - 1197
props, - 1198
children: Vec::new(), - 1199
}, - 1200
accessibility_summary: Some("Weekend plan".into()), - 1201
coverage: vak_presentation::Coverage::default(), - 1202
}); - 1203
let content = - 1204
OutputContent::from_compiled_adaptive(compiled, "Weekend plan\n\nSaturday: travel") - 1205
.expect("rich compilation should produce adaptive content"); - 1206
let OutputContent::Adaptive { fallback_text, .. } = content else { - 1207
panic!("expected adaptive content"); - 1208
}; - 1209
assert_eq!(fallback_text, "Weekend plan\n\nSaturday: travel"); - 1210
} - 1211
- 1212
#[test] - 1213
fn schema_v2_replay_ignores_future_fields_and_keeps_fallback() { - 1214
// This fixture represents a persisted v2 timeline. Unknown fields - 1215
// are intentionally tolerated so additive presentation metadata does - 1216
// not make an older desktop/bridge unable to replay a session. - 1217
let fixture = r#"{ - 1218
"schema_version": 2, - 1219
"session_id": "session-legacy", - 1220
"items": [{ - 1221
"id": "item-1", "timestamp": "2026-01-01T00:00:00Z", - 1222
"turn_id": "turn-1", "role": "assistant", "kind": "message", - 1223
"status": "succeeded", - 1224
"content": {"type":"adaptive", "tree": { - 1225
"schema_version": 1, "spec_id":"plan.timeline", "revision":1, - 1226
"digest":"old-digest", "root":{"primitive":"title","props":{"text":"Plan"},"children":[]}, - 1227
"accessibility_summary":"Plan", "coverage":{"rendered_paths":[],"omitted_paths":[]} - 1228
}, "fallback_text":"Plan\n\nSaturday: travel"}, - 1229
"fallback_text":"Plan\n\nSaturday: travel", "future_metadata":{"renderer":"new"} - 1230
}], "diagnostics": [], "future_timeline_field": true - 1231
}"#; - 1232
let timeline: OutputTimeline = serde_json::from_str(fixture).expect("v2 replay fixture"); - 1233
assert_eq!(timeline.schema_version, PRESENTATION_SCHEMA_VERSION); - 1234
assert_eq!(timeline.items[0].fallback_text, "Plan\n\nSaturday: travel"); - 1235
let OutputContent::Adaptive { fallback_text, .. } = &timeline.items[0].content else { - 1236
panic!("expected adaptive replay item"); - 1237
}; - 1238
assert_eq!(fallback_text, &timeline.items[0].fallback_text); - 1239
} - 1240
- 1241
#[test] - 1242
fn schema_v2_delivery_packet_keeps_fallback_when_new_fields_arrive() { - 1243
// Delivery packets are also durable upgrade inputs. The packet's - 1244
// exact Markdown fallback remains authoritative when a newer writer - 1245
// adds fields an older bridge does not know about. - 1246
let fixture = r#"{ - 1247
"schema_version": 2, - 1248
"job_id": "job-legacy", - 1249
"target": "webhook:demo", - 1250
"surface": "webhook", - 1251
"kind": "assistant", - 1252
"payload": {"type":"text","value":"Plan"}, - 1253
"fallback_markdown": "Plan\n\nSaturday: travel", - 1254
"chunks": ["Plan", "Saturday: travel"], - 1255
"actions": [], - 1256
"coverage": [], - 1257
"diagnostics": [], - 1258
"future_delivery_metadata": {"chunk_format":"rich"} - 1259
}"#; - 1260
let packet: crate::DeliveryPacket = - 1261
serde_json::from_str(fixture).expect("schema-v2 delivery packet"); - 1262
assert_eq!(packet.schema_version, 2); - 1263
assert_eq!(packet.fallback_markdown, "Plan\n\nSaturday: travel"); - 1264
assert_eq!(packet.chunks.len(), 2); - 1265
} - 1266
- 1267
#[test] - 1268
fn loose_paragraphs_and_nested_lists_keep_their_boundaries() { - 1269
let document = compile_markdown( - 1270
"- First **paragraph**.\n\n Second paragraph.\n\n - Nested [link](https://example.com)\n\n Last paragraph.", - 1271
); - 1272
let DocumentBlock::List { items, .. } = &document.blocks[0] else { - 1273
panic!("expected list"); - 1274
}; - 1275
assert_eq!(items[0].len(), 4); - 1276
assert!(matches!(items[0][2], DocumentBlock::List { .. })); - 1277
} - 1278
- 1279
#[test] - 1280
fn compiles_commonmark_without_losing_source() { - 1281
let source = "# Result\n\nA **strong** [link](https://example.com).\n\n- one\n- two\n\n| a | b |\n|---|---:|\n| 1 | 2 |\n\n```rust\nfn main() {}\n```"; - 1282
let document = compile_markdown(source); - 1283
assert_eq!(document.source_markdown, source); - 1284
assert!(matches!(document.blocks[0], DocumentBlock::Heading { .. })); - 1285
assert!( - 1286
document.blocks.iter().any( - 1287
|block| matches!(block, DocumentBlock::List { items, .. } if items.len() == 2) - 1288
) - 1289
); - 1290
assert!( - 1291
document - 1292
.blocks - 1293
.iter() - 1294
.any(|block| matches!(block, DocumentBlock::Table { rows, .. } if rows.len() == 1)) - 1295
); - 1296
assert!(document.blocks.iter().any(|block| matches!(block, DocumentBlock::Code { language, .. } if language.as_deref() == Some("rust")))); - 1297
} - 1298
- 1299
#[test] - 1300
fn unsafe_links_and_html_remain_inert() { - 1301
let document = compile_markdown("[bad](javascript:alert(1))\n\n<script>x</script>"); - 1302
let DocumentBlock::Paragraph { content, .. } = &document.blocks[0] else { - 1303
panic!("first block should be a paragraph"); - 1304
}; - 1305
assert!(matches!(&content[0], InlineNode::Link { safe: false, .. })); - 1306
assert!(!safe_link("javascript:alert(1)")); - 1307
assert!(!document.diagnostics.is_empty()); - 1308
} - 1309
- 1310
#[test] - 1311
fn fenced_diff_receives_a_native_block() { - 1312
let document = compile_markdown("```diff\n-old\n+new\n```"); - 1313
assert!(matches!(document.blocks[0], DocumentBlock::Diff { .. })); - 1314
} - 1315
- 1316
#[test] - 1317
fn specialized_renderer_golden_fixture_preserves_source_and_boundaries() { - 1318
// This compact fixture intentionally exercises the presentation - 1319
// primitives that have historically had specialized desktop views. - 1320
// The source remains the canonical fallback: adding a native view - 1321
// must not alter what a voice or constrained channel receives. - 1322
let source = "# Release review\n\n- [x] Diff reviewed\n- [ ] Tests expanded\n\n| Check | Result |\n| --- | --- |\n| Tests | 12 passed |\n\n```diff\n-old\n+new\n```\n\n```bash\n$ cargo test\n```\n\n> **Approval:** publish the artifact\n\n[Report](https://example.com/report)\n\n"; - 1323
let document = compile_markdown(source); - 1324
assert_eq!(document.source_markdown, source); - 1325
assert!( - 1326
document - 1327
.blocks - 1328
.iter() - 1329
.any(|block| matches!(block, DocumentBlock::Diff { .. })) - 1330
); - 1331
assert!( - 1332
document - 1333
.blocks - 1334
.iter() - 1335
.any(|block| matches!(block, DocumentBlock::Table { rows, .. } if rows.len() == 1)) - 1336
); - 1337
assert!(document.blocks.iter().any(|block| matches!(block, DocumentBlock::Code { language, .. } if language.as_deref() == Some("bash")))); - 1338
assert!(document.blocks.iter().any(|block| matches!(block, DocumentBlock::Paragraph { content, .. } if content.iter().any(|node| matches!(node, InlineNode::Link { safe: true, .. }))))); - 1339
- 1340
let encoded = serde_json::to_string(&document).expect("serialize specialized fixture"); - 1341
let replayed: super::PresentationDocument = - 1342
serde_json::from_str(&encoded).expect("replay specialized fixture"); - 1343
assert_eq!(replayed, document); - 1344
assert!(replayed.coverage.iter().all(|entry| { - 1345
matches!( - 1346
entry.disposition, - 1347
super::DocumentCoverageDisposition::Native - 1348
) - 1349
})); - 1350
} - 1351
- 1352
#[test] - 1353
fn specialized_output_envelopes_roundtrip_without_losing_fallback() { - 1354
let fallback = "Publish the report after approval."; - 1355
let outputs = [ - 1356
OutputContent::Approval { - 1357
request_id: "approval-1".into(), - 1358
tool: "publish".into(), - 1359
args_json: "{}".into(), - 1360
reason: "User confirmation required".into(), - 1361
expires_at: None, - 1362
}, - 1363
OutputContent::Artifact { - 1364
artifact: super::ArtifactRef { - 1365
name: "report.pdf".into(), - 1366
path: Some(".vak/scratch/report.pdf".into()), - 1367
media_type: Some("application/pdf".into()), - 1368
description: Some("Generated report".into()), - 1369
size_bytes: Some(2048), - 1370
status: Some(super::ArtifactStatus::Draft { - 1371
version: 2, - 1372
saved_as: Some(super::VersionFile { - 1373
version_id: "version-2".into(), - 1374
path: "report.pdf".into(), - 1375
}), - 1376
}), - 1377
}, - 1378
}, - 1379
OutputContent::Document { - 1380
document: compile_markdown(fallback), - 1381
}, - 1382
]; - 1383
for output in outputs { - 1384
let encoded = serde_json::to_string(&output).expect("serialize output envelope"); - 1385
let replayed: OutputContent = - 1386
serde_json::from_str(&encoded).expect("replay output envelope"); - 1387
assert_eq!(replayed, output); - 1388
} - 1389
assert_eq!(fallback, "Publish the report after approval."); - 1390
} - 1391
- 1392
#[test] - 1393
fn test_unfenced_vak_prefix() { - 1394
let text = "Vak\n{\"semantic_type\":\"metric\",\"payload\":{\"title\":\"Delhi Weather Snapshot\",\"Temperature\":\"33.5°C\"}}\n\nSome prose."; - 1395
let doc = compile_markdown(text); - 1396
assert!( - 1397
doc.blocks - 1398
.iter() - 1399
.any(|b| matches!(b, DocumentBlock::Structured { .. })) - 1400
); - 1401
} - 1402
- 1403
#[test] - 1404
fn mermaid_is_preserved_as_a_safe_diagram_source() { - 1405
let document = compile_markdown("```mermaid\ngraph TD; A-->B;\n```"); - 1406
assert!( - 1407
matches!(document.blocks[0], DocumentBlock::Diagram { ref source, .. } if source.contains("A-->B")) - 1408
); - 1409
assert_eq!( - 1410
document.source_markdown, - 1411
"```mermaid\ngraph TD; A-->B;\n```" - 1412
); - 1413
} - 1414
- 1415
#[test] - 1416
fn malformed_input_roundtrips_with_explicit_coverage() { - 1417
let source = "## Unclosed **strong\n\n<div onclick=\"bad()\">literal</div>"; - 1418
let document = compile_markdown(source); - 1419
let encoded = serde_json::to_string(&document).expect("serialize presentation"); - 1420
let decoded: super::PresentationDocument = - 1421
serde_json::from_str(&encoded).expect("deserialize presentation"); - 1422
assert_eq!(decoded.source_markdown, source); - 1423
assert!(!decoded.coverage.is_empty()); - 1424
assert_eq!(decoded, document); - 1425
assert!(!decoded.diagnostics.is_empty()); - 1426
} - 1427
} - 1428
Indexing the workspace…
Vakyartha documentation is discovering safe artifacts, anchors, and source references.