anda_brain 0.12.1

🧠 Anda Brain (大脑) — Autonomous Graph Memory for AI Agents
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
# Anda Brain API 文档(含 TypeScript 类型)

Cloudflare Worker 的对应能力和限制见[逐提交核对](../anda-brain-worker/PORTING_AUDIT.md)与[受信宿主产品契约](../anda-brain-worker/PRODUCT_cn.md)。Worker 已同步来源记录、审阅式修改、恢复和处理代次边界;预算化 Recall、Wiki 和学习运行时仍不提供。

Rust 现要求 Cognitive Nexus 0.13.4:Watch 触发会原子记录状态变化、`watch_fire`
活动及受保护 wake,并提供可重放回执和原生租约。服务现会独立于 Full Maintenance
调度结构化 Watch,从持久化目录发现已驱逐的注册 Space,并在重启后恢复有界扫描。
受信任 Rust 宿主现可在加载 Space 前安装 `ActionBindings`:四分支决策、澄清、固定
Attempt 和原生租约分派接入同一调度器。默认不安装生产执行器;运行时 API 已提供认证后的
待办/回答/后果接口,`BRAIN_RUNTIME_CONFIG` 可装配持久化 inbox 和明确的身份映射,
详见[运行时接入与恢复](RUNTIME_cn.md)。Space fork 不能复制原生运行身份。内部 `memory_runtime/status` 只读当前
配置,不领取任务或授予权限;现有 HTTP payload 和 token scopes 保持兼容。

批量记忆强度代谢跳过 SleepTask/Watch 运行记录;宿主结算错误通过
assessment.settlement_errors 提供给维护模型。

<a id="trusted-host-memory-product-contracts"></a>

## 可信宿主记忆产品合同(v0.12.1)

Rust `product` 模块提供由 Assertion 支撑的 `MemoryRecord`、稳定修订、明确的立场/语义生命周期/存储状态,以及 Evidence 的 typed 来源引用。`Space::product_records`、`product_record`、`product_source` 不负责终端用户认证;嵌入宿主在返回记录、预览、派生 ID 或来源引用前必须检查所有者及来源权限。摘要匹配证明来源关联,不证明推断正确。

`Space::ingest_product` 接收有界、可信的 `SourceIdentity`,包含父会话/会话链标识,自然语言输入不能指定它。`product_prepare`、`product_commit`、`product_change`、`product_discard` 按 caller/operation 保存不可变请求,绑定修订、预览摘要及十分钟有效期。更正撤回旧 Assertion,创建新声明、用户更正 Evidence 和 Activity;不改写原 Concept 名称,也不伪造跨 Proposition 的 supersession。反向更正是新的条件操作。

`Suppress` 归档,`Delete` 清除已声明的有界集合:选定 Proposition/Assertions、引用输入及已记录的反向依赖。未知来源、Concept 级联、保留约束和超过 128 项的集合会被拒绝。写入前先持久接受来源排除与处理 epoch;原生任务不因 API 等待者取消而丢失,Space 重载开放前会恢复已接受操作。旧 Formation/Maintenance/Notes 写入被版本栅栏拦截。变更清空处理 Notes 和 miss cache、停止向新上下文注入旧处理历史,并限制自动 KIP 读取当前 active 数据;可信所有者审计接口保持独立。Recall 返回上下文前重新核对捕获的 epoch。

受管理变更也会阻止预算版 Recall 注入旧历史,并在超时或轮次耗尽返回前检查处理版本。变更前开始的分页须从首页重试,变更后的分页仍可继续。删除会清理已清除内容在操作预览/更正正文中的副本,并废弃受影响的未提交意图,同时保留操作标识和摘要。若独立更正的声明及 Evidence 仍然存在,其来源正文会保留。更正来源读取会检查 Evidence 尚未清除且正文摘要一致。

移除不清理宿主的原聊天、文件、日志、备份、其他独立图谱记录、已交付的上下文或服务商副本。最小来源标识与摘要用于阻止重放。用不含当前排除信息的旧备份覆盖数据库不是保留删除语义的回滚方式。宿主也必须清空自己的注入 Notes,并防止后续对话链再次导入已排除来源。

`MemoryRuntime::{create_record_watch,record_watch,cancel_record_watch}` 使用不可伪造的已认证 `RuntimeCaller` 实现收件人拥有的窄范围订阅。创建持久记录身份,仅启用初始 generation;配置的控制器只获准归档该 Watch,持久标记保证不重新授予已撤销权限。取消使用原生归档,不伪造受保护运行状态;重试不重新启用。已投递的问题是独立工作,仍可见。它们是 Rust 接口,不新增通用模型工具或原生 HTTP 产品管理路由。

`RuntimeConfig::validate` 静态校验不加载 Space、不运行模型、不探测业务服务、不配置授权。可选学习运行时的 `product_readiness` 表示已安装隔离工作流的准备度,区分服务缺失、身份摘要不匹配、校准未审阅及批准门槛。ready 不授予业务部署权限,每项工作的服务与原生权限检查仍必须执行。

Anda Bot 当前通过同级临时 patch 使用这些合同。改用已发布的 0.12.1 crate 后再移除 patch,并保持 registry DB/KIP/Core 的单一类型身份。机制测试不证明真实学习收益或完整成本计量。


## 1) 通用约定

- Base URL: `http://{host}:{port}`
- 认证头:`Authorization: Bearer <token>`
- 分片部署:发送与服务端 `SHARDING_IDX` 相同的 `Shard-Id: <index>`(或 `X-Shard`);默认值为 `0`。
- 若 `ED25519_PUBKEYS` 为空或未提供,旧接口鉴权会关闭;新运行时接口仍要求真实凭据及映射,没有 CWT 验签器时独立后果 HTTP 写入不启用。
- 支持的序列化格式:
  - 请求:`Content-Type: application/json | application/cbor | text/markdown`
  - 响应:`Accept: application/json | application/cbor | text/markdown`
  - 内容协商仅作用于成功响应体。处理器错误使用 JSON,与 `Accept` 无关;中间件限流(`429`/`503`)和未匹配路由可能返回纯文本或空响应体。
- 大多数业务接口都会返回 RPC 包装后的结构体:`RpcResponse<T>`
- MCP 客户端可使用内置的支持流式传输的 HTTP MCP 端点:`/mcp/<space_id>`,也可以使用本地 stdio server:`anda_brain mcp --space-id <space_id> [local|aws]`

CognitiveMemory 2.1 对齐说明:现有 JSON/CBOR/Markdown 请求和鉴权保持兼容;没有新增
五意图 Memory Interface 或标准 after barrier。conversation id 不是处理回执。
维护报告 `skills` 新增可选 `unsupported_reason`,说明没有配置可信学习管线,旧计数
保持零。Watch 的 `disarmed` 兼容字段也统计 Nexus 的 expired;文本 Watch 无已配置的语义求值器时保持 deferred。
模型生成的 Formation 请求不得覆盖宿主捕获的 ingest 或 msgN 绑定;学习/runtime Facet
写入返回 UnsupportedCapability。原始管理 KIP 仍接受符合 Nexus 契约的受权写入。
使用精确 `@2.0.0` schema_ref 的旧 Watch/SleepTask 不能原地改成 2.1,需要显式创建、
重连并核验替代记录后再归档旧记录。

---

## 2) TypeScript 类型定义

```ts
export type TokenScope = 'read' | 'write' | '*';

export interface RpcError {
  message: string;
  data?: unknown;
}

export interface RpcResponse<T> {
  result?: T;
  error?: RpcError;
  next_cursor?: string;
}

export interface InputContext {
  counterparty?: string;
  agent?: string;
  source?: string; // 来源线程/渠道;不是提交或消息的去重键
  topic?: string;
}

export type MessageRole = 'system' | 'user' | 'assistant' | 'tool';

export type MessageContentPart =
  | string
  | {
      type: string;
      text?: string;
      [k: string]: unknown;
    };

export interface Message {
  role: MessageRole;
  content: string | MessageContentPart[];
  name?: string;  // user 或 tool 的名称
  user?: string;  // user ID
  timestamp?: number; // Unix timestamp in milliseconds
}

export interface FormationInput {
  messages: Message[]; // 至少包含一条非空消息(否则 400)
  context?: InputContext;
  timestamp?: string; // RFC 3339;统一为 UTC 毫秒格式,无效或缺省时使用接收时间
}

export interface RecallInput {
  query: string; // 不能为空/纯空白(否则 400)
  context?: InputContext;
  budget?: RecallBudget | null;
}

export interface RecallBudget {
  tokenizer?: 'o200k_base@tiktoken-rs-0.12.0';
  max_tokens?: number; // 1–65536;显式启用后的默认值为 4096
  context_tokens?: number; // 1–131072;默认 32768;整次规划输入规范序列化的累计上限
}

export interface MemoryPolicy {
  version?: number;
  memory_strength_decay_factor?: number;
  recall_reinforcement?: number; // retained for stored-policy compatibility; inert
  correction_penalty?: number; // retained for stored-policy compatibility; inert
  decay_floor?: number;
  stale_event_threshold_days?: number;
  unconsolidated_max_backlog?: number;
  orphan_max_count?: number;
  self_test_queries_per_cycle?: number;
  self_test_token_budget?: number;
  recall_search_threshold?: number; // declared but not consumed yet
  recall_max_rounds?: number;
  recall_budget?: RecallBudget | null;
  shadow_replay_sample?: number;
}

export interface MemoryCitation {
  entity: string;
  type?: string;
  name?: string;
  confidence?: number;
  source?: string;
  created_at?: string;
}

export interface RecallBudgetReceipt {
  tokenizer: string;
  token_limit: number;
  tokens: number;
  context_token_limit: number;
}

export interface RecallOutput {
  answer: string;
  found: boolean;
  uncertainty?: number;
  memories?: MemoryCitation[];
  conversation?: number;
  usage: Usage;
  failed_reason?: string;
  memory_budget?: RecallBudgetReceipt;
}

export interface ProbeInput {
  query: string;
  limit?: number;
}

export interface ProbeOutput {
  found: boolean;
  negative_cached: boolean;
  search_exhaustive?: boolean;
  hits?: MemoryCitation[];
}

export interface MemoryPinInput {
  entity: string; // 图谱实体 ID,例如 C-7、P-3、A-2
  pinned?: boolean; // default true
}

export interface MemoryPinOutput {
  entity: string;
  pinned: boolean;
  updated: number; // 更改的 retention 记录数
}

export interface MemoryForgetInput {
  entities: string[];
  dry_run?: boolean; // default false; inspect a dry run before deletion
}

export interface MemoryForgetEntity {
  entity: string;
  existed: boolean;
  error?: string;
}

export interface MemoryForgetReport {
  dry_run: boolean;
  deleted_concepts: number;
  deleted_propositions: number;
  deleted_assertions: number;
  deleted_evidence: number;
  deleted_activities: number;
  entities?: MemoryForgetEntity[];
}

export interface MemoryMetrics {
  recalls_completed: number;
  entities_recalled: number;
  probe_hits: number;
  probe_misses: number;
  negative_cache_hits: number;
  self_test_tested: number;
  self_test_grounded: number;
  reencode_tasks: number;
  corrections: number;
  decayed: number;
  uncertainty_reports: number;
  uncertainty_sum: number;
  forgotten_entities: number;
  updated_at: number;
}

export interface MemoryGraphCounters {
  concepts: number;
  propositions: number;
  unconsolidated?: number;
  orphans?: number;
  predicate_types?: number;
  as_of?: number;
}

export interface WatchSettlement {
  fired: number;
  conflicted: number;
  disarmed: number;
  deferred: number;
  error?: string;
}

export interface SkillSettlement {
  unsupported_reason?: string;
  graded: number;
  transitions: number;
  conflicted: number;
  error?: string;
}

export interface MemorySettlementReport {
  settled_at: number;
  revised_roots?: unknown[];
  decayed: number;
  decay_ran: boolean;
  new_corrections: number;
  watches: WatchSettlement;
  skills: SkillSettlement;
  decay_error?: string;
  correction_scan_error?: string;
  correction_scan_incomplete: boolean;
  correction_scan_through_seq: number;
  retention: {
    expired_assertions: number;
    archived: number;
    held: number;
    refused: number;
    remaining: number;
    error?: string;
  };
}

export interface SelfTestReport {
  tested_at: number;
  tested: number;
  grounded: number;
  reencode_tasks: number;
  usage: Usage;
}

export interface ShadowEvalInput {
  policy: MemoryPolicy;
  replay_sample?: number; // default from policy, at most 16
}

export interface ShadowReport {
  compared_at: number;
  replayed: number;
  baseline_wins: number;
  candidate_wins: number;
  ties: number;
  judge_errors: number;
  candidate_policy: MemoryPolicy;
  usage: Usage;
  samples?: { query: string; winner: 'baseline' | 'candidate' | 'tie' | 'error'; reason?: string }[];
}

export interface MemoryStatus {
  metrics: MemoryMetrics;
  groundability?: number;
  probe_hit_rate?: number;
  correction_rate?: number;
  avg_uncertainty?: number;
  maintenance_tokens_per_recall?: number;
  graph: MemoryGraphCounters;
  last_settlement?: MemorySettlementReport;
  last_self_test?: SelfTestReport;
  last_shadow?: ShadowReport;
  last_schema_audit?: { audited_at: number; predicates?: Record<string, number> };
}

export interface MaintenanceParameters {
  stale_event_threshold_days?: number; // [1, 365]
  memory_strength_decay_factor?: number; // (0, 1];旧名 confidence_decay_factor 仍被接受
  unconsolidated_max_backlog?: number; // [1, 10000];旧名 unsorted_max_backlog 仍被接受
  orphan_max_count?: number; // [1, 10000]
}

export interface MaintenanceInput {
  trigger?: 'scheduled' | 'threshold' | 'on_demand';
  scope?: 'full' | 'quick' | 'daydream'; // 默认 'daydream'
  timestamp?: string; // 规范 UTC:YYYY-MM-DDTHH:mm:ss.SSSZ
  parameters?: MaintenanceParameters;
}

export interface AddSpaceTokenInput {
  scope: TokenScope; // 铸造 "*" 需要 "*" scope 的 CWT
  name: string; // 必填,空间内唯一
  expires_at?: number; // Unix timestamp in milliseconds
  labels?: string[]; // wiki ACL 标签;缺省 = 不受限,[] = 仅无标签内容
}

export interface RevokeSpaceTokenInput {
  token?: string; // 完整 token 值……
  name?: string; // ……或唯一 token 名称(两者必填其一)
}

export interface UpdateSpaceInput {
  name?: string;
  description?: string;
  public?: boolean;
  wiki_digest?: boolean; // 开启 WikiDigest 图谱蒸馏(默认关闭)
  wiki_audit_reads?: boolean; // 外部 wiki 读操作写审计事件(默认关闭)
  wiki_acl_defaults?: Record<string, string>; // namespace -> 默认 ACL 标签
  memory_policy?: MemoryPolicy; // 替换空间策略;省略的成员使用服务端默认值
}

export interface FormationRestartInput {
  conversation: number;
}

export interface CreateOrUpdateSpaceInput {
  user: string;
  space_id: string;
  tier: number;
}

export interface GetOrInitUserInput {
  user: string;
  name?: string;
}

// ── Wiki:版本化参考文档与可校验引用 ──────────────────────────────

export type WikiDocStatus = 'active' | 'archived';
export type WikiSearchMode = 'chunks' | 'docs';

export interface WikiCommitInput {
  doc_id?: number; // 缺省 = 创建新文档
  parent_version?: number; // 更新必填(CAS);过期返回 409
  namespace?: string; // 默认 "default"
  slug?: string; // 展示用;缺省从标题派生
  title: string;
  content: string; // 全量 Markdown(非 diff);规范化后 ≤ 1 MiB
  tags?: string[]; // 缺省 = 更新时保持原值
  acl_label?: string; // 缺省 = 保持/继承 namespace 默认;"" 清除
  source_uri?: string; // 缺省 = 保持原值
  message?: string; // 提交说明
  metadata?: Record<string, unknown>; // 缺省 = 保持原值
}

export interface WikiDocInfo {
  id: number;
  namespace: string;
  slug: string;
  title: string;
  status: WikiDocStatus;
  current_version: number;
  current_checksum: string; // "sha3-256:..."
  tags: string[];
  acl_label?: string;
  source_uri?: string;
  metadata?: Record<string, unknown>;
  created_by: string;
  updated_by: string;
  created_at: number;
  updated_at: number;
}

export interface WikiVersionInfo {
  id: number;
  doc_id: number;
  parent_version?: number;
  checksum: string;
  size: number;
  author: string;
  message?: string;
  created_at: number;
}

export interface WikiCommitOutput {
  doc: WikiDocInfo;
  version: WikiVersionInfo;
  chunks: number;
  created: boolean;
  idempotent: boolean; // true = 内容未变,零写入
}

export interface WikiSearchInput {
  query: string; // BM25 关键词:术语、产品名、错误码优于整句
  namespaces?: string[];
  doc_ids?: number[];
  tags?: string[];
  top_k?: number; // 1-50,默认 8
  mode?: WikiSearchMode; // 'docs' = 每篇文档只返回最佳命中
  expand?: number; // 0-2 邻域扩展;引用范围相应扩大
}

export interface WikiCitation {
  uri: string; // wiki://{space}/{doc_id}@{version_id}#{start}-{end}
  doc_id: number;
  version_id: number;
  chunk_id: number;
  heading_path: string[];
  anchor: string; // 稳定章节锚点,可用于按节读取
  byte_range: [number, number];
  checksum: string; // 可经 /wiki/verify 校验
  quote: string;
}

export interface WikiHit {
  text: string;
  doc_title: string;
  heading_path: string[];
  citation: WikiCitation;
}

export interface WikiSearchOutput {
  hits: WikiHit[];
  total_docs_matched: number;
}

export type WikiSelector =
  | { type: 'toc' }
  | { type: 'section'; anchor: string }
  | { type: 'range'; start: number; end: number }
  | { type: 'full' };

export interface WikiReadInput {
  doc_id: number;
  version?: number; // 读取历史版本(time-travel)
  selector?: WikiSelector; // 默认 { type: 'full' }
}

export interface WikiTocEntry {
  anchor: string;
  heading_path: string[];
  byte_start: number;
  byte_end: number;
}

export interface WikiReadOutput {
  doc_id: number;
  version_id: number;
  is_current: boolean;
  title: string;
  status: WikiDocStatus;
  checksum: string;
  size: number;
  toc?: WikiTocEntry[]; // selector 为 'toc' 时返回
  content?: string; // section/range/full 时返回
  byte_range?: [number, number];
  truncated: boolean; // 全文读取有上限(256 KiB)
}

export interface WikiVerifyInput {
  uri?: string; // wiki:// 引用 URI;或使用下方显式字段
  doc_id?: number;
  version_id?: number;
  byte_range?: [number, number];
  checksum?: string; // 提供时与重算校验和比对
}

export type WikiVerifyStatus = 'valid' | 'superseded' | 'invalid' | 'not_found';

export interface WikiVerifyOutput {
  status: WikiVerifyStatus; // 'superseded' = 内容完好但已有新版本
  current_version?: number;
  checksum?: string; // 从不可变内容重算
  quote?: string;
}

export interface WikiBundleEntry {
  path: string; // bundle 相对路径,如 "guides/setup.md"
  content: string;
}

export interface WikiImportInput {
  entries: WikiBundleEntry[]; // OKF v0.1 bundle 文件(Markdown + YAML frontmatter)
  namespace?: string; // 默认 "default";bundle 以 namespace 为单位往返
}

export type WikiImportStatus = 'created' | 'updated' | 'unchanged';

export interface WikiImportOutput {
  created: number;
  updated: number;
  unchanged: number; // checksum 幂等:重复导入零版本膨胀
  docs: { path: string; doc_id: number; version_id: number; status: WikiImportStatus }[];
  skipped?: { path: string; reason: string }[];
}

export interface WikiExportOutput {
  namespace: string;
  entries: WikiBundleEntry[]; // concept .md 文件 + index.md + manifest.json
  docs: number;
}

export interface WikiEventInfo {
  id: number;
  // DocCreated | VersionCommitted | DocArchived | DocRestored | OrphanSwept
  // | CitationVerifyFailed | ImportCompleted | ExportCompleted
  // | DigestExtracted | DigestFailed | WikiQueried | WikiRead | StaleReport | EventsPruned
  kind: string;
  doc_id?: number;
  version_id?: number;
  actor: string;
  detail?: Record<string, unknown>;
  created_at: number;
}

export interface WikiDigestReport {
  digested: number; // 已提取或复用已有结果的文档代数
  facts: number; // 本轮处理的文档账本中保留的断言数,不表示事实完整性
  superseded: number; // 经明确核验或来源撤回而 retract 的本来源断言数
  skipped: number; // 无需提取的已归档、带标签或评测文档
  failed: number; // 失败且仍在待处理队列中的文档;再次调用可重试
  citations_checked: number;
  citations_invalid: number;
  usage: Usage;
}

export interface McpServerConfig {
  space_id: string;
  auth_token?: string;
  auto_create_space?: boolean;
  auto_create_tier?: number;
}

export interface McpHttpServerConfig {
  path_prefix?: string; // 默认 "/mcp"; client 连接 {path_prefix}/{space_id}
  allowed_hosts?: string[]; // rmcp 默认只允许 loopback;公司域名需要显式配置
  allowed_origins?: string[]; // 浏览器型 MCP client 使用
  auto_create_space?: boolean;
  auto_create_tier?: number;
}

export interface Concept {
  id: string;
  kind: 'concept';
  space_id?: string;
  schema_ref?: string;
  key?: string;
  name?: string;
  canonical_id?: string;
  aliases?: string[];
  attributes?: Record<string, unknown>;
  facets?: Record<string, Record<string, unknown>>;
  retention?: { retention_class?: string; expires_at?: string; legal_hold?: boolean };
  _system?: Record<string, unknown>;
}

export interface ModelConfig {
  family: string; // "gemini", "anthropic", "openai", "deepseek", "mimo" etc.
  model: string;
  api_base: string;
  api_key: string;
  disabled?: boolean;
  label?: string;
  effort?: 'minimal' | 'low' | 'medium' | 'high' | 'max';
  bearer_auth?: boolean;
  stream?: boolean;
  context_window?: number;
  max_output?: number;
}

export interface SpaceTier {
  tier: number;
  updated_at: number; // Unix timestamp in milliseconds
}

export interface SpaceToken {
  token: string;
  name: string;
  scope: TokenScope;
  usage: number;
  created_at: number; // Unix timestamp in milliseconds
  updated_at: number; // Unix timestamp in milliseconds
  expires_at?: number; // Unix timestamp in milliseconds
  labels?: string[]; // wiki ACL 标签:[] 仅可见无标签内容;缺省不受限
}

export interface StorageStats {
  [k: string]: number | string | boolean | null;
}

export interface SpaceInfo {
  id: string;
  name?: string;
  description?: string;
  owner: string;
  db_stats: StorageStats;
  concepts: number;
  propositions: number;
  conversations: number;
  public: boolean;
  tier: SpaceTier;
  formation_usage: Usage;
  recall_usage: Usage;
  maintenance_usage: Usage;
  formation_processed_id: number;
  maintenance_processed_id: number;
  maintenance_at: MaintenanceAt;
  wiki_docs: number;
  wiki_chunks: number;
  wiki_versions: number;
  wiki_queries: number;
  wiki_digested: number; // 观测用的版本高水位,不代表所有文档都已处理
  wiki_stale_docs: number; // 最近一次 housekeeping 陈旧扫描结果
}

export interface FormationStatus {
  id: string;
  concepts: number;
  propositions: number;
  conversations: number;
  formation_processing: boolean;
  maintenance_processing: boolean;
  formation_processed_id: number;
  maintenance_processed_id: number;
  maintenance_at: MaintenanceAt;
}

export interface MaintenanceAt {
  daydream: number;
  full: number;
  quick: number;
  /** 最近一次 maintenance 任务的启动时间(unix 毫秒),0 表示尚未启动过。 */
  start_at: number;
}

export interface Usage {
  /** 发送给 LLM 的输入 token 数。 */
  input_tokens: number;
  /** 从 LLM 接收的输出 token 数。 */
  output_tokens: number;
  /** 执行过程中命中缓存的 token 数。 */
  cached_tokens: number;
  /** 对模型、agent 或工具发起的请求次数。 */
  requests: number;
}

export interface AgentOutput {
  content: string;
  conversation?: number;
  failed_reason?: string;
  usage?: Usage;
  model?: string;
  [k: string]: unknown;
}

export type ConversationStatus =
  | 'submitted'
  | 'working'
  | 'idle'
  | 'completed'
  | 'failed'
  | 'cancelled';

export interface Conversation {
  _id: number;
  user: string;
  thread?: string;
  label?: string;
  messages: Message[];
  resources: unknown[];
  artifacts: unknown[];
  status: ConversationStatus;
  failed_reason?: string | null;
  period: number;
  created_at: number;
  updated_at: number;
  usage: Usage;
  steering_messages?: string[];
  follow_up_messages?: string[];
  ancestors?: number[];
}

export interface ConversationDelta {
  _id: number;
  messages: unknown[];
  artifacts: unknown[];
  status: ConversationStatus;
  usage: Usage;
  failed_reason?: string | null;
  updated_at: number;
  child?: number | null;
}

export interface ServiceInfo {
  name: string;
  version: string;
  sharding: number;
  description: string;
}

export type KipOperation = string | {
  op_id?: string;
  language?: 'KQL' | 'KML' | 'META'; // 声明仅供参考;只读限制以解析后的命令为准
  command?: string;
  ast?: unknown;
  parameters?: Record<string, unknown>;
  idempotency_key?: string;
  options?: { extensions?: Record<string, unknown> };
  extensions?: Record<string, unknown>;
};

export interface KipRequest {
  command?: string; // 单条命令;与 `operations` 互斥
  operations?: KipOperation[]; // 一次往返执行多条命令
  execution?: { mode: 'independent' | 'sequence' | 'atomic'; on_error?: 'stop' | 'continue'; isolation?: string; idempotency_key?: string; extensions?: Record<string, unknown> }; // 多于一条操作时必填
  read?: { snapshot_token?: string; extensions?: Record<string, unknown> }; // 把所有操作绑定到同一读取坐标
  parameters?: Record<string, unknown>; // 绑定到命令中 `:placeholder` 的值
  dry_run?: boolean; // 仅校验与规划,不提交
}

export interface KipError {
  code: string; // 注册表名称,如 "NotFoundOrNotVisible",不再是数字码
  message: string;
  category?: string;
  hint?: string;
  retry?: { class: string; after_ms?: number };
  details?: unknown;
}

export interface KipOperationResult<T> {
  op_id?: string;
  status: 'succeeded' | 'failed' | 'skipped' | 'rolled_back' | 'no_effect';
  result?: T;
  context?: unknown;
  error?: KipError;
  warnings?: unknown[];
  next_cursor?: string;
  receipt?: unknown;
  extensions?: Record<string, unknown>;
}

export interface KipResponse<T> {
  kip: '2.0';
  request_id?: string;
  status: 'succeeded' | 'failed' | 'partial' | 'outcome_unknown';
  results: KipOperationResult<T>[];
  execution?: unknown;
  context?: unknown;
  snapshot?: { space_id?: string; snapshot_seq: number; schema_environment_version?: number; snapshot_token?: string; extensions?: Record<string, unknown> };
  receipt?: unknown;
  warnings?: unknown[];
  next_cursor?: string;
  error?: KipError; // 仅当请求在进入 operations 之前就失败时才设置
  extensions?: Record<string, unknown>;
}
```

> **KIP 2.0。** 普通错误在 operation 层,信封错误才在请求层,客户端两处都要读。
> `outcome_unknown` 既不是成功也不是失败:写入可能已经提交,正确做法是按幂等键
> 查事务,而不是当作没发生过重发一次。

---

## 3) MCP Server

默认情况下,HTTP 服务会暴露支持流式传输的 HTTP MCP 端点;`MCP_HTTP_ENABLED=false` 可关闭它:

```text
https://your-brain-host/mcp/my_space_001
```

Client 通过 URL path 选择目标记忆空间,并使用与 REST 相同的 CWT 或 space token:`Authorization: Bearer <token>`。这适合公司内部多用户智能体平台:为每位员工分配一个 Brain space,员工的智能体通过 MCP 连接自己的空间。

Anda Brain 也可作为本地 MCP stdio server 运行:

```bash
MCP_AUTH_TOKEN="$SPACE_TOKEN" \
  anda_brain mcp --space-id my_space_001 local --db ./data
```

两种 MCP 模式都复用 HTTP 服务的模型、认证和存储配置。stdio 模式的嵌套 storage 子命令可省略(内存开发模式),也可以使用 `local --db ./data` 持久化到本地,或使用 `aws --bucket ... --region ...` 连接 S3。

| Tool | Input | Output | Scope |
| ---- | ----- | ------ | ----- |
| `anda_brain_remember_conversation` | `FormationInput` 形状(`messages`, `context`, `timestamp`) | `AgentOutput` | `write` |
| `anda_brain_recall_memory` | `RecallInput` 形状(`query`, `context`,可选 `budget`) | `AgentOutput` | `read` |
| `anda_brain_run_maintenance` | `MaintenanceInput` 形状 | `AgentOutput` | `write` |
| `anda_brain_get_space_info` | 无 | `SpaceInfo` | `read` |
| `anda_brain_get_formation_status` | 无 | `FormationStatus` | `read` |
| `anda_brain_execute_kip_readonly` | `{ command?, commands?, parameters?, dry_run? }` | `KipResponse` | `read` |
| `anda_brain_get_or_init_user` | `{ user, name? }` | `Concept` | `write` |
| `anda_brain_list_conversations` | `{ collection?, cursor?, limit? }` | `{ conversations, next_cursor }` | `read` |
| `anda_brain_get_conversation` | `{ conversation_id, collection?, delta?, messages_offset?, artifacts_offset? }` | `Conversation` 或 `ConversationDelta` | `read` |
| `anda_brain_wiki_search` | wiki 查询、过滤条件和结果上限 | `WikiSearchOutput` | `read` |
| `anda_brain_wiki_read` | 文档 ID 和读取选择器 | `WikiReadOutput` | `read` |
| `anda_brain_wiki_commit` | 文档字段和完整 Markdown 内容 | `WikiCommitOutput` | `write` |
| `anda_brain_wiki_verify` | citation URI 或显式引用字段 | `WikiVerifyOutput` | `read` |

MCP 只读 KIP 工具使用 `commands`,并为批量读取补上 independent 执行模式。HTTP `/execute_kip_readonly` 使用 `operations`,批量请求须显式提供 `execution.mode`。Wiki MCP 工具在启用 `wiki` feature 时提供;服务二进制始终启用该 feature。

当设置了 `ED25519_PUBKEYS` 时,远程 MCP 客户端需要携带 `Authorization` bearer token;stdio 模式请通过 `MCP_AUTH_TOKEN` 或 `--mcp-auth-token` 配置 CWT 或 space token。`read` 工具也可无 token 访问 public space。远程 MCP 经过公司域名或反向代理暴露时,请设置 `MCP_HTTP_ALLOWED_HOSTS`。本地 stdio 开发可用 `--mcp-auto-create-space` 自动创建目标 space;远程开发可用 `MCP_HTTP_AUTO_CREATE_SPACE=true`,但在远程自动创建不存在的 space 前,必须配置好 `ED25519_PUBKEYS`,且客户端需提供该 space 拥有 `write` 范围的 CWT。

---

## 4) 接口列表

## 4.1 公共接口

### GET `/favicon.ico` 和 GET `/apple-touch-icon.webp`

- 说明:产品图标静态资源
- 鉴权:无
- 响应:`image/x-icon` 或 `image/webp`

### GET `/info`

- 说明:服务信息
- 鉴权:无
- 响应(JSON):`ServiceInfo`

### GET `/SKILL.md`

- 说明:返回技能描述 Markdown
- 鉴权:无
- 响应:`text/markdown`

---

## 4.2 空间业务接口(`/v1/{space_id}`)

### POST `/v1/{space_id}/formation`

- 作用:提交记忆写入任务
- 鉴权:SpaceToken/CWT `write`
- 请求体:`FormationInput`(Markdown 模式下也允许原始字符串)
- 观察时间接受带时区偏移和不同小数精度的 RFC 3339,统一为 `YYYY-MM-DDTHH:mm:ss.SSSZ`。无效或缺省的时间戳使用已保存的会话创建时间,重试沿用同一回退时间,并保留原始输入。Markdown 原文按一条 user 消息原样捕获,同样提供 `:msg1` Evidence 绑定。
- 响应(JSON/CBOR):`RpcResponse<AgentOutput>`
- 响应(Markdown):`string`(仅返回 `AgentOutput.content`)

### POST `/v1/{space_id}/recall`

- 作用:按自然语言召回记忆
- 鉴权:SpaceToken/CWT `read`(公开空间免鉴权,私有空间需有效 token)。带标签限制的 space token 会收到 `403`,因为 agentic Recall 可跨所有 wiki 标签读取。
- 请求体:`RecallInput`(Markdown 模式下也允许原始字符串)
- 响应(JSON/CBOR):`RpcResponse<AgentOutput>`
- 响应(Markdown):纯文本 `AgentOutput.content`

### POST `/v1/{space_id}/recall_structured`

- 作用:返回合成答案、从检索轨迹提取的记忆引用、`found` 和可选不确定性。
- 鉴权和请求体:同 `/recall`;带标签限制的 token 返回 `403`。
- 响应(JSON/CBOR):`RpcResponse<RecallOutput>`
- 响应(Markdown):纯文本 `RecallOutput.answer`

<a id="recall-budget-contract"></a>

### Recall 预算合同

可选 `budget` 启用宿主选择的 JSON 记忆包,放在 `content` 中,替代自由生成的答案。
`memory_policy.recall_budget` 可对所有 Recall 强制同一上限;请求只能收紧,不能提高或
关闭策略。策略和请求均省略/null 时保持旧行为。

每次请求先按当前问题执行有界、参数化的概念搜索。只有未完成的承诺(`pending`/`blocked`)
作为必需项;已结束承诺作为可选历史候选。返回的紧凑记录保留 ID、版本和来源,省略重复的
LegacyRecord 原文,并在 `recall_detail` 中列出省略字段。必需属性和原生程序检查不会被
摘要掉。完整 Primer 仍进入规划上下文,交付包仅带紧凑的执行依据;需要详情时可用 KQL
字段投影读取。

可选候选逐条装包;`coverage.partial`、`coverage.omitted` 明示不完整交付。累计模型输入
预算耗尽时,宿主仍可返回已授权读取的候选,同时附上必需警告 `recall_context_budget_exhausted`。
这类响应是局部 `bounded` 包,不是模型合成答案或相关性证明。必需读取不完整,或输出预算
连完整约束和警告都容纳不了时,仍返回 `budget_insufficient`;提供方调用失败也仍按失败处理。

固定 codec 对 compact JSON 记忆包全文计数,含转义和 coverage;`context_tokens`
另行限制本次 Recall 所有规划输入规范序列化的累计 token。提供商消息模板、计费和
RPC/MCP 传输副本不属于这些范围。不根据模型名猜编码,也不回退字符数估算。
预算响应不会附带历史、thoughts、artifacts 或工具调用作为记忆旁路。

`recall_structured` 将同一包放在 `answer`,不从完整 trace 另外复制 citations,并增加
`memory_budget`:`tokenizer`、`token_limit`、`tokens`、`context_token_limit`;此模式的
`found` 仅表示交付了非 Primer 候选,不表示已证明语义相关或完整。Markdown 返回同一
包文本。`budget_insufficient` 或带静态 `failed_reason` 的字面量 `null` 表示不可用/
不充分,不能当成成功的空答案。预算允许时,包内可选的 `failed_reason` 字段携带同一
固定错误代码,用于区分模型调用失败和 token 预算耗尽;该字段计入包的 token 总数,
不会交付提供方的原始错误内容。预算失败使用固定代码:`recall_output_budget_exhausted`、
`recall_required_read_incomplete`、`recall_context_budget_exhausted`、
`recall_deadline_reached`、`recall_model_unavailable`、
`recall_planner_incomplete` 或 `recall_procedure_window_incomplete`。
记忆包始终是候选读取(`semantic_complete=false`、`action_ready=false`)。
必要约束和警告作为整体保留;无法容纳时不交付普通记忆,不用估算或自由答案绕过预算。

### POST `/v1/{space_id}/maintenance`

- 作用:触发维护(睡眠/整理)
- 鉴权:SpaceToken/CWT `write`
- 请求体:`MaintenanceInput`
- 响应:`RpcResponse<AgentOutput>`

`parameters` 中明确提供的值覆盖空间策略;省略项使用空间策略的默认值。同一份有效参数同时用于确定性 settlement 和维护模型,不修改持久化的空间策略。

### POST `/v1/{space_id}/memory/pin`

- 作用:固定或取消固定一个图谱实体;固定后其记忆强度不参与闲置衰减。
- 鉴权:SpaceToken/CWT `write`
- 请求体:`MemoryPinInput`;`pinned` 默认 `true`。
- 响应:`RpcResponse<MemoryPinOutput>`

### POST `/v1/{space_id}/memory/forget`

- 作用:物理删除图谱实体;删除前可用 `dry_run: true` 检查影响。
- 鉴权:SpaceToken/CWT `write`
- 请求体:`MemoryForgetInput`;`dry_run` 默认 `false`。
- 响应:`RpcResponse<MemoryForgetReport>`;单个实体的错误位于 `result.entities`。

接受显式的 Concept(`C-*`)、Proposition(`P-*`)、Assertion(`A-*`)、Evidence(`E-*`)和 Activity(`X-*`)ID,包括保存消息原文的 Evidence。原生 legal hold 和引用检查仍然生效,成功清除后保留已擦除身份桩。计数分别报告各类被清除记录,包含级联删除。此操作清除所选图谱记录;已保存的会话、wiki 文档及外部副本各有独立生命周期。
引用已清除元素的产品预览会在报告成功前清理;预览清理失败会写入该实体的错误字段。

### GET `/v1/{space_id}/memory_status`

- 用途:读取记忆统计和最近一次维护报告。
- 鉴权:SpaceToken/CWT `read`;公开空间允许匿名读取。
- 响应:`RpcResponse<MemoryStatus>`,保持 JSON/CBOR/Markdown 协商。
- `result.last_settlement.correction_scan_incomplete`:本次有界扫描尚未证明 backlog 已耗尽,后续维护会从事务内部继续。
- `result.last_settlement.correction_scan_through_seq`:已完整读取的最大事务序号。
- `result.last_settlement.correction_scan_error`:扫描失败原因;失败不会推进游标。
- 这些字段表示更正发现进度,不表示模型完成审查或 Watch 获得完整授权覆盖。

### POST `/v1/{space_id}/execute_kip_readonly`

- 作用:执行 KIP 请求(只读模式,适用于查询)
- 鉴权:SpaceToken/CWT `read`(公开空间免鉴权,私有空间需有效 token)
- 请求体:`KipRequest`,或直接一个 JSON 字符串(按单条命令解析)
- 若 `operations` 超过一项,必须提供 `execution.mode`;即使 HTTP 返回 `200`,也要检查顶层 `status` 和每个 `results[].status`。
- 响应:`KipResponse<T>`(结果类型随命令而定)
- 只读由命令**解析出的语义**决定:无论请求怎么标注,KML 变更都会在这里被拒绝

### POST `/v1/{space_id}/get_or_init_user`

- 作用:按给定 principal 获取或初始化用户 Concept 节点
- 鉴权:SpaceToken/CWT `write`
- 请求体:`GetOrInitUserInput`
- 省略 `name` 时保留已有显示名;显式提供 `name` 时更新显示名。首次创建且未提供姓名时,使用 key 作为初始显示名。
- 响应:`RpcResponse<Concept>`

### GET `/v1/{space_id}/info`

- 作用:获取空间状态和统计
- 鉴权:SpaceToken/CWT `read`(公开空间免鉴权,私有空间需有效 token)
- 响应:`RpcResponse<SpaceInfo>`

### GET `/v1/{space_id}/status`

- `/v1/{space_id}/info` 的别名,鉴权和响应相同。

### POST `/v1/{space_id}/probe`

- 作用:无需模型的检索可达性检查;`found:false` 不代表信念被否定。
- 鉴权:沿用 Space 的 `read` 权限和公开空间读取规则。
- 请求:`{"query":"...", "limit":8}`。
- 响应:`RpcResponse<ProbeOutput>`,含 `found`、`negative_cached`、可选 `hits` 和可选 `search_exhaustive`。后者来自 SEARCH result 顶层覆盖字段;缺省表示未知,有剩余分页时为 false。负缓存仅保存明确穷尽的检索 miss,不能作为不存在或信念被否定的证明。

### GET `/v1/{space_id}/formation_status`

- 作用:获取记忆写入状态(更轻量级的接口,专门用于监控记忆写入进度)
- 鉴权:SpaceToken/CWT `read`(公开空间免鉴权,私有空间需有效 token)
- 响应:`RpcResponse<FormationStatus>`
- 此接口是轻量监控,游标不是逐任务成功证明。Rust 宿主可用 `Space::processing_report` / `wait_for_processing` 区分排队、运行、失败、取消、中断和超时;超时后继续核对同一 conversation ID,不重新提交。

### GET `/v1/{space_id}/conversations/{conversation_id}?collection=<collection>`

- 作用:获取单条会话详情
- 鉴权:SpaceToken/CWT `read`(公开空间免鉴权,私有空间需有效 token);带 ACL 标签限制的 token 返回 `403`——会话持久化了完整的 agent 运行历史,不受标签过滤;`collection=recall` 对公开空间的匿名访问也返回 `403`(私有期的 recall 运行可能内嵌 labeled wiki 内容)
- Query:
  - `collection?: string` // "formation"(默认)、"recall" 或 "maintenance";未知值返回 `400`
- 响应:`RpcResponse<Conversation>`

### GET `/v1/{space_id}/conversations/{conversation_id}/delta?collection=<collection>&messages_offset=<n>&artifacts_offset=<n>`

- 作用:按客户端已消费的 offset 获取会话增量更新
- 鉴权:SpaceToken/CWT `read`(公开空间免鉴权,私有空间需有效 token);带 ACL 标签限制的 token 返回 `403`(`collection=recall`:公开空间匿名访问同样拒绝)
- Query:
  - `collection?: string` // "formation"(默认)、"recall" 或 "maintenance";未知值返回 `400`
  - `messages_offset?: number` // 仅返回该偏移量之后的新消息,默认 `0`
  - `artifacts_offset?: number` // 仅返回该偏移量之后的新 artifacts,默认 `0`
- 响应:`RpcResponse<ConversationDelta>`

### GET `/v1/{space_id}/conversations?collection=<collection>&cursor=<cursor>&limit=<n>`

- 作用:分页列出会话
- 鉴权:SpaceToken/CWT `read`(公开空间免鉴权,私有空间需有效 token);带 ACL 标签限制的 token 返回 `403`(`collection=recall`:公开空间匿名访问同样拒绝)
- Query:
  - `collection?: string` // "formation"(默认)、"recall" 或 "maintenance";未知值返回 `400`
  - `cursor?: string`
  - `limit?: number`
- 响应:`RpcResponse<Conversation[]>`(并通过 `next_cursor` 给出下一页游标)

---

## 4.3 Wiki 接口(`/v1/{space_id}/wiki`)

Wiki 是空间的版本化参考记忆(政策、手册、SOP、API 文档)。写入是 Git 式不可变提交(CAS 并发控制);检索返回可校验的 `wiki://` 引用。ACL:文档可携带 `acl_label`;带 `labels` 的 space token 仅可见无标签内容 + 所授标签——查询预过滤后仍核对文档当前版本、状态和权限。权限检查与版本选择共享同一文档快照。公开空间的匿名读者仅可见无标签内容;越权一律表现为 404。

Wiki 专属错误语义:`409` 提交冲突(`RpcError.data.current_version` 为应 rebase 的版本)、`413` 内容超 1 MiB、`404` 不存在或 ACL 拒绝。

目录由 Markdown 的 ATX 标题(`#`–`######`)生成,独立于检索分块;读取 section 包含该标题的子章节。锚点按标题派生,同名标题加序号。`full`、`range` 和 `section` 均最多返回 256 KiB;`truncated` 为 true 时,使用返回的 `byte_range` 继续读取。历史和引用校验只接受已发布 parent 链中的版本,失败提交的残留不是历史。

OKF 导入按完整文件替换 title、tags、resource、type 和未知 frontmatter 键值,删除字段会清空对应导入状态;已有 ACL 与其他宿主 metadata 保留。标题或标签经 commit 修改后,导出仍保留未知键值。YAML 使用标准解析和序列化,不承诺注释或原始排版保真。

WikiDigest 默认关闭。开启后,commit、archive、restore 和 ACL 变化持久化文档待处理标记;每轮最多处理 20 个文档,启动、维护后或显式调用时推进,失败文档保留待重试。正文校验和未变时复用已有账本,不再调用模型。提取漏项不是撤回依据:对旧断言必须在每个正文批次中明确核验为 `absent`,缺失、重复或 `unknown` 判断均保留原断言。归档或加标签由后续 digest 撤回本来源断言;该图谱同步是异步的。模型处理中发生文档变更时,不发布旧结果,保留新一代待处理标记。观测高水位 `wiki_digested` 不表示队列已经清空。


### POST `/v1/{space_id}/wiki/docs`

- 作用:提交文档(创建;或携带 `doc_id` + `parent_version` 做 CAS 更新);同内容提交为零写入
- 鉴权:SpaceToken/CWT `write`
- 请求体:`WikiCommitInput`(也接受原始 Markdown 字符串,标题取首个标题行)
- 响应:`RpcResponse<WikiCommitOutput>`

### GET `/v1/{space_id}/wiki/docs?namespace=<ns>&status=<status>&tag=<tag>&cursor=<cursor>&limit=<n>`

- 作用:分页列出文档
- 鉴权:SpaceToken/CWT `read`(公开空间免鉴权;ACL 标签生效)
- 响应:`RpcResponse<WikiDocInfo[]>`(下一页游标经 `next_cursor` 返回)

### GET `/v1/{space_id}/wiki/docs/{doc_id}`

- 作用:文档元信息 + 目录(TOC)
- 鉴权:SpaceToken/CWT `read`(公开空间免鉴权;ACL 标签生效)
- 响应:`RpcResponse<{ doc: WikiDocInfo; toc: WikiTocEntry[] }>`

### GET `/v1/{space_id}/wiki/docs/{doc_id}/content?version=<id>&anchor=<anchor>&start=<n>&end=<n>`

- 作用:渐进读取——`anchor` 读单节、`start`+`end` 读字节区间、均不传读受限全文;`version` 读历史版本
- 鉴权:SpaceToken/CWT `read`(公开空间免鉴权;ACL 标签生效)
- 响应:`RpcResponse<WikiReadOutput>`

### GET `/v1/{space_id}/wiki/docs/{doc_id}/versions?cursor=<cursor>&limit=<n>`

- 作用:版本历史(不可变提交链)
- 鉴权:SpaceToken/CWT `read`(公开空间免鉴权;ACL 标签生效)
- 响应:`RpcResponse<WikiVersionInfo[]>`(下一页游标经 `next_cursor` 返回)

### POST `/v1/{space_id}/wiki/docs/{doc_id}/archive`

- 作用:归档文档(退出检索,仍可按 id 读取,可恢复)
- 鉴权:SpaceToken/CWT `write`
- 响应:`RpcResponse<WikiDocInfo>`

### POST `/v1/{space_id}/wiki/docs/{doc_id}/restore`

- 作用:恢复归档文档进入检索
- 鉴权:SpaceToken/CWT `write`
- 响应:`RpcResponse<WikiDocInfo>`

### POST `/v1/{space_id}/wiki/search`

- 作用:BM25 关键词检索,返回片段与可校验引用
- 鉴权:SpaceToken/CWT `read`(公开空间免鉴权;ACL 标签生效)
- 请求体:`WikiSearchInput`(也接受原始查询字符串)
- 响应:`RpcResponse<WikiSearchOutput>`

### POST `/v1/{space_id}/wiki/verify`

- 作用:对照不可变存储校验引用
- 鉴权:SpaceToken/CWT `read`(公开空间免鉴权;ACL 标签生效)
- 请求体:`WikiVerifyInput`(也接受原始 `wiki://` URI 字符串)
- 响应:`RpcResponse<WikiVerifyOutput>`

### GET `/v1/{space_id}/wiki/events?kind=<kind>&doc_id=<id>&cursor=<cursor>&limit=<n>`

- 作用:查询 append-only 审计日志(写入、导入、蒸馏;开启 `wiki_audit_reads` 后含读操作)
- 鉴权:SpaceToken/CWT `read`;受 ACL 标签限制的 token 返回 `403`
- 响应:`RpcResponse<WikiEventInfo[]>`(下一页游标经 `next_cursor` 返回)

### POST `/v1/{space_id}/wiki/import`

- 作用:导入 OKF v0.1 bundle;checksum 幂等(重复导入零版本膨胀);未知 frontmatter 键值按结构保留;YAML 注释、字段顺序及标量排版不保留
- 鉴权:SpaceToken/CWT `*`(全量 scope)
- 请求体:`WikiImportInput`
- 响应:`RpcResponse<WikiImportOutput>`

### GET `/v1/{space_id}/wiki/export?namespace=<ns>`

- 作用:按 namespace 导出 OKF bundle(concept `.md` + `index.md` + 含校验和的 `manifest.json`);可在空库完整重放
- 鉴权:SpaceToken/CWT `*`(全量 scope)
- 响应:`RpcResponse<WikiExportOutput>`

### POST `/v1/{space_id}/wiki/digest`

- 作用:把待处理 wiki 版本蒸馏进 Cognitive Nexus(每条事实写成 Proposition + 归属于 Brain 的 Assertion,并引用对应段落作为 Evidence);经完整正文批次明确核验不再支持的旧断言,digest 撤回自己的 Assertion;漏提取或未知判断不会触发撤回,Proposition 与他人的 Assertion 不受影响(需先 `update_space {"wiki_digest": true}` 开启)
- 鉴权:SpaceToken/CWT `write`
- 响应:`RpcResponse<WikiDigestReport>`

---

## 4.4 空间管理接口(`/v1/{space_id}/management`)

### GET `/v1/{space_id}/management/space_tokens`

- 作用:列出 Space Token
- 鉴权:必须通过 CWT `write`(用户管理级鉴权)
- 响应:`RpcResponse<SpaceToken[]>` —— `token` 字段仅显示前缀(如 `STabc123…`);完整 token 值只在 `add_space_token` 响应中出现一次,铸造时务必保存,或后续凭 `name` 吊销

### POST `/v1/{space_id}/management/add_space_token`

- 作用:新增 Space Token
- 鉴权:必须通过 CWT `write`(用户管理级鉴权)。铸造 `*`(全 scope)token 需要 `*` scope 的 CWT——`write` CWT 不能铸造高于自身 scope 的 token
- 请求体:`AddSpaceTokenInput` —— `name` 必填且空间内唯一。仅 `read` token 可设置 `labels`;`[]` 表示仅可读无标签 wiki 内容,省略表示不受标签限制。
- 响应:`RpcResponse<SpaceToken>`(新 token,前缀总是 `ST`;这是唯一携带完整 token 值的响应)

### POST `/v1/{space_id}/management/revoke_space_token`

- 作用:吊销 Space Token
- 鉴权:必须通过 CWT `write`(用户管理级鉴权)
- 请求体:`RevokeSpaceTokenInput` —— 传 `token`(完整 token 值)或 `name`(唯一 token 名称,供未保存 token 值的管理者使用)
- 响应:`RpcResponse<boolean>`(是否成功吊销)

### PATCH `/v1/{space_id}/management/update_space`

- 作用:更新空间信息、wiki 设置及可选的 `memory_policy`(校验后作为新策略持久化)。
- 鉴权:必须通过 CWT `write`(用户管理级鉴权)
- 请求体:`UpdateSpaceInput`
- 响应:`RpcResponse<true>`

### POST `/v1/{space_id}/management/shadow_eval`

- 作用:在空间副本上重放近期 Recall,对比候选记忆策略和当前策略;可能产生多次模型调用。
- 鉴权:CWT `write`(不接受 space token)。
- 请求体:`ShadowEvalInput`;`replay_sample` 默认采用空间策略,上限为 `16`。
- 响应:`RpcResponse<ShadowReport>`

### PATCH `/v1/{space_id}/management/restart_formation`

- 作用:通过会话 ID 重启记忆写入任务(用于失败/过期的写入任务)
- 鉴权:必须通过 CWT `write`(用户管理级鉴权)
- 请求体:`FormationRestartInput`
- 响应:`RpcResponse<true>`

### GET `/v1/{space_id}/management/space_byok`

- 作用:获取 BYOK(Bring Your Own Key)配置,即使用自定义模型配置
- 鉴权:必须通过 CWT `write`(用户管理级鉴权;响应包含模型供应商凭据)
- 响应:`RpcResponse<ModelConfig>`

### PATCH `/v1/{space_id}/management/space_byok`

- 作用:更新 BYOK(Bring Your Own Key)配置,即使用自定义模型配置
- 鉴权:必须通过 CWT `write`(用户管理级鉴权)
- 请求体:`ModelConfig`
- 响应:`RpcResponse<true>`

---

## 4.5 管理员接口(`/admin`)

### POST `/admin/create_space`

- 作用:创建空间
- 鉴权:平台管理员 + CWT `write`
- 请求体:`CreateOrUpdateSpaceInput`
- 响应:`RpcResponse<SpaceInfo>`

### POST `/admin/{space_id}/update_space_tier`

- 作用:更新空间 tier
- 鉴权:平台管理员 + CWT `write`
- 请求体:`CreateOrUpdateSpaceInput`
- 响应:`RpcResponse<SpaceTier>`

---

## 5) 前端调用示例(TS)

```ts
async function rpcPost<TReq, TRes>(
  url: string,
  body: TReq,
  token?: string
): Promise<RpcResponse<TRes>> {
  const res = await fetch(url, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Accept: 'application/json',
      ...(token ? { Authorization: `Bearer ${token}` } : {}),
    },
    body: JSON.stringify(body),
  });

  const responseText = await res.text();
  if (!res.ok) {
    let message = responseText || `HTTP ${res.status}`;
    try {
      const error = JSON.parse(responseText) as RpcError;
      if (error.message) message = error.message;
    } catch { /* 中间件错误可能是纯文本 */ }
    throw new Error(`HTTP ${res.status}: ${message}`);
  }
  return JSON.parse(responseText) as RpcResponse<TRes>;
}

// Recall
const recall = await rpcPost<RecallInput, AgentOutput>(
  '/v1/my_space_001/recall',
  { query: '这个用户的偏好是什么?', context: { counterparty: 'user_1' } },
  'YOUR_TOKEN'
);

if (recall.error) {
  console.error(recall.error.message);
} else {
  console.log(recall.result?.content);
}
```

---

## 6) 错误语义

- 认证失败:HTTP `401`,响应体为 `RpcError`
- 参数错误:HTTP `400`,响应体为 `RpcError`
- 无权访问:HTTP `403`;空间或 wiki 文档不存在:HTTP `404`
- Wiki 提交冲突:HTTP `409`,当前版本位于 `RpcError.data.current_version`;wiki 内容超限:HTTP `413`
- 模型请求限流:HTTP `429`;全局 HTTP 限流:HTTP `503`。这些中间件响应是纯文本。
- 成功时:HTTP `200`,响应体通常为 `RpcResponse<T>`
- 处理器错误即使在 `Accept` 请求 CBOR 或 Markdown 时也返回 JSON;未匹配路由和中间件错误可能是纯文本或空响应体。只有成功响应体遵循 `Accept`。
- KIP 请求可能返回 HTTP `200`,但 `KipResponse.status` 或某项操作的 `status` 为 `failed`;必须检查两层 KIP 状态。
- MCP 工具沿用同一分类:调用方可修复的失败以 JSON-RPC `invalid_params`/`invalid_request` 返回(wiki 提交冲突携带与 HTTP `409` 相同的 `data.current_version` 重试载荷),只有真正的内部错误才用 `internal_error`


### 隔离的 MIB 宿主

相邻 Anda Bot 的 `mib` feature 在本机提供独立的 `/mib-agent/v0.1` 和
`/mib-memory/v0.1` 协议;它们不属于本生产 Brain API 的路由。宿主使用
`experiments` 实现隔离状态、完成屏障、单调业务时间和清理,详见
[接入](README.md#mib-integration)。适配器不声明在线学习能力;
缺少 provider 或 observer 遥测的成本仍明确标为不完整。

Rust 工厂 `Experiment::create_with_recall_budget` 在运行对外可用前持久化强制
Recall 预算。`audit_procedures()` 返回有界、只读的原生程序清单;截断计数不能证明
不存在。仅 Bot MIB 的 `learning_audit` 扩展将该清单交给评测侧,不进入业务模型。
它不启用学习,也不赋予执行权限。详见 [验证](README.md#mib-integration)。

已退役 Rust `anda_brain::eval` API 与 `eval` CLI(含 optimizer/miner 参数)。
MIB 提供公开产品回归 profile;自测、shadow 诊断、probe、引用与账本继续作为线上
工具。运行策略使用各 Space 持久化的 `MemoryPolicy`。可信 Rust 宿主可以在共享或
打开 Space 前调用 `AppState::with_agent_prompts(AgentPrompts)` 提供不可变的部署
段:每段以 `# A.` 开头、最多 128 KiB,编译参考前缀保持原样。这不是 HTTP/MCP
提示操作。详见 [迁移](README.md#offline-regression-and-instance-configuration)。


### 可信学习运行时(仅 Rust)

启用 `learning` feature 后,`Space::learning()` 提供显式注册、冻结 cohort、
有界 `drive` 步骤、重启后发现工作及独立认证的 Outcome 接收。原生 lease、当前
可执行权限、依赖有效性和 policy pin 共同约束派发。这些宿主 API 不增加 HTTP/MCP
路由或模型写权限;收齐 cohort 不会采纳 Skill。`settle(job_id)` 在固定 cutoff 后
重算原生账本,原子提交裁决与 standing。`reviews()` 和 `enroll_review()` 提供保留
原始采纳依据的持久复核;`submit_safety_signal()` 接受独立认证的安全撤销信号。
`bind_application_context()` 接受短时有效的可信宿主环境观测,`procedure_status()`
及 Recall 内部的 `check_procedure_status` 工具只读检查当前推荐条件,不授予执行权限。
条件无法验证或复核到期时停止推荐。已配置 learning 的 Space 不允许通过 fork/snapshot
复制操作 journal。详见 [运行时](README.md#native-learning-contracts) 和
[生命周期与恢复](README.md#native-learning-contracts)。


## 有身份的运行时待办与后果

启动前配置 `BRAIN_RUNTIME_CONFIG`。完整合同、恢复及示例见 [RUNTIME_cn.md](RUNTIME_cn.md)
和 [runtime.example.json](runtime.example.json)。公共/本地 Space 也必须提供真实凭据。

| 接口 | 授权 | 返回 |
| --- | --- | --- |
| `GET /v1/{space_id}/attention?limit=20&cursor=...` | 真实 read/* 凭据、原生主体映射和 audience | `AttentionPage`,读取不领取 |
| `POST /v1/{space_id}/attention/{id}/responses` | 真实 write/*、当前可见性及正确接收者 | `ResponseReceipt`,body 为 `AttentionResponse` |
| `POST /v1/{space_id}/outcomes` | 验签的观察者 CWT、当前 record_outcome 及登记合同 | `ObservationReceipt`,body 为 `OutcomeInput` |
| `GET /v1/{space_id}/runtime/status` | 真实 read/*,配置启用时需映射 | `RuntimeStatus`,计数仅覆盖可见的有限页面 |

URL 中的 id 是返回的 wake 摘要,不是带斜杠的 wake_ref。五分钟有效的游标经加密认证,
绑定调用者/instance/配置;跨调用者或过期游标被拒绝。公共 Space 和普通 write token
不能认证独立观察者。MCP 暴露 get_attention、respond_attention、get_runtime_status
(均带 anda_brain_ 前缀),观察者写入不属于模型工具。

POST 使用结构化 JSON/CBOR,响应保留 JSON/CBOR/Markdown 协商。同事件同文幂等,
异文 409 并留存审计;未来时间或错误 instance 被拒绝。迟到/更正/安全状态、原生提交
和 learning 入样分别报告。learning 变体必须符合原有 OutcomeMeasurements 合同,
包括 baseline 在内均只路由到既有控制器。

```ts
type RuntimeScope = { space_id: string; space_instance: string };
type AttentionQuery = { cursor?: string | null; limit?: number | null };
type AttentionResponse =
  | { kind: "clarification"; event_key: string; answer: string }
  | { kind: "agent_statement"; event_key: string; statement: string };
type ResponseReceipt = {
  receipt_id: string; status: string; evidence_ref: string | null;
};
type AttentionPage = {
  scope: RuntimeScope; items: AttentionItem[];
  next_cursor: string | null; complete: boolean;
};
type AttentionItem = {
  id: string; wake_ref: string; parent_id: string | null;
  watch_ref: string; fire_activity_ref: string; summary: string;
  state: "pending" | "running" | "blocked" | "completed" | "cancelled";
  reason: string | null; decision: Record<string, unknown> | null;
  decision_ref: string | null; attempt_ref: string | null;
  dispatch_ref: string | null; clarification: Record<string, unknown> | null;
  delivery: Record<string, unknown> | null;
};
type OutcomeStatus = "success" | "partial" | "failure" | "aborted" | "unknown";
type OutcomeInput = {
  space_instance: string; attempt_ref: string;
  observer_configuration_digest: string; event_key: string;
  observed_at: string; metric: string; window: string;
  observation:
    | { kind: "measurement"; terminal: boolean; outcome_status: OutcomeStatus;
        magnitude?: number | null; payload: unknown }
    | { kind: "learning"; measurements: Record<string, unknown> };
  correction_of?: string | null; safety_signal?: string | null;
  utility?: { witness_ref?: string; witness?: ContributionWitness } | null;
};
type ObservationReceipt = {
  format: "anda-brain:observation-receipt-v1";
  receipt_id: string; scope: RuntimeScope; event_key: string;
  body_digest: string; observer: string; received_at_ms: number;
  observed_at: string; status: string;
  native_committed: boolean; learning_eligible: boolean;
  outcome_status: OutcomeStatus | null; outcome_ref: string | null;
  observation_ref: string | null; reason: string | null; safety_pending: boolean;
  safety_evaluation_ref?: string; // 解决或覆盖本安全信号的原生撤销记录。
};
type RuntimeStatus = {
  supported: boolean; configured: boolean; scope: RuntimeScope | null;
  attention_enabled: boolean; actions_enabled: boolean;
  observation_enabled: boolean; observer_authenticated: boolean;
  blocked_reasons: string[]; visible_items: number; inventory_complete: boolean;
  utility?: UtilityStatus;
  learning?: LearningRuntimeStatus;
  semantic_attention?: SemanticAttentionStatus;
  trust?: TrustRuntimeStatus;
};
```

### 后果与回答语义

待办页包含 1–50 项、最多 256 KiB 可见输出。`complete` 仅表示本次快照遍历结束,
不表示任务完成或语义完整;每页重验可见性,包括 gate 记忆包背后的原生证据。
MCP 回答参数为 `{id, response}`,列表参数为 `{cursor, limit}`。读取和回答均不领取
任务;澄清回答须对应已提交 ask、正确接收者和有效期限,回答进入新 gate,不授予权限。
`agent_statement` 只生成带归属 Evidence 和 Activity,不生成独立 OutcomeRecord。例如:

```json
{"kind":"clarification","event_key":"answer-42","answer":"明天"}
```

测量请求使用实际保留的身份与摘要:

```json
{
  "space_instance":"sha256:INSTANCE_DIGEST",
  "attempt_ref":"X-42",
  "observer_configuration_digest":"sha256:REGISTERED_METHOD_DIGEST",
  "event_key":"instrument-event-42",
  "observed_at":"2026-09-17T10:00:00.000Z",
  "metric":"delivery",
  "window":"durable_inbox_v1",
  "observation":{
    "kind":"measurement",
    "terminal":true,
    "outcome_status":"success",
    "magnitude":null,
    "payload":{"delivery_digest":"sha256:ACTUAL_DELIVERY_REQUEST_DIGEST"}
  },
  "correction_of":null,
  "safety_signal":null
}
```

观察合同固定主体、方法/配置摘要、控制域、任务族、指标、窗口及允许延迟。接收层验证
真实 act/Attempt、原生事务作者、已存在分派和观测时间,拒绝控制器自评。inbox 成功还
须验证实际持久化投递及匹配的摘要/时间,仅证明 inbox 写入,不代表人已阅读或业务成功。
其他回调须提供自己的独立测量合同。

普通合格测量原子生成 Outcome Evidence 与 `outcome_observation` Activity;原始材料
保留在 Evidence payload,不扩展封闭的 OutcomeRecord Facet。非终结/unknown 不完成
分派,缺失 magnitude/cost 不填零。终结证据对账同一 Attempt,取消后也可保留真实后果。
原生留证与分派对账是两个可恢复步骤;未确认写入须用相同事件/内容和新鲜认证重试。
调用方取消不截断已接收写入。

认证后的迟到、冲突及学习非终结材料可审计,不改变旧试验入样资格。更正指向同一
观察者/Attempt 的较早事件,追加证据,不改写旧 Outcome/Evaluation。迟到或排除的
安全信号仍可发现;显式启用的学习消费者使用当前观察者权限,在原生撤销完成后才确认
`safety_pending` 并记录 `safety_evaluation_ref`。

已登记学习 Attempt 使用 `observation:{"kind":"learning", "measurements":{...}}`。
归属来自保留的 ticket,`trial_ref:null` 的 baseline 也不会落入普通写入器;只有
`LearningRuntime::submit_outcome` 写原生结果,保持冻结 cutoff、可比性和 ACK 恢复。
控制器不可用时拒绝,不转普通路径。`learning_eligible:true` 只表示合同接纳,不等于
正向裁决。输入上限 16 KiB,事件键 256 字节;身份装配和存储上限见[运行时指南](RUNTIME_cn.md)。

### 学习运行状态

既有 status 路由和 MCP 工具新增 learning;模型工具不提供 cohort 报名或观察者
凭据管理。只有明确映射的 auditor 能看到 capacity / last_pass,其他调用方为 null。
Maintenance 的可选 skills.runtime 显示独立调度状态,旧 Skill 计数不会重复计入
此前调度工作。详见[学习指南](LEARNING_RUNTIME_cn.md)。

```typescript
type LearningRuntimeStatus = {
  compiled: boolean; registered: boolean; registration_enabled?: boolean;
  bindings_ready: boolean; automatic_allowed: boolean; running?: boolean;
  automation?: { trials: boolean; reviews: boolean; archive: boolean; safety: boolean };
  blocked_reasons?: string[];
  capacity?: { hot_jobs: number; maximum_hot_jobs: number; archived_jobs: number;
    retained_identities: number; reserved_bytes: number;
    storage: { maximum_records: number; maximum_reserved_bytes: number } } | null;
  last_pass?: { started_at_ms: number; finished_at_ms: number; enrolled: number;
    driven: number; observed: number; settled: number; archived: number;
    reviews_checked: number; reviews_enrolled: number; safety_resolved: number;
    blocked: string[] } | null;
};
```

### 交付与效用元数据

结构化 Recall 新增可选 recall_receipt 元数据,answer/语义 packet 保持不变。普通或
直接 agent 调用可通过 conversation ID 在可信 Rust API 查询收据。观察者在 outcomes
的 utility 中可选择内联见证或既有原生见证引用,不放宽验签与独立权限检查。
运行状态新增 utility 的开关、校准状态及恢复原因;模型没有设置分数或新增 MCP
变更工具。详见 [UTILITY_RUNTIME_cn.md](UTILITY_RUNTIME_cn.md)。

```typescript
type RecallReceiptRef = {
  id: string; digest: string; scope: RuntimeScope;
};
// RecallOutput.recall_receipt?: RecallReceiptRef
// OutcomeInput.utility?: { witness_ref?: string; witness?: ContributionWitness }
// RuntimeStatus.utility?: UtilityStatus
type UtilityStatus = {
  configured: boolean; automatic: boolean; apply: boolean;
  calibrated: boolean; ranking: boolean; running: boolean;
  reason: string | null;
};
```

### 文本注意力状态

Runtime status 新增可选 `semantic_attention`:`configured`、`automatic`、`running`、
`pin`、`reason` 及可空的 `last_pass`。后者包含单轮有界统计 `scanned`、`calls`、
`input_tokens`、`advanced`、`fired`、`expired`、`deferred`、`reason`,仅配置为 auditor
的调用者可读取,其他调用者得到 null。它不是完整清单,也不证明所有文本 Watch
均已求值。既有 JSON/CBOR/Markdown 和 HTTP/MCP 请求形状保持兼容;不新增模型配置
或求值写接口。操作员通过每 Space 的 `semantic` 启动绑定安装。预算、pin 迁移、
unknown/deferred、原生 Artifact 擦除及幂等恢复见
[SEMANTIC_WATCH_RUNTIME_cn.md](SEMANTIC_WATCH_RUNTIME_cn.md)。

```typescript
type SemanticAttentionStatus = {
  configured: boolean; automatic: boolean; running: boolean;
  pin: { id: string; digest: string } | null; reason: string | null;
  last_pass: {
    scanned: number; calls: number; input_tokens: number; advanced: number;
    fired: number; expired: number; deferred: number; reason: string | null;
  } | null;
};
```

### 上下文 trust 状态与发现提示

既有 HTTP 状态路由和 MCP 状态工具新增可选 `trust` 元数据。`governor_authorized`
表示配置的治理主体当前是否具有原生权限,不是授予调用者的权限。不新增 HTTP/MCP
trust 管理或独立事实写工具,既有 JSON/CBOR/Markdown 请求保持兼容。正常认证的
独立 measurement payload 可选携带 `trust_verification_ref: "E-…"`,用于公告既有原生
事实核验记录并有界发现,不能把行动成功/失败转成信任得分。可信 Rust 事实接收、
审查、应用、版本冲突恢复和限定域回退见 [TRUST_RUNTIME_cn.md](TRUST_RUNTIME_cn.md)。

```typescript
type TrustRuntimeStatus = {
  configured: boolean; automatic: boolean; apply: boolean; automatic_apply: boolean;
  calibrated: boolean; governor_authorized: boolean; running: boolean;
  reason: string | null;
};
```