- 1001
/// Stakes come from what an action does, never from what it is about: - 1002
/// "customer", "payment", "live" and "everyone" read ordinary edits as - 1003
/// irreversible, capped approval at `ask`, and told the model to confirm - 1004
/// renaming a struct. - 1005
#[test] - 1006
fn stakes_topic_words_do_not_raise_stakes() { - 1007
let cases: &[&str] = &[ - 1008
"rename the Customer struct to Client", - 1009
"fix the payment form validation", - 1010
"the live server is broken", - 1011
"make the banner visible to everyone", - 1012
"this affects every customer", - 1013
"the expensive migration", - 1014
"within budget constraints", - 1015
"using up quota", - 1016
]; - 1017
for text in cases { - 1018
let extraction = extract(&req(text)); - 1019
assert_eq!( - 1020
extraction.stakes_from_words.winner().map(|w| w.0), - 1021
None, - 1022
"`{text}` is about a topic, not an irreversible action" - 1023
); - 1024
} - 1025
// Sending and paying are irreversible by what they do, not by the word. - 1026
assert_eq!( - 1027
resolve_text("send payment to the customer").reading.stakes, - 1028
Stakes::Irreversible - 1029
); - 1030
assert_eq!( - 1031
resolve_text("pay the invoice now").reading.stakes, - 1032
Stakes::Irreversible - 1033
); - 1034
} - 1035
- 1036
#[test] - 1037
fn stakes_effectful_acts_imply_a_floor() { - 1038
let cases: &[&str] = &[ - 1039
"refactor the parser", - 1040
"deploy the service", - 1041
"configure the gateway", - 1042
"write a new module", - 1043
"create the test suite", - 1044
"fix the bug", - 1045
]; - 1046
for text in cases { - 1047
let intent = resolve_text(text); - 1048
assert!( - 1049
intent.reading.stakes.rank() >= Stakes::Reversible.rank(), - 1050
"`{}` effectful act should imply >= Reversible stakes, got {:?}", - 1051
text, - 1052
intent.reading.stakes - 1053
); - 1054
} - 1055
} - 1056
- 1057
#[test] - 1058
fn stakes_ordering_takes_highest_with_support() { - 1059
let mut votes: Votes<Stakes> = Votes::default(); - 1060
votes.add(Stakes::Irreversible, 1.0); - 1061
votes.add(Stakes::Reversible, 0.5); - 1062
let (winner, conf) = votes.winner().unwrap(); - 1063
assert_eq!(winner, Stakes::Irreversible); - 1064
assert!( - 1065
conf >= 0.7, - 1066
"corroboration should not reduce confidence: {}", - 1067
conf - 1068
); - 1069
- 1070
// Votes that all sit below the escalation floor abstain: a stray hint is - 1071
// not evidence of the level it names, and the axis default applies. - 1072
let mut weak: Votes<Stakes> = Votes::default(); - 1073
weak.add(Stakes::Reversible, 0.3); - 1074
weak.add(Stakes::Inert, 0.3); - 1075
assert!(weak.winner().is_none()); - 1076
} - 1077
- 1078
// ================================================================ - 1079
// Part 4: Evidence classification - 1080
// ================================================================ - 1081
- 1082
#[test] - 1083
fn evidence_none_is_default_confident() { - 1084
let cases: &[&str] = &[ - 1085
"what is 2 + 2", - 1086
"fix the bug", - 1087
"write a report", - 1088
"deploy to prod", - 1089
"hello", - 1090
"explain the parser", - 1091
"find the config", - 1092
]; - 1093
for text in cases { - 1094
let extraction = extract(&req(text)); - 1095
let evidence = extraction.evidence.winner().map(|w| w.0); - 1096
// No evidence words in any of these, so winner() is None (not - 1097
// Some(Evidence::None)) — the fallback only applies when votes - 1098
// exist but fall below the floor. - 1099
assert!( - 1100
evidence.is_none(), - 1101
"`{}` should have no evidence winner, got {:?}", - 1102
text, - 1103
evidence - 1104
); - 1105
} - 1106
} - 1107
- 1108
#[test] - 1109
fn evidence_cited_scenarios() { - 1110
let cases: &[&str] = &[ - 1111
"cite your sources", - 1112
"citation needed for this claim", - 1113
"provide sources for the argument", - 1114
"show your sources", - 1115
"cite the source material", - 1116
"evidence is required for this", - 1117
"cite sources now", - 1118
]; - 1119
for text in cases { - 1120
let extraction = extract(&req(text)); - 1121
let evidence = extraction.evidence.winner().map(|w| w.0); - 1122
assert_eq!( - 1123
Some(Evidence::Cited), - 1124
evidence, - 1125
"`{}` should read as Cited, got {:?}", - 1126
text, - 1127
evidence - 1128
); - 1129
} - 1130
} - 1131
- 1132
#[test] - 1133
fn evidence_verified_scenarios() { - 1134
let cases: &[&str] = &[ - 1135
"prove the fix works", - 1136
"make sure the tests pass", - 1137
"ensure the build passes on CI", - 1138
"passing the tests proves it", - 1139
"prove this theorem now", - 1140
]; - 1141
for text in cases { - 1142
let extraction = extract(&req(text)); - 1143
let evidence = extraction.evidence.winner().map(|w| w.0); - 1144
assert_eq!( - 1145
Some(Evidence::Verified), - 1146
evidence, - 1147
"`{}` should read as Verified, got {:?}", - 1148
text, - 1149
evidence - 1150
); - 1151
} - 1152
} - 1153
- 1154
/// "Make sure" and "ensure" demand machine-checkable proof only when there is - 1155
/// something checkable to be sure of. - 1156
#[test] - 1157
fn evidence_assurance_without_a_checkable_object_is_not_verification() { - 1158
for text in [ - 1159
"write a poem about autumn and make sure it rhymes", - 1160
"ensure correctness of the approach", - 1161
"make sure you use tabs", - 1162
] { - 1163
assert_eq!( - 1164
extract(&req(text)).evidence.winner().map(|w| w.0), - 1165
None, - 1166
"`{text}`" - 1167
); - 1168
} - 1169
} - 1170
- 1171
#[test] - 1172
fn evidence_audited_scenarios() { - 1173
let cases: &[&str] = &[ - 1174
"get it signed off by security", - 1175
"get sign off from the team", - 1176
"sign off on this before merging", - 1177
"acceptance testing required first", - 1178
"this needs sign off from compliance", - 1179
]; - 1180
for text in cases { - 1181
let extraction = extract(&req(text)); - 1182
let evidence = extraction.evidence.winner().map(|w| w.0); - 1183
assert_eq!( - 1184
Some(Evidence::Audited), - 1185
evidence, - 1186
"`{}` should read as Audited, got {:?}", - 1187
text, - 1188
evidence - 1189
); - 1190
} - 1191
} - 1192
- 1193
#[test] - 1194
fn evidence_verified_and_audited_can_coexist() { - 1195
let text = "get sign off on the code and prove the tests pass"; - 1196
let extraction = extract(&req(text)); - 1197
let evidence = extraction.evidence.winner().map(|w| w.0); - 1198
assert_eq!( - 1199
Some(Evidence::Audited), - 1200
evidence, - 1201
"should take the highest supported evidence level" - 1202
); - 1203
} - 1204
- 1205
// ================================================================ - 1206
// Part 5: Clarity / ambiguity — edge cases - 1207
// ================================================================ - 1208
- 1209
#[test] - 1210
fn clarity_bare_pronoun_without_context_is_ambiguous() { - 1211
let cases: &[&str] = &[ - 1212
"fix this", - 1213
"change that", - 1214
"show me it", - 1215
"run this", - 1216
"edit those", - 1217
"deploy it", - 1218
"review them", - 1219
"delete that", - 1220
]; - 1221
for text in cases { - 1222
let extraction = extract(&req(text)); - 1223
let clarity = extraction.clarity.winner().map(|w| w.0); - 1224
assert!( - 1225
clarity == Some(Clarity::Ambiguous) || clarity.is_none(), - 1226
"`{}` (no context) should be ambiguous or have no winner, got {:?}", - 1227
text, - 1228
clarity - 1229
); - 1230
} - 1231
} - 1232
- 1233
#[test] - 1234
fn clarity_bare_pronoun_with_context_is_clear() { - 1235
let text = "fix this"; - 1236
let mut request = req(text); - 1237
request.history.turn_index = 5; - 1238
request.history.previous_act = Some(Act::Modify); - 1239
let extraction = extract(&request); - 1240
let clarity = extraction.clarity.winner().map(|w| w.0); - 1241
assert_eq!( - 1242
Some(Clarity::Clear), - 1243
clarity, - 1244
"with context, `this` should resolve to clear" - 1245
); - 1246
} - 1247
- 1248
#[test] - 1249
fn clarity_underspecified_requests_do_not_crash() { - 1250
let cases: &[&str] = &[ - 1251
"do the thing", - 1252
"handle it", - 1253
"take care of it", - 1254
"manage the situation", - 1255
]; - 1256
for text in cases { - 1257
let extraction = extract(&req(text)); - 1258
let _ = extraction.act.winner(); - 1259
} - 1260
} - 1261
- 1262
// ================================================================ - 1263
// Part 6: Resolution cascade — tier correctness - 1264
// ================================================================ - 1265
- 1266
#[test] - 1267
fn resolution_confident_readings_are_settled() { - 1268
let cases: &[&str] = &[ - 1269
"hello", - 1270
"what is the meaning of life", - 1271
"fix the bug in the parser", - 1272
"deploy to production", - 1273
"write a report on the architecture", - 1274
"find the config file", - 1275
"test the parser", - 1276
]; - 1277
for text in cases { - 1278
let resolution = resolve( - 1279
&req(text), - 1280
&Declared::default(), - 1281
&Authority::default(), - 1282
&ResolverConfig::default(), - 1283
); - 1284
match &resolution { - 1285
Resolution::Settled(intent) => { - 1286
assert!( - 1287
intent.reading.confidence >= 0.45 || intent.provenance.tier == Tier::General, - 1288
"`{}` settled but confidence too low: {}", - 1289
text, - 1290
intent.reading.confidence - 1291
); - 1292
} - 1293
Resolution::Escalate { partial, .. } => { - 1294
assert!( - 1295
partial - 1296
.engagement - 1297
.limits - 1298
.is_at_most(&Limits::unrestricted()) - 1299
); - 1300
} - 1301
} - 1302
} - 1303
} - 1304
- 1305
#[test] - 1306
fn resolution_unknown_input_falls_back_to_general() { - 1307
let resolution = resolve( - 1308
&req("zorble the frobnicator immediately"), - 1309
&Declared::default(), - 1310
&Authority::default(), - 1311
&ResolverConfig::default(), - 1312
); - 1313
let intent = resolution.intent(); - 1314
assert_eq!(intent.provenance.tier, Tier::General); - 1315
// Kernel on and nothing understood: the orientation floor, not - 1316
// everything (docs/design/68, Principle 6). `Engagement::general` is - 1317
// what a *disabled* kernel produces. - 1318
assert_eq!(intent.engagement, Engagement::orienting()); - 1319
} - 1320
- 1321
#[test] - 1322
fn resolution_declared_override_trumps_signals() { - 1323
let declared = Declared { - 1324
act: Some(Act::Modify), - 1325
horizon: Some(Horizon::Session), - 1326
stakes: Some(Stakes::Reversible), - 1327
evidence: Some(Evidence::Verified), - 1328
..Declared::default() - 1329
}; - 1330
let intent = resolve_declared("hi", &declared); - 1331
assert_eq!(intent.reading.act, Act::Modify); - 1332
assert_eq!(intent.reading.horizon, Horizon::Session); - 1333
assert_eq!(intent.reading.stakes, Stakes::Reversible); - 1334
assert_eq!(intent.reading.evidence, Evidence::Verified); - 1335
assert_eq!(intent.provenance.tier, Tier::Declared); - 1336
assert!(intent.provenance.reproducible); - 1337
} - 1338
- 1339
#[test] - 1340
fn resolution_partial_declared_merges_with_signals() { - 1341
let declared = Declared { - 1342
act: Some(Act::Modify), - 1343
..Declared::default() - 1344
}; - 1345
let intent = resolve_declared("fix the parser", &declared); - 1346
assert_eq!(intent.reading.act, Act::Modify); - 1347
assert!(intent.reading.stakes.rank() >= Stakes::Reversible.rank()); - 1348
} - 1349
- 1350
#[test] - 1351
fn resolution_disabled_reproduces_general() { - 1352
let config = ResolverConfig { - 1353
enabled: false, - 1354
..ResolverConfig::default() - 1355
}; - 1356
let resolution = resolve( - 1357
&req("deploy everything to production right now"), - 1358
&Declared::default(), - 1359
&Authority::default(), - 1360
&config, - 1361
); - 1362
let intent = resolution.intent(); - 1363
assert_eq!(intent.engagement, Engagement::general()); - 1364
assert_eq!(intent.provenance.tier, Tier::General); - 1365
} - 1366
- 1367
#[test] - 1368
fn resolution_provisional_reading_withholds_slicing() { - 1369
let config = ResolverConfig { - 1370
accept_confidence: 0.99, - 1371
provisional_confidence: 0.0, - 1372
..ResolverConfig::default() - 1373
}; - 1374
let resolution = resolve( - 1375
&req("explain the deploy script and then deploy it"), - 1376
&Declared::default(), - 1377
&Authority::default(), - 1378
&config, - 1379
); - 1380
let intent = resolution.peek(); - 1381
assert_eq!( - 1382
intent.engagement.limits.required_domains, - 1383
Engagement::orienting().limits.required_domains, - 1384
"a provisional reading gets the orientation floor, never a guessed slice" - 1385
); - 1386
} - 1387
- 1388
#[test] - 1389
fn classification_may_raise_stakes_not_lower() { - 1390
let partial = resolve_text("deploy the service"); - 1391
let downplayed = Classification { - 1392
act: Some("operate".into()), - 1393
stakes: Some("inert".into()), - 1394
confidence: Some(0.99), - 1395
..Classification::default() - 1396
}; - 1397
let intent = apply_classification( - 1398
partial, - 1399
std::slice::from_ref(&downplayed), - 1400
"cheap-model", - 1401
"digest", - 1402
&Authority::default(), - 1403
&ResolverConfig::default(), - 1404
true, - 1405
); - 1406
assert_eq!( - 1407
intent.reading.stakes, - 1408
Stakes::Irreversible, - 1409
"classifier must not lower stakes below the act floor" - 1410
); - 1411
} - 1412
- 1413
#[test] - 1414
fn classification_empty_leaves_free_tier_intact() { - 1415
let partial = resolve_text("refactor the parser"); - 1416
let before_reading = partial.reading.clone(); - 1417
let before_engagement = partial.engagement.clone(); - 1418
let after = apply_classification( - 1419
partial, - 1420
std::slice::from_ref(&Classification::default()), - 1421
"flaky-model", - 1422
"digest", - 1423
&Authority::default(), - 1424
&ResolverConfig::default(), - 1425
true, - 1426
); - 1427
assert_eq!(after.reading, before_reading); - 1428
assert_eq!(after.engagement, before_engagement); - 1429
} - 1430
- 1431
#[test] - 1432
fn classification_only_overwrites_returned_axes() { - 1433
let partial = resolve_text("deploy to production"); - 1434
let classification = Classification { - 1435
act: Some("operate".into()), - 1436
..Classification::default() - 1437
}; - 1438
let intent = apply_classification( - 1439
partial, - 1440
std::slice::from_ref(&classification), - 1441
"local-model", - 1442
"abc123", - 1443
&Authority::default(), - 1444
&ResolverConfig::default(), - 1445
false, - 1446
); - 1447
assert_eq!(intent.reading.act, Act::Operate); - 1448
assert!(!intent.provenance.reproducible); - 1449
assert_eq!(intent.provenance.tier, Tier::LocalModel); - 1450
} - 1451
- 1452
// ================================================================ - 1453
// Part 7: Engagement derivation — matrix tests - 1454
// ================================================================ - 1455
- 1456
#[test] - 1457
fn engagement_output_shape_per_act() { - 1458
let cases: &[(Act, OutputShape)] = &[ - 1459
(Act::Converse, OutputShape::Prose), - 1460
(Act::Answer, OutputShape::Prose), - 1461
(Act::Locate, OutputShape::Findings), - 1462
(Act::Analyze, OutputShape::Prose), - 1463
(Act::Author, OutputShape::Artifact), - 1464
(Act::Modify, OutputShape::Diff), - 1465
(Act::Operate, OutputShape::Report), - 1466
(Act::Verify, OutputShape::Matrix), - 1467
(Act::Orchestrate, OutputShape::Report), - 1468
(Act::Govern, OutputShape::Report), - 1469
]; - 1470
for (act, expected_shape) in cases { - 1471
let r = reading_simple(*act, Horizon::Turn, Stakes::Reversible, Evidence::None); - 1472
let engagement = derive(&r, &Authority::default(), true); - 1473
assert_eq!( - 1474
engagement.posture.delivery.shape, *expected_shape, - 1475
"act {:?} should produce shape {:?}", - 1476
act, expected_shape - 1477
); - 1478
} - 1479
} - 1480
- 1481
#[test] - 1482
fn engagement_output_shape_cited_evidence_for_answer_analyze() { - 1483
for act in [Act::Answer, Act::Analyze] { - 1484
let r = reading_simple(act, Horizon::Turn, Stakes::Inert, Evidence::Cited); - 1485
let engagement = derive(&r, &Authority::default(), true); - 1486
assert_eq!( - 1487
engagement.posture.delivery.shape, - 1488
OutputShape::Sources, - 1489
"{:?} with Cited evidence should produce Sources shape", - 1490
act - 1491
); - 1492
} - 1493
} - 1494
- 1495
#[test] - 1496
fn engagement_stop_profile_per_act() { - 1497
let cases: &[(Act, StopProfile)] = &[ - 1498
(Act::Converse, StopProfile::Message), - 1499
(Act::Answer, StopProfile::Message), - 1500
(Act::Locate, StopProfile::Inspection), - 1501
(Act::Analyze, StopProfile::Inspection), - 1502
(Act::Author, StopProfile::Inspection), - 1503
(Act::Operate, StopProfile::Effect), - 1504
// Verify with no verified/audit evidence → Inspection (not - 1505
// Verification, which requires evidence >= Verified). - 1506
(Act::Verify, StopProfile::Inspection), - 1507
(Act::Orchestrate, StopProfile::Inspection), - 1508
(Act::Govern, StopProfile::Effect), - 1509
]; - 1510
for (act, expected_stop) in cases { - 1511
let r = reading_simple(*act, Horizon::Turn, Stakes::Reversible, Evidence::None); - 1512
let engagement = derive(&r, &Authority::default(), true); - 1513
assert_eq!( - 1514
engagement.posture.stop, *expected_stop, - 1515
"act {:?} should produce stop {:?}", - 1516
act, expected_stop - 1517
); - 1518
} - 1519
} - 1520
- 1521
#[test] - 1522
fn engagement_stop_profile_verified_overrides_act() { - 1523
for act in Act::ALL { - 1524
let r = reading_simple(act, Horizon::Turn, Stakes::Inert, Evidence::Verified); - 1525
let engagement = derive(&r, &Authority::default(), true); - 1526
assert_eq!( - 1527
engagement.posture.stop, - 1528
StopProfile::Verification, - 1529
"{:?} with Verified evidence should use Verification stop", - 1530
act - 1531
); - 1532
} - 1533
} - 1534
- 1535
#[test] - 1536
fn engagement_context_profile_per_act_and_horizon() { - 1537
let r = reading_simple( - 1538
Act::Converse, - 1539
Horizon::Immediate, - 1540
Stakes::Inert, - 1541
Evidence::None, - 1542
); - 1543
let engagement = derive(&r, &Authority::default(), true); - 1544
assert_eq!(engagement.posture.context, ContextProfile::Minimal); - 1545
- 1546
for act in [Act::Modify, Act::Verify, Act::Operate] { - 1547
let r = reading_simple(act, Horizon::Turn, Stakes::Reversible, Evidence::None); - 1548
let engagement = derive(&r, &Authority::default(), true); - 1549
assert_eq!(engagement.posture.context, ContextProfile::Working); - 1550
} - 1551
- 1552
for act in [Act::Modify, Act::Operate] { - 1553
let r = reading_simple(act, Horizon::Durable, Stakes::Reversible, Evidence::None); - 1554
let engagement = derive(&r, &Authority::default(), true); - 1555
assert_eq!(engagement.posture.context, ContextProfile::Full); - 1556
} - 1557
} - 1558
- 1559
#[test] - 1560
fn engagement_hil_mode_matrix() { - 1561
for autonomy in Autonomy::ALL { - 1562
for attendance in Attendance::ALL { - 1563
let r = reading_simple( - 1564
Act::Operate, - 1565
Horizon::Turn, - 1566
Stakes::Irreversible, - 1567
Evidence::None, - 1568
); - 1569
let auth = authority_of(autonomy, attendance); - 1570
let engagement = derive(&r, &auth, true); - 1571
assert_eq!( - 1572
engagement.posture.hil, - 1573
HilMode::Interrupt, - 1574
"Irreversible must always interrupt: autonomy={:?} attendance={:?}", - 1575
autonomy, - 1576
attendance - 1577
); - 1578
} - 1579
} - 1580
- 1581
let r = reading_simple( - 1582
Act::Modify, - 1583
Horizon::Turn, - 1584
Stakes::Reversible, - 1585
Evidence::None, - 1586
); - 1587
let auth = authority_of(Autonomy::Autonomous, Attendance::Interactive); - 1588
let engagement = derive(&r, &auth, true); - 1589
assert_eq!(engagement.posture.hil, HilMode::Review); - 1590
- 1591
let r = reading_simple( - 1592
Act::Modify, - 1593
Horizon::Turn, - 1594
Stakes::Reversible, - 1595
Evidence::None, - 1596
); - 1597
// Delegation alone is not a boundary: the turn reviews like any other - 1598
// reversible work until a strand is known to serve an enveloped - 1599
// commitment. - 1600
let auth = authority_of(Autonomy::Delegated, Attendance::Interactive); - 1601
let engagement = derive(&r, &auth, true); - 1602
assert_eq!(engagement.posture.hil, HilMode::Review); - 1603
assert_eq!(engagement.limits.approval_ceiling, ApprovalCeiling::Ask); - 1604
} - 1605
- 1606
/// A strand serving a commitment with a live grant works inside it: the - 1607
/// grant's permission and spend ceilings narrow that strand, and under - 1608
/// delegation it proceeds inside the envelope rather than asking first. - 1609
#[test] - 1610
fn an_envelope_narrows_the_strand_that_serves_its_commitment() { - 1611
let now = Utc::now(); - 1612
let auth = authority_of(Autonomy::Delegated, Attendance::Interactive); - 1613
let intent = resolve( - 1614
&req("refactor the parser module"), - 1615
&Declared::default(), - 1616
&auth, - 1617
&ResolverConfig::default(), - 1618
) - 1619
.intent(); - 1620
let strand_id = intent.strands[0].strand_id.clone(); - 1621
let envelopes = BTreeMap::from([(strand_id, test_envelope(PermissionCeiling::WorkspaceWrite))]); - 1622
let narrowed = apply_envelopes(intent.clone(), &envelopes, Autonomy::Delegated, now); - 1623
let strand = &narrowed.strands[0]; - 1624
assert_eq!(strand.engagement.posture.hil, HilMode::Envelope); - 1625
assert_eq!( - 1626
strand.engagement.limits.permission_ceiling, - 1627
PermissionCeiling::WorkspaceWrite - 1628
); - 1629
assert_eq!(strand.engagement.limits.spend_ceiling_usd, Some(5.0)); - 1630
assert!( - 1631
narrowed - 1632
.engagement - 1633
.limits - 1634
.is_at_most(&intent.engagement.limits) - 1635
); - 1636
- 1637
// A revoked or expired grant narrows nothing and grants nothing. - 1638
for dead in [ - 1639
Envelope { - 1640
revoked_at: Some(now), - 1641
..test_envelope(PermissionCeiling::ReadOnly) - 1642
}, - 1643
Envelope { - 1644
expires_at: Some(now - chrono::Duration::hours(1)), - 1645
..test_envelope(PermissionCeiling::ReadOnly) - 1646
}, - 1647
] { - 1648
let envelopes = BTreeMap::from([(intent.strands[0].strand_id.clone(), dead)]); - 1649
let untouched = apply_envelopes(intent.clone(), &envelopes, Autonomy::Delegated, now); - 1650
assert_eq!(untouched, intent); - 1651
} - 1652
} - 1653
- 1654
#[test] - 1655
fn engagement_demand_hints_populated() { - 1656
for act in [Act::Analyze, Act::Author, Act::Modify, Act::Orchestrate] { - 1657
let r = reading_simple(act, Horizon::Durable, Stakes::Reversible, Evidence::None); - 1658
let engagement = derive(&r, &Authority::default(), true); - 1659
assert!( - 1660
engagement.posture.demand.reasoning_required, - 1661
"{:?} should require reasoning", - 1662
act - 1663
); - 1664
} - 1665
- 1666
let r = reading_simple(Act::Answer, Horizon::Turn, Stakes::Inert, Evidence::Cited); - 1667
let engagement = derive(&r, &Authority::default(), true); - 1668
assert!(engagement.posture.demand.evidence_required); - 1669
- 1670
let r = reading_simple( - 1671
Act::Modify, - 1672
Horizon::Turn, - 1673
Stakes::Reversible, - 1674
Evidence::None, - 1675
); - 1676
let engagement = derive(&r, &Authority::default(), true); - 1677
assert!(engagement.posture.demand.structured_output); - 1678
} - 1679
- 1680
#[test] - 1681
fn engagement_delivery_posture_by_attendance_and_stakes() { - 1682
for attendance in Attendance::ALL { - 1683
let r = reading_simple( - 1684
Act::Operate, - 1685
Horizon::Turn, - 1686
Stakes::Irreversible, - 1687
Evidence::None, - 1688
); - 1689
// Delivery urgency derives from reading.stakes (not authority.attendance): - 1690
// Irreversible stakes always Interrupt regardless of attendance. - 1691
let r = Reading { attendance, ..r }; - 1692
let engagement = derive(&r, &authority_of(Autonomy::Assisted, attendance), true); - 1693
assert_eq!(engagement.posture.delivery.urgency, Urgency::Interrupt); - 1694
} - 1695
- 1696
let mut r = reading_simple(Act::Verify, Horizon::Durable, Stakes::Inert, Evidence::None); - 1697
r.attendance = Attendance::Unattended; - 1698
let engagement = derive( - 1699
&r, - 1700
&authority_of(Autonomy::Assisted, Attendance::Unattended), - 1701
true, - 1702
); - 1703
assert_eq!(engagement.posture.delivery.cadence, Cadence::Digest); - 1704
assert_eq!(engagement.posture.delivery.urgency, Urgency::Quiet); - 1705
- 1706
let r = reading_simple(Act::Answer, Horizon::Turn, Stakes::Inert, Evidence::None); - 1707
let engagement = derive(&r, &Authority::default(), true); - 1708
assert_eq!(engagement.posture.delivery.cadence, Cadence::Live); - 1709
} - 1710
- 1711
#[test] - 1712
fn engagement_min_satisfaction_per_evidence() { - 1713
let cases: &[(Evidence, Satisfaction)] = &[ - 1714
(Evidence::None, Satisfaction::Asserted), - 1715
(Evidence::Cited, Satisfaction::Cited), - 1716
(Evidence::Verified, Satisfaction::Observed), - 1717
(Evidence::Audited, Satisfaction::Attested), - 1718
]; - 1719
for (evidence, expected_sat) in cases { - 1720
let r = reading_simple(Act::Modify, Horizon::Session, Stakes::Reversible, *evidence); - 1721
let engagement = derive(&r, &Authority::default(), true); - 1722
assert_eq!(engagement.limits.min_satisfaction, *expected_sat); - 1723
} - 1724
} - 1725
- 1726
#[test] - 1727
fn engagement_domain_requirements_per_act() { - 1728
let cases: &[(Act, &[&str])] = &[ - 1729
(Act::Converse, &[]), - 1730
(Act::Answer, &["live-data", "web"]), - 1731
(Act::Locate, &["live-data", "web", "vcs"]), - 1732
(Act::Analyze, &["live-data", "web", "code-exec", "vcs"]), - 1733
(Act::Author, &["documents", "web"]), - 1734
(Act::Modify, &["documents", "code-exec", "vcs"]), - 1735
( - 1736
Act::Operate, - 1737
&[ - 1738
"code-exec", - 1739
"web", - 1740
"live-data", - 1741
"messaging", - 1742
"documents", - 1743
"orchestration", - 1744
], - 1745
), - 1746
(Act::Verify, &["code-exec", "observability"]), - 1747
(Act::Orchestrate, &["orchestration", "code-exec"]), - 1748
( - 1749
Act::Govern, - 1750
&["memory", "orchestration", "documents", "observability"], - 1751
), - 1752
]; - 1753
for (act, expected_domains) in cases { - 1754
let r = reading_simple(*act, Horizon::Turn, Stakes::Reversible, Evidence::None); - 1755
let engagement = derive(&r, &Authority::default(), true); - 1756
for domain in *expected_domains { - 1757
assert!( - 1758
engagement.limits.required_domains.contains(domain), - 1759
"{:?} should require domain `{domain}`", - 1760
act - 1761
); - 1762
} - 1763
} - 1764
} - 1765
- 1766
#[test] - 1767
fn engagement_cited_evidence_adds_live_data_and_web() { - 1768
for act in Act::ALL { - 1769
let r = reading_simple(act, Horizon::Turn, Stakes::Reversible, Evidence::Cited); - 1770
let engagement = derive(&r, &Authority::default(), true); - 1771
assert!(engagement.limits.required_domains.contains("live-data")); - 1772
assert!(engagement.limits.required_domains.contains("web")); - 1773
} - 1774
} - 1775
- 1776
#[test] - 1777
fn engagement_clarify_policy_by_stakes() { - 1778
for act in [Act::Converse, Act::Answer] { - 1779
let mut r = reading_simple(act, Horizon::Turn, Stakes::Inert, Evidence::None); - 1780
r.clarity = Clarity::Ambiguous; - 1781
let engagement = derive(&r, &Authority::default(), true); - 1782
assert_eq!(engagement.posture.clarify, ClarifyPolicy::StateAssumption); - 1783
} - 1784
- 1785
let mut r = reading_simple(Act::Operate, Horizon::Turn, Stakes::Costly, Evidence::None); - 1786
r.clarity = Clarity::Ambiguous; - 1787
let engagement = derive(&r, &Authority::default(), true); - 1788
assert_eq!(engagement.posture.clarify, ClarifyPolicy::Ask); - 1789
- 1790
let r = reading_simple( - 1791
Act::Modify, - 1792
Horizon::Turn, - 1793
Stakes::Reversible, - 1794
Evidence::None, - 1795
); - 1796
let engagement = derive(&r, &Authority::default(), true); - 1797
assert_eq!(engagement.posture.clarify, ClarifyPolicy::Proceed); - 1798
} - 1799
- 1800
#[test] - 1801
fn engagement_checkpoints_for_effectful_stakes_reversible_plus() { - 1802
for stakes in [Stakes::Reversible, Stakes::Costly, Stakes::Irreversible] { - 1803
let r = reading_simple(Act::Modify, Horizon::Session, stakes, Evidence::None); - 1804
let engagement = derive(&r, &Authority::default(), true); - 1805
assert!(engagement.posture.checkpoint_before_effect); - 1806
} - 1807
- 1808
let r = reading_simple(Act::Answer, Horizon::Turn, Stakes::Inert, Evidence::None); - 1809
let engagement = derive(&r, &Authority::default(), true); - 1810
assert!(!engagement.posture.checkpoint_before_effect); - 1811
} - 1812
- 1813
#[test] - 1814
fn engagement_any_effectful_contender_forces_checkpoint() { - 1815
let r = reading_simple( - 1816
Act::Answer, - 1817
Horizon::Session, - 1818
Stakes::Reversible, - 1819
Evidence::None, - 1820
); - 1821
let engagement = derive(&r, &Authority::default(), true); - 1822
assert!(!engagement.posture.checkpoint_before_effect); - 1823
- 1824
let mut r2 = reading_simple( - 1825
Act::Answer, - 1826
Horizon::Session, - 1827
Stakes::Reversible, - 1828
Evidence::None, - 1829
); - 1830
r2.alternate_acts.insert(Act::Modify); - 1831
let engagement2 = derive(&r2, &Authority::default(), true); - 1832
assert!(engagement2.posture.checkpoint_before_effect); - 1833
// The stop rule follows the primary act; a contender only widens the - 1834
// toolbox and the checkpoint. - 1835
assert_eq!(engagement2.posture.stop, StopProfile::Message); - 1836
} - 1837
- 1838
#[test] - 1839
fn engagement_note_content() { - 1840
let r = reading_simple( - 1841
Act::Operate, - 1842
Horizon::Turn, - 1843
Stakes::Irreversible, - 1844
Evidence::None, - 1845
); - 1846
let engagement = derive(&r, &Authority::default(), true); - 1847
let note = engagement.posture.note.as_deref().unwrap_or(""); - 1848
assert!(note.contains("cannot be undone")); - 1849
- 1850
let r = reading_simple( - 1851
Act::Modify, - 1852
Horizon::Turn, - 1853
Stakes::Reversible, - 1854
Evidence::Verified, - 1855
); - 1856
let engagement = derive(&r, &Authority::default(), true); - 1857
let note = engagement.posture.note.as_deref().unwrap_or(""); - 1858
assert!(note.contains("runtime") || note.contains("decide")); - 1859
- 1860
let r = reading_simple(Act::Answer, Horizon::Turn, Stakes::Inert, Evidence::Cited); - 1861
let engagement = derive(&r, &Authority::default(), true); - 1862
let note = engagement.posture.note.as_deref().unwrap_or(""); - 1863
assert!(note.contains("source")); - 1864
- 1865
let r = reading_simple( - 1866
Act::Converse, - 1867
Horizon::Immediate, - 1868
Stakes::Inert, - 1869
Evidence::None, - 1870
); - 1871
let engagement = derive(&r, &Authority::default(), true); - 1872
assert!(engagement.posture.note.is_none()); - 1873
} - 1874
- 1875
// ================================================================ - 1876
// Part 8: Authority composition - 1877
// ================================================================ - 1878
- 1879
#[test] - 1880
fn authority_approval_ceiling_irreversible_always_asks() { - 1881
for autonomy in Autonomy::ALL { - 1882
for attendance in Attendance::ALL { - 1883
let auth = authority_of(autonomy, attendance); - 1884
assert_eq!( - 1885
auth.approval_ceiling(Stakes::Irreversible), - 1886
ApprovalCeiling::Ask, - 1887
"Irreversible must always ask: autonomy={autonomy:?} attendance={attendance:?}" - 1888
); - 1889
} - 1890
} - 1891
} - 1892
- 1893
/// Delegation asks at the turn level; the gate lets through only the - 1894
/// actions a live envelope covers. - 1895
#[test] - 1896
fn authority_approval_ceiling_delegated_asks_at_the_turn_level() { - 1897
let auth = authority_of(Autonomy::Delegated, Attendance::Interactive); - 1898
assert_eq!( - 1899
auth.approval_ceiling(Stakes::Reversible), - 1900
ApprovalCeiling::Ask - 1901
); - 1902
} - 1903
- 1904
#[test] - 1905
fn authority_approval_ceiling_composes_only_tightens() { - 1906
for a in ApprovalCeiling::ALL { - 1907
for b in ApprovalCeiling::ALL { - 1908
let met = a.meet(b); - 1909
assert!(met.rank() <= a.rank()); - 1910
assert!(met.rank() <= b.rank()); - 1911
} - 1912
} - 1913
} - 1914
- 1915
#[test] - 1916
fn authority_gate_fallback_by_attendance_and_horizon() { - 1917
let auth = authority_of(Autonomy::Assisted, Attendance::Interactive); - 1918
assert_eq!(auth.gate_fallback(Horizon::Turn), GateFallback::Deny); - 1919
assert_eq!(auth.gate_fallback(Horizon::Durable), GateFallback::Deny); - 1920
- 1921
// Only work durable enough to own a commitment has somewhere to park a - 1922
// question; multi-step work inside one session fails closed like a turn. - 1923
let auth = authority_of(Autonomy::Delegated, Attendance::Unattended); - 1924
assert_eq!(auth.gate_fallback(Horizon::Durable), GateFallback::Defer); - 1925
assert_eq!(auth.gate_fallback(Horizon::Session), GateFallback::Deny); - 1926
assert_eq!(auth.gate_fallback(Horizon::Immediate), GateFallback::Deny); - 1927
assert_eq!(auth.gate_fallback(Horizon::Turn), GateFallback::Deny); - 1928
} - 1929
- 1930
#[test] - 1931
fn authority_escalation_refuses_irreversible_assume() { - 1932
let policy = Escalation::AssumeConservative { after_hours: 24 }; - 1933
assert!(policy.permitted_for(Stakes::Reversible)); - 1934
assert!(policy.permitted_for(Stakes::Costly)); - 1935
assert!(!policy.permitted_for(Stakes::Irreversible)); - 1936
assert!(Escalation::WaitIndefinitely.permitted_for(Stakes::Irreversible)); - 1937
assert!(Escalation::AbandonAfter { after_hours: 24 }.permitted_for(Stakes::Irreversible)); - 1938
} - 1939
- 1940
#[test] - 1941
fn authority_autonomy_capped_by_never_widens() { - 1942
for a in Autonomy::ALL { - 1943
for b in Autonomy::ALL { - 1944
let capped = a.capped_by(b); - 1945
assert!(capped.rank() <= a.rank()); - 1946
assert!(capped.rank() <= b.rank()); - 1947
} - 1948
} - 1949
} - 1950
- 1951
#[test] - 1952
fn authority_envelope_covers_paths() { - 1953
let env = test_envelope(PermissionCeiling::WorkspaceWrite); - 1954
assert!(env.covers("edit", &["src/main.rs".to_string()])); - 1955
assert!(env.covers("edit", &["src/deep/nested/file.rs".to_string()])); - 1956
assert!(!env.covers("bash", &["src/main.rs".to_string()])); - 1957
assert!(!env.covers("edit", &["docs/readme.md".to_string()])); - 1958
assert!(!env.covers( - 1959
"edit", - 1960
&["src/main.rs".to_string(), "docs/x.md".to_string()] - 1961
)); - 1962
assert!(!env.covers("edit", &[])); - 1963
} - 1964
- 1965
// ================================================================ - 1966
// Part 9: Narrowing invariant — full combinatorial - 1967
// ================================================================ - 1968
- 1969
#[test] - 1970
fn narrowing_invariant_full_combinatorial() { - 1971
let baseline = Limits::unrestricted(); - 1972
let mut checked = 0u64; - 1973
for &act in &Act::ALL { - 1974
for &horizon in &Horizon::ALL { - 1975
for &stakes in &Stakes::ALL { - 1976
for &evidence in &Evidence::ALL { - 1977
for &clarity in &Clarity::ALL { - 1978
for &attendance in &Attendance::ALL { - 1979
for &autonomy in &Autonomy::ALL { - 1980
for &slice in &[true, false] { - 1981
let mut r = reading_simple(act, horizon, stakes, evidence); - 1982
r.clarity = clarity; - 1983
r.attendance = attendance; - 1984
r.confidence = 0.9; - 1985
r.axis_confidence = Confidences { - 1986
act: 0.9, - 1987
horizon: 0.9, - 1988
stakes: 0.9, - 1989
evidence: 0.9, - 1990
}; - 1991
let auth = authority_of(autonomy, attendance); - 1992
let engagement = derive(&r, &auth, slice); - 1993
assert!( - 1994
engagement.limits.is_at_most(&baseline), - 1995
"widened: {:?}/{:?}/{:?}/{:?}/{:?}/{:?}/{:?} slice={slice}", - 1996
act, - 1997
horizon, - 1998
stakes, - 1999
evidence, - 2000
clarity,
Indexing the workspace…
Vakyartha documentation is discovering safe artifacts, anchors, and source references.