@zq-silk/yui 2.6.0 → 2.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/README.md +23 -0
  2. package/dist/cli/commandCatalog.js +34 -7
  3. package/dist/cli/updateCommand.js +3 -0
  4. package/dist/commands/configCommands.js +1 -0
  5. package/dist/commands/globalRoleCommands.js +62 -35
  6. package/dist/commands/inboxCommands.js +372 -0
  7. package/dist/commands/roleSkillValidation.js +2 -0
  8. package/dist/commands/taskCommands.js +39 -7
  9. package/dist/commands/taskRoleRuntimeStatus.js +2 -0
  10. package/dist/context/currentSkills.js +48 -0
  11. package/dist/context/roleSessionContext.js +13 -16
  12. package/dist/context/runContextPack.js +50 -3
  13. package/dist/context/runInputContract.js +1 -1
  14. package/dist/context/sessionBootstrapManifest.js +27 -4
  15. package/dist/context/skillCatalog.js +2 -3
  16. package/dist/context/taskContext.js +38 -12
  17. package/dist/controlPlaneCli.js +58 -7
  18. package/dist/controller/controller.js +8 -2
  19. package/dist/controller/fileSchedulerStoreAdapter.js +26 -6
  20. package/dist/controller/globalInputDelivery.js +86 -16
  21. package/dist/controller/globalRuntimeAttention.js +136 -6
  22. package/dist/controller/operatorNotification.js +6 -1
  23. package/dist/controller/providerRetryDelivery.js +3 -5
  24. package/dist/controller/runtime.js +6 -2
  25. package/dist/controller/structuredProviderObservation.js +51 -15
  26. package/dist/controller/taskHostTerminalRecovery.js +33 -0
  27. package/dist/doctor/doctor.js +25 -2
  28. package/dist/executor/effectiveLaunch.js +2 -2
  29. package/dist/executor/fileRoleLaunchPlanner.js +8 -15
  30. package/dist/interaction/notificationPresentation.js +2 -2
  31. package/dist/interaction/operatorPresentation.js +1 -1
  32. package/dist/message/globalInputBacklog.js +69 -0
  33. package/dist/message/globalMessageQuery.js +1 -0
  34. package/dist/message/inboxReceipt.js +62 -0
  35. package/dist/message/message.js +6 -1
  36. package/dist/message/messageContinuation.js +34 -13
  37. package/dist/message/taskInboxOwnership.js +43 -0
  38. package/dist/models/modelManagement.js +469 -0
  39. package/dist/models/modelManagementConfig.js +46 -0
  40. package/dist/models/modelManagementFiles.js +90 -0
  41. package/dist/models/modelManagementHttp.js +90 -0
  42. package/dist/models/modelManagementTypes.js +1 -0
  43. package/dist/nativeAgent/session/backends.js +1 -1
  44. package/dist/observability/runtimeIdentity.js +1 -1
  45. package/dist/output/boundedRead.js +43 -14
  46. package/dist/resources/sqliteResourceRegistry.js +1 -1
  47. package/dist/runtime/agentEndpointIdentity.js +8 -4
  48. package/dist/runtime/agentEndpointOwnership.js +5 -6
  49. package/dist/runtime/agentHost.js +165 -24
  50. package/dist/runtime/agentHostImplementation.js +18 -0
  51. package/dist/runtime/managedCaller.js +25 -1
  52. package/dist/runtime/managedIdentity.js +1 -1
  53. package/dist/runtime/providerRetry.js +19 -1
  54. package/dist/runtime/sessionCaller.js +53 -0
  55. package/dist/scheduler/operatorEvent.js +49 -0
  56. package/dist/scheduler/operatorInputNotificationProcessor.js +5 -4
  57. package/dist/scheduler/taskWake.js +5 -0
  58. package/dist/sqlite/driver.js +108 -0
  59. package/dist/storage/contextRecords.js +28 -0
  60. package/dist/storage/sqliteSchema.js +21 -1
  61. package/dist/storage/sqliteStore.js +64 -1
  62. package/dist/storage/storageSchema.js +1 -1
  63. package/dist/storage/storageVersions.js +1 -1
  64. package/dist/storage/storeRpc.js +1 -0
  65. package/dist/storage/taskStore.js +4 -0
  66. package/dist/storage/upgrade/upgradeOrchestrator.js +1 -1
  67. package/dist/task/completionReadiness.js +13 -6
  68. package/dist/telemetry/sqliteTelemetryStore.js +1 -1
  69. package/dist/web/assets/assetManifest.js +28 -2
  70. package/dist/web/assets/client/app/manage.js +6 -0
  71. package/dist/web/assets/client/app/models.js +20 -0
  72. package/dist/web/assets/client/app/settings.js +41 -9
  73. package/dist/web/assets/client/i18n/en.js +180 -2
  74. package/dist/web/assets/client/i18n/zh-CN.js +178 -2
  75. package/dist/web/assets/client/index.js +8 -0
  76. package/dist/web/assets/client/layout/manageShell.js +94 -0
  77. package/dist/web/assets/client/lib/api.js +13 -1
  78. package/dist/web/assets/client/lib/i18n.js +5 -3
  79. package/dist/web/assets/client/views/dock/conversation.js +231 -80
  80. package/dist/web/assets/client/views/models.js +777 -0
  81. package/dist/web/assets/client/views/skills.js +22 -15
  82. package/dist/web/assets/shared/icons.js +2 -0
  83. package/dist/web/assets/shared/manageNav.js +13 -0
  84. package/dist/web/assets/shell/manage.js +54 -0
  85. package/dist/web/assets/shell/models.js +7 -0
  86. package/dist/web/assets/shell/settings.js +1 -35
  87. package/dist/web/assets/shell/settingsContent.js +30 -0
  88. package/dist/web/assets/shell/sidebar.js +1 -0
  89. package/dist/web/assets/styles/index.js +6 -0
  90. package/dist/web/assets/styles/views/conversation.js +133 -0
  91. package/dist/web/assets/styles/views/manage.js +71 -0
  92. package/dist/web/assets/styles/views/models.js +129 -0
  93. package/dist/web/assets/styles/views/settings.js +28 -14
  94. package/dist/web/assets/styles/views/sidebar.js +1 -0
  95. package/dist/web/webServer.js +59 -9
  96. package/docs/cli-information-contract.md +42 -11
  97. package/docs/cli-information-contract.zh-CN.md +28 -7
  98. package/docs/managed-turn-and-session-runtime.md +127 -5
  99. package/docs/managed-turn-and-session-runtime.zh-CN.md +83 -3
  100. package/docs/release-workflow.md +105 -9
  101. package/docs/release-workflow.zh-CN.md +73 -5
  102. package/docs/storage-baseline.md +22 -7
  103. package/docs/storage-baseline.zh-CN.md +14 -5
  104. package/docs/task-delivery.md +17 -8
  105. package/docs/task-delivery.zh-CN.md +11 -5
  106. package/docs/testing/review-evaluation.md +148 -0
  107. package/docs/testing/review-evaluation.zh-CN.md +117 -0
  108. package/docs/testing/verification-levels.md +26 -4
  109. package/docs/testing/verification-levels.zh-CN.md +11 -1
  110. package/i18n/README.zh-CN.md +19 -0
  111. package/package.json +5 -2
  112. package/skills/yui-leader/SKILL.md +28 -11
  113. package/skills/yui-leader/VERSION +1 -0
  114. package/skills/yui-leader/references/execution.md +29 -0
  115. package/skills/yui-leader/references/replicated-execution.md +7 -0
  116. package/skills/yui-operator/SKILL.md +15 -3
  117. package/skills/yui-operator/VERSION +1 -0
  118. package/skills/yui-operator/references/task-delivery.md +2 -0
  119. package/skills/yui-reviewer/SKILL.md +43 -1
  120. package/skills/yui-reviewer/VERSION +1 -0
  121. package/skills/yui-runtime/SKILL.md +144 -15
  122. package/skills/yui-runtime/VERSION +1 -0
  123. package/skills/yui-runtime/references/publication.md +16 -5
  124. package/skills/yui-runtime/references/recovery.md +24 -5
  125. package/skills/yui-worker/SKILL.md +8 -1
  126. package/skills/yui-worker/VERSION +1 -0
@@ -0,0 +1,129 @@
1
+ import { BREAKPOINTS } from "../../shared/geometry.js";
2
+ /*
3
+ * MODELS VIEW — the content of the /models sections. The rail, reading column
4
+ * and section headings come from views/manage; cards, badges, chips,
5
+ * segmented controls and fields from the shared ui stylesheets. These rules
6
+ * add the provider table, the catalog list and the quota meters. On phones
7
+ * the provider table becomes stacked rows.
8
+ */
9
+ export const MODELS_STYLES = `
10
+ /* Heading first, as on every management page: the page scope and the shared
11
+ connection status sit under the current section's heading. The wrappers
12
+ flatten into one column so only order changes, never the DOM. */
13
+ .models-body .manage-main{display:flex;flex-direction:column;gap:14px}
14
+ .models-body .models-root,.models-body .models-section:not([hidden]){display:contents}
15
+ .models-body .manage-main>*,.models-root>*,.models-section>*{width:100%;max-width:1120px;margin-left:auto;margin-right:auto}
16
+ .models-section>.manage-head{order:-1}
17
+ .models-body .manage-scope{margin-bottom:0}
18
+ .models-root .seg-btn[aria-pressed="true"]{background:var(--surface-2);color:var(--ink);box-shadow:var(--shadow-1),0 0 0 1px var(--line-2)}
19
+ .models-root{display:grid;gap:16px;min-width:0}
20
+ .models-section p:not(.kicker){color:var(--ink-2);font-size:var(--fs-sm);line-height:1.55;overflow-wrap:anywhere}
21
+ .models-section .manage-heading p:not(.kicker){color:var(--ink-3)}
22
+ .models-card{overflow:hidden}
23
+ .models-card>.card-body{gap:12px}
24
+ .models-status{display:grid;gap:8px;min-width:0}
25
+ .models-status:empty{display:none}
26
+ .models-facts{display:flex;flex-wrap:wrap;gap:6px 8px;align-items:center;min-width:0}
27
+ .models-facts small{overflow-wrap:anywhere}
28
+ .models-facts .badge[hidden]{display:none}
29
+ .models-notice{flex:1 1 280px;min-width:0}
30
+ .models-alert{display:flex;flex-wrap:wrap;align-items:center;gap:8px 12px;padding:10px 14px;border:1px solid var(--bad-soft);border-radius:var(--r-md);background:var(--bad-soft)}
31
+ .models-alert>.icon{width:16px;height:16px;color:var(--bad);flex:none}
32
+ .models-alert p{flex:1 1 240px;min-width:0}
33
+ .models-note{display:flex;flex-wrap:wrap;align-items:center;gap:6px;padding:9px 12px;border:1px solid var(--line);border-radius:var(--r-md);background:var(--surface-2)}
34
+ .models-note>.icon{width:15px;height:15px;color:var(--info);flex:none}
35
+ .models-empty{color:var(--ink-3)!important;font-size:var(--fs-sm)}
36
+ .models-count{color:var(--ink-4);font-size:var(--fs-xs)!important;font-variant-numeric:tabular-nums}
37
+ .models-receipt{white-space:pre-wrap;overflow-wrap:anywhere}
38
+ .models-receipt-group .settings-actions{margin-top:8px}
39
+
40
+ /* Toolbars: search plus segmented filters */
41
+ .models-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:8px 10px;padding:12px 16px;border-bottom:1px solid var(--line);min-width:0}
42
+ .models-toolbar-flat{padding:0;border:0}
43
+ .models-toolbar .seg{flex-wrap:wrap}
44
+ .models-search{position:relative;display:flex;align-items:center;flex:1 1 240px;min-width:0;max-width:420px}
45
+ .models-search>.icon{position:absolute;left:10px;width:15px;height:15px;color:var(--ink-4);pointer-events:none}
46
+ .models-search input{width:100%;height:32px;padding:0 10px 0 32px;border-radius:var(--r-md);background:var(--surface-2)}
47
+ .models-results{display:grid;gap:0;min-width:0}
48
+ .models-results>.models-count{padding:8px 16px 0}
49
+ .models-results>.models-empty{padding:12px 16px 16px}
50
+ .models-catalog-results>.models-count{padding:0 0 8px}
51
+ .models-catalog-results>.models-empty{padding:0}
52
+
53
+ /* Provider table */
54
+ .models-table-wrap{min-width:0;overflow-x:auto}
55
+ .models-table{width:100%;border-collapse:collapse;font-size:var(--fs-sm)}
56
+ .models-table th{padding:10px 12px;color:var(--ink-4);font-size:var(--fs-2xs);font-weight:600;letter-spacing:.04em;text-align:left;text-transform:uppercase;border-bottom:1px solid var(--line);white-space:nowrap}
57
+ .models-table td{padding:11px 12px;border-bottom:1px solid var(--line);vertical-align:top;min-width:0}
58
+ .models-table tr:last-child td{border-bottom:0}
59
+ .models-table th:first-child,.models-table td:first-child{padding-left:16px}
60
+ .models-table th:last-child,.models-table td:last-child{padding-right:16px}
61
+ .models-table tbody tr:hover{background:var(--surface-2)}
62
+ .models-table tbody tr[aria-current="true"]{background:var(--accent-soft);box-shadow:inset 3px 0 0 var(--accent)}
63
+ .models-cell-main{display:grid;gap:3px;justify-items:start;min-width:0}
64
+ .models-cell-main strong{font-weight:600;color:var(--ink);overflow-wrap:anywhere}
65
+ .models-cell-main code{white-space:normal;overflow-wrap:anywhere}
66
+ .models-url{display:block;max-width:280px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ink-2)}
67
+ .models-row-actions{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:6px;min-width:0}
68
+ .models-row-actions .btn{height:28px;padding:0 10px;font-size:var(--fs-xs)}
69
+ .models-reason{flex-basis:100%;max-width:260px;text-align:right;line-height:1.4;overflow-wrap:anywhere}
70
+ .models-danger{color:var(--bad)}
71
+ .models-danger:hover:not(:disabled){color:var(--bad);background:var(--bad-soft)}
72
+
73
+ /* Provider editor */
74
+ .models-editor{border-color:var(--accent-line)}
75
+ .models-form-head{display:flex;flex-wrap:wrap;align-items:center;gap:8px 10px;min-width:0}
76
+ .models-form-head h2{font-size:var(--fs-md);font-weight:600;overflow-wrap:anywhere;min-width:0}
77
+ .models-provider-form .settings-grid{gap:14px 20px;align-items:start}
78
+ .models-provider-form input:not([type=checkbox]),.models-provider-form select,.models-connection-form input{width:100%;min-width:0}
79
+ .models-provider-form .settings-actions{margin-top:4px}
80
+
81
+ /* Connection settings */
82
+ .models-connection-form{display:grid;gap:16px;min-width:0}
83
+ .models-connection-form{grid-template-columns:repeat(2,minmax(0,1fr))}
84
+ .models-connection-form>.settings-actions,.models-connection-form>.receipt,.models-connection-form>.models-receipt-group{grid-column:1/-1;margin-top:0}
85
+ .models-fieldset{display:grid;align-content:start;gap:14px;min-width:0;margin:0;padding:0;border:0}
86
+ .models-fieldset legend{margin-bottom:12px;padding:0;color:var(--ink);font-size:var(--fs-sm);font-weight:600}
87
+ .models-explain h2{font-size:var(--fs-sm);font-weight:600}
88
+
89
+ /* Catalog */
90
+ .models-catalog{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:0 20px;min-width:0}
91
+ .models-catalog-item{display:flex;align-items:center;justify-content:space-between;gap:10px;min-width:0;padding:7px 2px;border-bottom:1px solid var(--line)}
92
+ .models-catalog-item code{font-family:var(--font-mono);font-size:var(--fs-xs);color:var(--ink);overflow-wrap:anywhere;min-width:0}
93
+
94
+ /* Quota accounts, groups and meters */
95
+ .models-accounts{list-style:none;margin:0 auto;padding:0;display:grid;gap:14px;min-width:0}
96
+ .models-account .card-title>span:first-child{font-family:var(--font-mono);font-size:var(--fs-sm)}
97
+ .models-groups{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:18px 28px;min-width:0}
98
+ .models-group{display:grid;align-content:start;gap:10px;min-width:0}
99
+ .models-group h3{font-size:var(--fs-sm);font-weight:600;color:var(--ink)}
100
+ .models-windows{list-style:none;margin:0;padding:0;display:grid;gap:12px;min-width:0}
101
+ .models-window{display:grid;gap:5px;min-width:0}
102
+ .models-window-line{display:flex;justify-content:space-between;gap:12px;font-size:var(--fs-sm);min-width:0}
103
+ .models-window-name{color:var(--ink-2);overflow-wrap:anywhere;min-width:0}
104
+ .models-window-value{color:var(--ink);font-weight:500;font-variant-numeric:tabular-nums;white-space:nowrap}
105
+ .models-meter{position:relative;height:6px;border-radius:var(--r-pill);background:var(--surface-3);overflow:hidden}
106
+ .models-meter>span{position:absolute;inset:0 auto 0 0;border-radius:inherit;background:var(--tone)}
107
+ .models-meter.is-unknown{background:repeating-linear-gradient(90deg,var(--surface-3) 0 6px,transparent 6px 10px)}
108
+ .models-window small{font-size:var(--fs-xs);overflow-wrap:anywhere}
109
+ .models-balances{display:flex;flex-wrap:wrap;gap:8px 28px;margin:0;padding-top:12px;border-top:1px solid var(--line);font-size:var(--fs-sm)}
110
+ .models-balances div{display:grid;gap:2px;min-width:0}
111
+ .models-balances dt{color:var(--ink-3);font-size:var(--fs-xs)}
112
+ .models-balances dd{margin:0;color:var(--ink);font-weight:500;font-variant-numeric:tabular-nums}
113
+
114
+ @media(max-width:${BREAKPOINTS.small}px){
115
+ .models-connection-form{grid-template-columns:minmax(0,1fr)}
116
+ .models-provider-form .settings-grid{grid-template-columns:minmax(0,1fr)}
117
+ .models-search{max-width:none;flex-basis:100%}
118
+ .models-table thead{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
119
+ .models-table,.models-table tbody,.models-table tr,.models-table td{display:block;width:100%}
120
+ .models-table tr{padding:10px 14px;border-bottom:1px solid var(--line)}
121
+ .models-table tr:last-child{border-bottom:0}
122
+ .models-table td{display:grid;grid-template-columns:84px minmax(0,1fr);gap:8px;align-items:start;padding:4px 0!important;border:0}
123
+ .models-table td::before{content:attr(data-label);color:var(--ink-4);font-size:var(--fs-2xs);font-weight:600;letter-spacing:.04em;text-transform:uppercase;padding-top:3px}
124
+ .models-url{max-width:none;white-space:normal;overflow-wrap:anywhere}
125
+ .models-row-actions{justify-content:flex-start}
126
+ .models-reason{text-align:left;max-width:none}
127
+ .models-catalog{grid-template-columns:minmax(0,1fr)}
128
+ }
129
+ `;
@@ -1,26 +1,40 @@
1
+ import { BREAKPOINTS } from "../../shared/geometry.js";
2
+ /*
3
+ * SETTINGS VIEW — the content of the /settings sections (preferences, Skills,
4
+ * Agents & server). The rail, reading column and section headings come from
5
+ * views/manage. Settings panels share the card surface of the model pages:
6
+ * the same border, radius, padding and title scale; nested panels (a Skill in
7
+ * the catalog) sit one surface step lower instead of nesting full cards.
8
+ */
1
9
  export const SETTINGS_STYLES = `
2
- .settings-body{display:block;overflow:auto;height:auto;min-height:100dvh}
3
- .settings-page{max-width:1040px;margin:auto;padding:32px 24px 80px;display:grid;gap:22px}
4
- .settings-page p{color:var(--ink-2);font-size:var(--fs-sm);line-height:1.6;overflow-wrap:anywhere}
5
- .settings-header{display:flex;gap:20px;align-items:center}
6
- .settings-card{padding:22px;border:1px solid var(--line-2);border-radius:var(--r-lg);background:var(--surface);min-width:0}
7
- .settings-card>summary{font-size:var(--fs-md);font-weight:600;cursor:pointer}
8
- .settings-card h2{font-size:var(--fs-md);margin-bottom:16px}
9
- .settings-card[open]>summary{margin-bottom:16px}
10
+ .settings-card{display:block;padding:16px;border:1px solid var(--line);border-radius:var(--r-lg);background:var(--surface);min-width:0}
11
+ .settings-card .settings-card{padding:14px;background:var(--surface-2)}
12
+ .settings-card>summary{display:flex;align-items:center;gap:8px;min-height:24px;font-size:var(--fs-md);font-weight:600;color:var(--ink);cursor:pointer;overflow-wrap:anywhere}
13
+ .settings-card h2{font-size:var(--fs-md);font-weight:600;color:var(--ink);margin-bottom:14px}
14
+ .settings-card h3{font-size:var(--fs-sm);font-weight:600;color:var(--ink);overflow-wrap:anywhere}
15
+ .settings-card[open]>summary{margin-bottom:14px;padding-bottom:12px;border-bottom:1px solid var(--line)}
16
+ .manage-section[data-section] .settings-card p,.settings-stack>p{color:var(--ink-2);font-size:var(--fs-sm);line-height:1.6;overflow-wrap:anywhere}
10
17
  .settings-stack{display:grid;gap:16px;min-width:0}
11
- .settings-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:24px}
18
+ .settings-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:20px 24px;min-width:0}
12
19
  .settings-field{padding:14px 0;border-bottom:1px solid var(--line);display:grid;gap:8px;min-width:0}
13
20
  .settings-field small{color:var(--ink-3);overflow-wrap:anywhere}
14
21
  .settings-field small:empty,.settings-field .settings-actions:empty{display:none}
15
22
  .settings-field textarea{width:100%;min-height:88px;resize:vertical}
16
23
  .settings-field input,.settings-field select{width:100%;min-width:0}
17
24
  .settings-field .settings-reset{display:flex;gap:8px;align-items:center;font-size:var(--fs-xs)}
18
- .settings-reset input{width:auto}
19
- .settings-actions{display:flex;gap:10px;flex-wrap:wrap;margin-top:16px;align-items:center}
25
+ .settings-reset{display:flex;gap:8px;align-items:center;font-size:var(--fs-sm);color:var(--ink-2)}
26
+ .settings-reset input{width:auto;flex:none}
27
+ .settings-actions{display:flex;gap:10px;flex-wrap:wrap;margin-top:16px;align-items:center;min-width:0}
28
+ .settings-actions code{overflow-wrap:anywhere;min-width:0}
20
29
  .settings-receipt{white-space:pre-wrap;overflow-wrap:anywhere}
21
30
  .settings-error{color:var(--bad)!important}
22
31
  .settings-observation{max-height:260px;overflow:auto;white-space:pre-wrap;overflow-wrap:anywhere;font-size:var(--fs-xs)}
23
- .settings-search{position:sticky;top:0;background:var(--canvas);padding:12px 0;z-index:1}
24
- .settings-page input[type=checkbox]{width:16px;height:16px;padding:0;accent-color:var(--accent)}
25
- @media(max-width:640px){.settings-page{padding:18px 12px 48px}.settings-grid{grid-template-columns:1fr}.settings-card{padding:16px}}
32
+ .settings-search{position:sticky;top:0;z-index:1;padding:10px 0;background:var(--canvas)}
33
+ .settings-search input{width:100%;max-width:520px}
34
+ #settings-status:empty,#browser-receipt:empty{display:none}
35
+ .mono-line{overflow-wrap:anywhere}
36
+ @media(max-width:${BREAKPOINTS.small}px){
37
+ .settings-grid{grid-template-columns:minmax(0,1fr)}
38
+ .settings-card{padding:14px}
39
+ }
26
40
  `;
@@ -71,4 +71,5 @@ export const SIDEBAR_STYLES = `
71
71
  .foot-btn[aria-pressed="true"]{color:var(--accent);border-color:var(--accent-line);background:var(--accent-soft)}
72
72
  .foot-btn kbd{margin-left:2px}
73
73
  .side-foot .icon-btn{margin-left:auto}
74
+ .side-foot .icon-btn+.icon-btn{margin-left:0}
74
75
  `;
@@ -7,9 +7,9 @@ import { parseTaskSearchOptions, searchTaskBodies } from "../context/taskSearch.
7
7
  import { readTaskUsage } from "../runtime/taskUsageQuery.js";
8
8
  import { readWebTaskActivity } from "./webTaskActivity.js";
9
9
  import { WebRequestRejected } from "./webMutation.js";
10
- import { SETTINGS_HTML } from "./assets/shell/settings.js";
10
+ import { MODELS_HTML } from "./assets/shell/models.js";
11
11
  import { TASK_SUBMISSION_INTENTS } from "../message/message.js";
12
- import { DASHBOARD_HTML, findWebAsset } from "./assets/assetManifest.js";
12
+ import { DASHBOARD_HTML, findWebAsset, prepareWebDocument, WEB_ASSET_VERSION } from "./assets/assetManifest.js";
13
13
  import { buildWebTaskCatalog, buildWebPageSessions, buildWebTaskDetail } from "./webSnapshot.js";
14
14
  const MAX_JSON_BODY_BYTES = 16 * 1024;
15
15
  const MAX_TERMINAL_MESSAGE_BYTES = 64 * 1024;
@@ -204,6 +204,54 @@ async function handleHttpRequest(request, response, store, dependencies, token,
204
204
  }
205
205
  return;
206
206
  }
207
+ if (pathname === "/api/models" || pathname.startsWith("/api/models/")) {
208
+ try {
209
+ const service = dependencies.models;
210
+ if (!service)
211
+ throw new WebRequestRejected("Model management unavailable.");
212
+ const query = new URL(request.url, "http://localhost").searchParams;
213
+ if ([...query.keys()].some(k => !["cursor", "source"].includes(k) || query.getAll(k).length !== 1)) {
214
+ throw new WebRequestRejected("Unknown Model query.");
215
+ }
216
+ let value;
217
+ if (method === "GET" && pathname === "/api/models")
218
+ value = service.read();
219
+ else if (method === "GET" && pathname === "/api/models/catalog")
220
+ value = service.readCatalog(query.get("cursor") ?? "0");
221
+ else if (method === "GET" && pathname === "/api/models/quota")
222
+ value = service.readQuota(query.get("source") ?? "factory");
223
+ else if (method === "POST") {
224
+ // Credential-bearing forms require an exact same-origin browser request.
225
+ if (headerValue(request, "origin") !== `http://${headerValue(request, "host")}`) {
226
+ throw new WebRequestRejected("Model changes require a same-origin request.");
227
+ }
228
+ if (headerValue(request, "content-type")?.split(";")[0]?.trim() !== "application/json") {
229
+ throw new WebRequestRejected("Model changes require JSON.");
230
+ }
231
+ const body = await readMutationBody(request);
232
+ if (pathname === "/api/models/connection")
233
+ value = service.saveConnection(body);
234
+ else if (pathname === "/api/models/provider")
235
+ value = service.saveProvider(body);
236
+ else if (pathname === "/api/models/refresh")
237
+ value = await service.refresh(body);
238
+ else
239
+ throw new WebRequestRejected("Unknown Model operation.");
240
+ }
241
+ else {
242
+ sendJson(response, 405, { error: "Method not allowed.", disposition: "not-submitted" }, false);
243
+ return;
244
+ }
245
+ sendJson(response, 200, value, false);
246
+ }
247
+ catch (error) {
248
+ sendJson(response, 409, {
249
+ error: error instanceof WebRequestRejected ? error.message : "Model operation failed. Inspect the current state before retrying.",
250
+ disposition: method === "GET" || error instanceof WebRequestRejected ? "not-submitted" : "unknown"
251
+ }, false);
252
+ }
253
+ return;
254
+ }
207
255
  if (pathname === "/api/settings" || pathname === "/api/settings/group" || pathname === "/api/settings/capabilities") {
208
256
  try {
209
257
  if (!dependencies.settings)
@@ -529,12 +577,14 @@ async function handleHttpRequest(request, response, store, dependencies, token,
529
577
  }
530
578
  if (method === "GET" || method === "HEAD") {
531
579
  try {
532
- const asset = findWebAsset(pathname);
533
- if (pathname === "/" || pathname === "/index.html" || pathname === "/settings") {
534
- sendText(response, 200, "text/html; charset=utf-8", pathname === "/settings" ? SETTINGS_HTML.replace("__YUI_WEB_TOKEN__", token) : dashboardHtml(token), method === "HEAD");
580
+ const assetVersion = new URL(request.url, "http://localhost").searchParams.get("v");
581
+ const asset = findWebAsset(pathname, assetVersion);
582
+ const managementPage = /^\/(?:models(?:\/(?:providers|catalog|quota))?|settings(?:\/(?:preferences|skills|server|connection))?)\/?$/.test(pathname);
583
+ if (pathname === "/" || pathname === "/index.html" || managementPage) {
584
+ sendText(response, 200, "text/html; charset=utf-8", prepareWebDocument(managementPage ? MODELS_HTML.replace("__YUI_WEB_TOKEN__", token) : dashboardHtml(token), managementPage ? "/assets/js/app/manage.js" : "/assets/app.js"), method === "HEAD");
535
585
  }
536
586
  else if (asset !== null) {
537
- sendAsset(response, asset, method === "HEAD");
587
+ sendAsset(response, asset, method === "HEAD", assetVersion === WEB_ASSET_VERSION);
538
588
  }
539
589
  else if (pathname === "/api/search") {
540
590
  const query = new URL(request.url, "http://localhost").searchParams;
@@ -960,12 +1010,12 @@ function sendText(response, status, contentType, body, head) {
960
1010
  response.setHeader("content-length", Buffer.byteLength(body));
961
1011
  response.end(head ? undefined : body);
962
1012
  }
963
- function sendAsset(response, asset, head) {
1013
+ function sendAsset(response, asset, head, versioned = false) {
964
1014
  const payload = asset.encoding === "base64"
965
1015
  ? Buffer.from(asset.body, "base64")
966
1016
  : Buffer.from(asset.body, "utf-8");
967
- if (asset.contentType.startsWith("font/") || asset.contentType.startsWith("image/")) {
968
- response.setHeader("cache-control", "public, max-age=31536000, immutable");
1017
+ if (versioned) {
1018
+ response.setHeader("cache-control", "private, max-age=31536000, immutable");
969
1019
  }
970
1020
  response.statusCode = 200;
971
1021
  response.setHeader("content-type", asset.contentType);
@@ -14,14 +14,15 @@ schema migration or new snapshot/cache store is introduced.
14
14
  | Question | Entry | Default information / further reading |
15
15
  | --- | --- | --- |
16
16
  | Which Task? | `task list` | Existing bounded catalog, filters, attention and cursor |
17
- | What is current? | `task context <task>` | Current Task/Brief/Role/Project/workspace facts, active work and Runs, open inputs, active decisions, unresolved jobs, recent Message references; no event or terminal-Run dump |
17
+ | What is current? | `task context <task>` | Current facts, active work, open inputs, active decisions, unresolved jobs and unacknowledged Message references; no event or terminal-Run dump |
18
18
  | What records exist? | `task context list <task> --store <family>` | One authorized family, summaries and exact digest-bearing references |
19
19
  | What does it actually say? | `task context inspect <task> --store <family> --ref <id> --digest <digest>` | Exact current record, including original result expansion; long documents are paged |
20
20
  | What changed? | `task context delta <task> --after <cursor>` | Immutable events with a fixed upper bound, not a snapshot of current mutable state |
21
- | Which Global input? | `session context <role>` | Identity, profile, authority, current native Turn/retry and separate bounded pending/recent Message pages |
21
+ | Which Global input? | `session context <role>` | Identity, Profile read pointer, authority, current native Turn/retry facts and a bounded pending Message page; history is opt-in |
22
22
  | Read Global input | `role message list <role> [--pending]`, `role message show <role> <id>` | Scoped discovery, then exact original; queue acceptance never erases history |
23
23
  | What arrived in this wake? | `task wake show <task> <wake>` | Fixed-window inputs/results, attributed optional summaries and exact original reads; `--history` expands diagnostics |
24
- | What was assigned? | `task run context <task>/<run>` | Frozen authority and a single `pointers` inventory with summaries; changed identities in `deltaRefs`; current observations remain separate |
24
+ | What was assigned? | `task run context <task>/<run>` | Frozen authority, up to 16 `pointers`, sampled changed identities and live observations with totals; `--view refs` pages references, `--view full` reads the full pack |
25
+ | Which repeated failure? | `role message list <role> --diagnostics` | Derived classified groups with count, first/latest and recovery evidence; `--diagnostic <key>` pages original occurrences |
25
26
  | Which configuration is real? | `task role session inspect <task> <role>` | Task/Role identity, desired binding, frozen Session, current Provider binding, retry and explicit Host observation; no full Task/Role copies or Provider conversation history |
26
27
 
27
28
  Domain lists for Task Messages, events, WorkItems, Runs, decisions, milestones,
@@ -35,23 +36,35 @@ workspaces and other authorized record families. `--status`, `--after` and
35
36
  `--work-item` narrow Context discovery; every continuation must retain filters.
36
37
  Run listing accepts a Task or `task/work` target.
37
38
 
38
- Current Context's `attention.messages` counts all authorized Messages, not only
39
- undelivered input. `collections` counts and `omitted` explicitly describe
40
- incomplete discovery. Recent samples are not proof that no older pending or
39
+ Current Context's `attention.messages` excludes explicit acknowledgements and
40
+ retirements; delivery alone is not handling. The exact wake receipt and latest
41
+ Message revision determine coverage. `--view current` continues that view;
42
+ the default family list still includes history. `collections` counts and `omitted`
43
+ explicitly describe incomplete discovery. Samples are not proof that no older pending or
41
44
  relevant input exists. Read the relevant fixed wake and original Messages;
42
45
  use family discovery when a broader requirement/history audit is needed.
43
46
 
44
47
  ## Budgets and continuations
45
48
 
46
- - Discovery pages default to 20 items, accept 1–100, and reserve a 32 KiB
47
- compact-JSON budget. Items contain summaries, never full Message/report bodies.
49
+ - Discovery pages default to 20 items, accept 1–100, and enforce a 32 KiB
50
+ compact-JSON budget including the success envelope, escaped identities,
51
+ continuation and nested structure. Summaries are at most 512 UTF-8 bytes.
48
52
  - Current Task Context has at most 64 records, with a 24 KiB record/attention
49
53
  budget inside a 32 KiB response budget. Single inline values are at most
50
54
  2 KiB; large values and Message/Run/WorkItem/Knowledge bodies use references.
51
55
  Each collection contributes at most eight sampled records at entry.
52
- - Global entry samples up to eight pending and eight recent Messages separately.
53
- They have independent continuations, so a long historical list cannot crowd
54
- pending input out of the entry view.
56
+ - Global entry samples up to eight unacknowledged inputs, including claimed or
57
+ uncertain ones. It does not repeat recent history, Profile bodies, frozen Skill
58
+ packages or accumulated retry details. The Manifest is the Profile pointer;
59
+ explicit Message and Session retry reads retain history and original evidence.
60
+ - Run entry samples up to eight records per live category and 16 frozen refs.
61
+ Pointer continuation uses `--view refs` and `pointerPage.nextCursor`; full pack
62
+ document continuation uses `--view full`. Neither changes the frozen authority.
63
+ Read `--view input` before acting when `input.directiveOmitted` is true: the
64
+ entry's bounded directive summary is not the assigned instruction body.
65
+ - `session skills [--cursor ...]` checks only current metadata/readability. It
66
+ does not read Skill bodies or historical packages, and uses document pagination
67
+ only when the configured metadata exceeds the inline budget.
55
68
  - Detail documents up to 16 KiB remain ordinary JSON. Larger documents return
56
69
  `contentPage`: exact source, SHA-256 digest, JSON-character offset, total bytes
57
70
  and characters, text, completeness and a next cursor. Chunks contain at most
@@ -78,6 +91,24 @@ concurrent writes. For append-only event traversal use fixed-bound Context delta
78
91
  Discovery currently scans the selected authorized family to fingerprint it;
79
92
  its output, not total storage-reading cost, is bounded.
80
93
 
94
+ ## Runtime diagnostics
95
+
96
+ Global failure evidence remains ordinary record-only Messages; no aggregate
97
+ table, Message envelope change, memory store or recovery state machine is added.
98
+ Grouping is a derived view of new evidence documents. Older documents remain
99
+ readable in ordinary history, not heuristically reclassified. Classified source,
100
+ Host/Session, error category/code and explicit effect distinctions determine
101
+ equivalence; unclassified faults are not merged. Original affected IDs and raw
102
+ evidence remain in exact documents, never a growing array in one notification.
103
+ Counts represent distinct observations, not repeat polls of the same identity.
104
+
105
+ One queued notice represents an unchanged failure episode. Only a new group,
106
+ changed impact or exact successful recovery observation produces a new notice.
107
+ Recovery ends the corresponding episode without acknowledging inputs or proving
108
+ absence of previous effects. Recurrence after recovery gets a new episode.
109
+ Operator's own failures/recovery notices are retained without self-delivery.
110
+ Discovery and every evidence page retain the existing Role read boundary.
111
+
81
112
  ## Effects and exceptions
82
113
 
83
114
  Message send/queue/steer receipts preserve identity, digest, body byte count and
@@ -12,14 +12,14 @@ CLI 调用成功,不代表 Task、原生 Turn 或远端投递完成。
12
12
  | 问题 | 入口 | 默认信息与下一步 |
13
13
  | --- | --- | --- |
14
14
  | 找哪个 Task? | `task list` | 既有有界目录、过滤器、attention 与游标 |
15
- | 当前有什么? | `task context <task>` | 当前 Task/Brief/Role/Project/工作区事实、活跃工作与 Run、开放输入、有效决策、未解决 Job、近期 Message 引用;不倾倒事件或终态 Run |
15
+ | 当前有什么? | `task context <task>` | 当前事实、活跃工作、开放输入、有效决策、未解决 Job、未确认处理的 Message 引用;不倾倒事件或终态 Run |
16
16
  | 有哪些记录? | `task context list <task> --store <family>` | 一种获授权的记录、摘要与带 digest 的确切引用 |
17
17
  | 原文是什么? | `task context inspect <task> --store <family> --ref <id> --digest <digest>` | 确切当前记录,含原始结果展开;长文档分页 |
18
18
  | 发生了什么变化? | `task context delta <task> --after <cursor>` | 固定上界内的不可变事件,不是可变当前状态的快照 |
19
- | Global 收到了什么? | `session context <role>` | 身份、Profile、权限、当前原生 Turn/retry,以及分别有界的 pending/recent Message 页 |
19
+ | Global 收到了什么? | `session context <role>` | 身份、Profile 读取指针、权限、当前 Turn/retry 事实与小窗口 pending 页;历史按需读取 |
20
20
  | 读取 Global 输入 | `role message list <role> [--pending]`、`role message show <role> <id>` | 在自身范围内发现,再读完整原文;队列接受不删除历史 |
21
21
  | 本次唤醒带来什么? | `task wake show <task> <wake>` | 固定窗口的输入/结果、标明来源的可选摘要和确切原文入口;`--history` 展开诊断历史 |
22
- | 分配了什么? | `task run context <task>/<run>` | 冻结授权与一份带摘要的 `pointers` 目录;`deltaRefs` 表示变化身份;当前观察独立 |
22
+ | 分配了什么? | `task run context <task>/<run>` | 冻结授权与有限 `pointers` 窗口,变化身份和活跃观察附总数;`--view refs/full` 按需扩展 |
23
23
  | 实际配置是什么? | `task role session inspect <task> <role>` | Task/Role 身份、期望绑定、冻结 Session、当前 Provider 绑定、retry 与显式 Host 观察;不复制整个 Task/Role 或 Provider 会话历史 |
24
24
 
25
25
  Task Message、事件、WorkItem、Run、决策、里程碑、publication 和 InputRequest 列表
@@ -31,17 +31,26 @@ Context 列表还暴露候选、Review、Job、Project Knowledge、工作区等
31
31
  `--status`、`--after`、`--work-item` 缩小发现范围;续读必须保留过滤条件。
32
32
  Run 列表接受 Task 或 `task/work` 目标。
33
33
 
34
- 当前 Context 的 `attention.messages` 统计全部获授权 Message,不仅是未投递输入。
35
- `collections` 计数与 `omitted` 明确表达发现不完整。近期抽样不能证明没有更早的待处理
34
+ 当前 Context 的 `attention.messages` 排除明确 ack 或退役的 Message;投递成功不代表
35
+ 处理完成。精确 wake 回执必须覆盖最新原文版本。用 `--view current` 续读当前视图,
36
+ 默认分类列表仍保留完整历史。`collections` 计数与 `omitted` 明确表达发现不完整。抽样不能证明没有更早的待处理
36
37
  或相关输入。读取相关固定 wake 与原始 Message;更广的需求/历史审计使用分类发现。
37
38
 
38
39
  ## 预算与续读
39
40
 
40
- - 发现页默认 20 条,可选 1–100,紧凑 JSON 预算 32 KiB。条目包含摘要,不含完整报告正文。
41
+ - 发现页默认 20 条,可选 1–100,紧凑 JSON 预算 32 KiB,计入成功 envelope、
42
+ 转义身份、游标和嵌套结构。摘要至多 512 UTF-8 字节,不含完整报告正文。
41
43
  - 当前 Task Context 至多 64 条,记录与 attention 共 24 KiB,响应预算 32 KiB。
42
44
  单个内联值至多 2 KiB;大值及 Message/Run/WorkItem/Knowledge 正文用引用。
43
45
  入口每个集合最多抽样八条。
44
- - Global 入口分别抽样八条 pending 与八条 recent;独立续读,历史不能挤掉待处理输入。
46
+ - Global 入口最多八条未确认处理的输入,保留已领取或效果未知项;不重复 recent、
47
+ Profile 正文、历史 Skill 包和累计 retry 详情。Profile 由 Manifest 精确指向。
48
+ - Run 入口最多 16 个冻结引用和每类八条活跃观察,附总数。`--view refs` 配合
49
+ `pointerPage.nextCursor` 发现更多引用;`--view full` 显式读取完整冻结包。
50
+ 若 `input.directiveOmitted` 为 true,行动前用 `--view input` 全文读取分配指令;
51
+ 默认入口的指令摘要不是指令正文。
52
+ - `session skills [--cursor ...]` 只检查当前元信息和可读性,不读技能正文;
53
+ 配置元信息过大时使用相同文档分页。
45
54
  - 不超过 16 KiB 的详情保持普通 JSON。更大详情返回 `contentPage`:确切来源、
46
55
  SHA-256 digest、JSON 字符偏移、总字节数/字符数、文本、完整性与下一游标。
47
56
  每块最多 4096 个 UTF-16 单元,不拆代理对,转义后的输出低于 32 KiB。
@@ -61,6 +70,18 @@ Run 列表接受 Task 或 `task/work` 目标。
61
70
  追加事件遍历使用固定上界 Context delta。目前分类发现扫描选定的授权集合来计算指纹;
62
71
  有界的是输出,不是总存储读取成本。
63
72
 
73
+ ## 重复运行时诊断
74
+
75
+ `role message list <role> --diagnostics` 从原始 record-only Message 派生故障组,
76
+ 给出首次/最近时间、不同观察的数量及恢复证据;`--diagnostic <key>` 分页发现原文。
77
+ 按明确的 Host/Session、来源、故障类别/代码及效果边界区分;未分类错误不猜测合并。
78
+ 同一观察重复轮询不新增记录或计数,同组跨 Turn 不重复唤醒。新故障、影响变化、
79
+ 精确成功恢复或恢复后再发生可产生通知。Operator 自身诊断保留但不自动唤醒自身。
80
+ 恢复不等于消息 ack、Task 完成或撤销旧副作用。
81
+
82
+ 聚合不持久化,也不累计受影响 ID 数组;不增加表、消息 envelope 字段或第二状态机。
83
+ 旧证据仍由普通历史读取,不启发式重新分类。每页沿用现有 Role 权限边界。
84
+
64
85
  ## 效果与例外
65
86
 
66
87
  Message send/queue/steer 回执保留身份、digest、正文字节数及原有提交/投递/control
@@ -39,6 +39,40 @@ automatically create Runs. Explicit dispatch loads one exact Run Context Pack.
39
39
 
40
40
  ## Context
41
41
 
42
+ ### Current caller and durable handling
43
+
44
+ Desktop and TUI use the same current-Session authority. A Desktop command carrying
45
+ only `CODEX_THREAD_ID` resolves its owner from the selected Home's existing active
46
+ Session inventory, then verifies the current Role/Agent binding, revocation and
47
+ captured workspace. Codex's native ID takes precedence over an inherited transport
48
+ ID, so a native child cannot borrow its parent's identity. Unknown native IDs,
49
+ wrong Homes and conflicting hints fail closed; only a terminal with no managed or
50
+ native identity is a plain user. Environment variables and a Manifest locate
51
+ context, not continuing authority. A replaced Session retains only its bounded
52
+ self-diagnostic reads, not inbox or mutation permission.
53
+
54
+ `yui inbox list` exposes the current identity, delivery evidence, handling state
55
+ and blockers separately. Reads never consume input. Automatically accepted
56
+ Global messages, delivered Leader windows and the current Assignment's
57
+ continuation messages still need `claim` and explicit `ack --reason` after their
58
+ originals and effects have been handled. Claiming delivered input does not resend
59
+ it. Pending/unknown acceptance cannot be taken over; an accepted Global input or
60
+ Leader window can be explicitly settled by its rightful successor without
61
+ changing its original delivery target. Include useful result/effect receipt
62
+ references in the reason. Task completion still requires handling user inputs,
63
+ not merely a native terminal.
64
+
65
+ Receipts remain on the existing Message/TaskWake records. Both notification
66
+ paths pin mutable Draft revisions by existing `message.updated` event IDs,
67
+ not timestamps; a later revision cannot inherit an old acknowledgement.
68
+ Claimed Message content and fixed window references cannot be silently replaced.
69
+ Duplicate accepted notifications do not re-submit that revision. If a handler
70
+ crashes or ack fails after an external effect, inspect the original claim and
71
+ effect receipt, finish only unfinished work, and retry the same acknowledgement.
72
+ No lease expires and no installation upgrade or context compaction resets
73
+ handling. This reuses storage 1.7 payloads without adding a message system,
74
+ schema transition or an arbitrary external exactly-once guarantee.
75
+
42
76
  ```sh
43
77
  yui task context <task> --json
44
78
  yui task context list <task> --store <store> [--cursor <cursor>]
@@ -69,11 +103,27 @@ Run Pack is a reference directory: read the relevant requirement and message
69
103
  bodies before acting, rather than treating a successful load as the deliverable.
70
104
  Planning Packs expose no Project write scope or Task-completion permission.
71
105
 
72
- The Manifest pointer is a recovery locator, not a read receipt. Load its exact
73
- `yui-runtime`, Role Skills and profile on first entry, a new/version-changed
74
- Session, or missing context after compaction/recovery. Reuse instructions only
75
- when the same-version full content is still available; Yui stores no "already
76
- read" state. Always refresh dynamic facts. Leader notifications use
106
+ The Manifest pointer is a recovery locator, not a read receipt. At the start of
107
+ every turn run `yui session skills --json` through the Session's CLI/Home. It
108
+ checks current paths, internal `VERSION` files and readability, without reading
109
+ Skill bodies or walking/snapshotting resources. Builtins use the running
110
+ installation's `skills/<id>` entry; configured Skills use `YUI_HOME/skills/<id>`.
111
+ These paths do not contain a Session/content digest. After changing installation
112
+ locations the check resolves the current installation, not an old recorded path.
113
+ For Global Sessions the Manifest's `skillCheckCommand` is its self-contained
114
+ `session context <role>` read, which also returns current Skill metadata and works
115
+ after moving to Desktop without the launch shell's environment. An older Global
116
+ Manifest's existing `loadCommand` provides the same check.
117
+
118
+ Load current `yui-runtime`, applicable Role/custom Skills and necessary references,
119
+ plus the Manifest's profile, on first entry, a version change, recovery, or missing/
120
+ compacted/uncertain context. Reuse only when versions are unchanged and the full
121
+ instructions remain available now. Yui stores no "already read" state and does
122
+ not claim to inspect the model's context. Historical packages remain audit only;
123
+ missing/corrupt snapshots do not prevent valid Session resume or input delivery.
124
+ Missing current files report their exact path and recovery action. Session
125
+ identity, scope, writer fences and real CLI/Home incompatibility still reject.
126
+ Always refresh dynamic facts. Leader notifications use
77
127
  `currentCommand`; dispatched AgentRuns use the actual Run ID with
78
128
  `loadCommand`/`expandCommand`, never their placeholder templates.
79
129
 
@@ -139,6 +189,78 @@ summary store, read-acknowledgement or extra model call is involved. Missing or
139
189
  oversized summaries fall back to facts without clipping qualifications.
140
190
  Summaries never grant authority, accept results or mark reviews approved.
141
191
 
192
+ ### Operator backlog and periodic recovery
193
+
194
+ Task completion/cancellation/retirement, publication records/adoption and input
195
+ requests enqueue Operator attention in the same transaction as their durable
196
+ event. Existing Run failure routing keeps its retry and supervisor guards.
197
+ The ready mailbox is the incremental recovery source: a lost scheduler signal
198
+ or Controller restart does not require a Leader report or a scan of historical
199
+ Tasks. The existing periodic pass retries outstanding mailbox work; an unchanged,
200
+ settled mailbox creates neither a Message nor a model call.
201
+
202
+ At most one unsent engineering notice is queued. Further facts coalesce in the
203
+ mailbox until that notice is accepted or conclusively not delivered. Each handoff
204
+ claims at most 64 source signals and reads exact records, retaining the unclaimed
205
+ suffix. Global delivery reads at most 64 pending Messages per Role per pass;
206
+ conclusively stale originals retain their nondelivery evidence, with later pages
207
+ handled by subsequent passes. Reserved interrupt-then inputs remain discoverable
208
+ beyond that ordinary page. FIFO user inputs and unknown-effect fences are not
209
+ reordered to make notifications appear healthy. SQL aggregates still inspect
210
+ matching stored rows; these bounds limit materialized records and per-pass
211
+ delivery work, not the size of the persisted mailbox or database.
212
+
213
+ A full reconciliation may ask the original Host to republish an already observed
214
+ terminal for the exact Session, authority, attempt and native Turn. For a Desktop
215
+ direct Turn, that Host must have retained both the exact start and terminal under
216
+ the unchanged writer fence; `direct:<nativeTurnId>` and the native Turn are both
217
+ required. This bounded latest observation does not make the input client-owned.
218
+ During an Inbox persistence failure, the Host additionally retains every
219
+ unpersisted original fact, including starts and full terminals, until the
220
+ existing Inbox accepts it. Later direct turns must not overwrite those bytes.
221
+ This uses the existing Inbox and canonical observer, including the original result.
222
+ It does not submit input, query another native client, restart a Host, or infer
223
+ quiescence from elapsed time/idle state. Normal terminal processing signals again
224
+ after releasing Host occupancy. Unknown acceptance remains isolated unless exact
225
+ evidence settles that input. Explicit stop/replacement and external writers remain
226
+ hard boundaries. Full Task and Global reconciliation also covers an unsettled
227
+ final input with no queued successor. A filesystem repair retries observations,
228
+ not native execution; process loss before persistence remains a disclosed gap.
229
+
230
+ `yui session context <role> --json` includes bounded `backlog` diagnostics: pending
231
+ count, oldest timestamp, target and attempt identities, blocking reason and
232
+ recovery guidance. Live age is in `backlogObservation`, outside the paged source
233
+ digest. `in-flight-or-unobserved-terminal` deliberately does not label a
234
+ long-running accepted Turn as stuck. An unavailable/older Host or missing retained
235
+ terminal produces one record-only runtime-attention Message per exact attempt;
236
+ inspect it through the existing message list/show commands. No recovery Agent,
237
+ private timer, migration or new acknowledgement state is introduced. If the
238
+ Provider itself never reported a terminal, or the original Host lost its evidence,
239
+ automatic reconciliation cannot prove completion: restore the compatible observation
240
+ path or explicitly stop/replace only with the required native quiescence evidence.
241
+ This change does not backfill arbitrary pre-existing historical events, adopt old
242
+ Hosts, or authorize production upgrades/restarts.
243
+
244
+ Controller restart preserves live Hosts; it does not replace their loaded code.
245
+ A supported surviving Host writes raw observations to the immutable Inbox even
246
+ while the Controller is down; the restarted Controller applies them under current
247
+ Session fences. A frozen Manifest's CLI/storage mismatch is a context-read failure,
248
+ not proof that the Host publisher failed: this publisher uses the Inbox/RPC, not
249
+ that CLI. An Endpoint checkout generation is not a complete Host build identity.
250
+ The runtime-attention evidence distinguishes an unavailable control channel,
251
+ rejected control (including implementations without reconciliation), and a missing
252
+ exact retained terminal, with reported Endpoint/event-delivery observations.
253
+ The status `controlCapabilities` advertisement gates additive v1 commands.
254
+ Missing `reconcile-turn` support yields `unsupported` without sending the
255
+ invalid request. The original Inbox remains usable; no alternative native
256
+ input or guessed terminal is generated. `hostImplementation` identifies code
257
+ captured when the Host loaded, not the current install or Endpoint generation.
258
+ Compatible build changes do not block exact native Session resume after an
259
+ authorized safe release. They never change the user's launch configuration.
260
+ Missing delivery diagnostics mean unreported, not healthy. Unsupported live code
261
+ cannot be repaired by another Controller restart or guessed adoption; inspect the
262
+ original evidence and explicitly authorize any necessary lifecycle recovery.
263
+
142
264
  `task wake show <task> <wake>` now defaults to inputs/results and explicit
143
265
  references, including older referenced originals. It omits unrelated diagnostic
144
266
  events and merely started Runs; `--history` restores full fixed-window discovery.