dsh-kingdom 0.8.0 → 2.0.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 (162) hide show
  1. package/ASSETS_NOTICE.md +22 -0
  2. package/LICENSE +661 -29
  3. package/NOTICE +9 -0
  4. package/README.md +93 -94
  5. package/THIRD_PARTY_NOTICES.md +92 -0
  6. package/cordis.patch.yml +6 -6
  7. package/docs/V2.0-RELEASE-NOTES.md +30 -0
  8. package/docs/V2.0-USER-GUIDE.md +74 -0
  9. package/lib/adapter/dsh-backend.js +327 -24
  10. package/lib/adapter/dsh-backend.js.map +1 -1
  11. package/lib/adapter/dsh-cost.js +68 -0
  12. package/lib/adapter/dsh-cost.js.map +1 -0
  13. package/lib/adapter/dsh-session-events.js +86 -0
  14. package/lib/adapter/dsh-session-events.js.map +1 -0
  15. package/lib/adapter/dsh-usage.js +159 -0
  16. package/lib/adapter/dsh-usage.js.map +1 -0
  17. package/lib/capability/admin.js +72 -0
  18. package/lib/capability/admin.js.map +1 -0
  19. package/lib/capability/dsh-enforcement.js +143 -34
  20. package/lib/capability/dsh-enforcement.js.map +1 -1
  21. package/lib/capability/resolver.js +21 -8
  22. package/lib/capability/resolver.js.map +1 -1
  23. package/lib/capability/service.js +169 -26
  24. package/lib/capability/service.js.map +1 -1
  25. package/lib/capability/tool-disclosure.js +144 -0
  26. package/lib/capability/tool-disclosure.js.map +1 -0
  27. package/lib/core/binding.js +52 -34
  28. package/lib/core/binding.js.map +1 -1
  29. package/lib/core/budget.js +304 -0
  30. package/lib/core/budget.js.map +1 -0
  31. package/lib/core/collaboration.js +422 -0
  32. package/lib/core/collaboration.js.map +1 -0
  33. package/lib/core/cost.js +212 -0
  34. package/lib/core/cost.js.map +1 -0
  35. package/lib/core/db.js +197 -4
  36. package/lib/core/db.js.map +1 -1
  37. package/lib/core/execution.js +2 -2
  38. package/lib/core/execution.js.map +1 -1
  39. package/lib/core/governed-claim.js +46 -0
  40. package/lib/core/governed-claim.js.map +1 -0
  41. package/lib/core/governed.js +891 -98
  42. package/lib/core/governed.js.map +1 -1
  43. package/lib/core/kingdom.js +78 -70
  44. package/lib/core/kingdom.js.map +1 -1
  45. package/lib/core/owner-binding-intent.js +732 -0
  46. package/lib/core/owner-binding-intent.js.map +1 -0
  47. package/lib/core/owner-control.js +86 -0
  48. package/lib/core/owner-control.js.map +1 -0
  49. package/lib/core/owner-window.js +822 -0
  50. package/lib/core/owner-window.js.map +1 -0
  51. package/lib/core/task-service.js +296 -133
  52. package/lib/core/task-service.js.map +1 -1
  53. package/lib/core/territory.js +44 -14
  54. package/lib/core/territory.js.map +1 -1
  55. package/lib/core/usage.js +39 -0
  56. package/lib/core/usage.js.map +1 -0
  57. package/lib/core/workspace-admission.js +225 -0
  58. package/lib/core/workspace-admission.js.map +1 -0
  59. package/lib/dispatch/evidence.js +5 -2
  60. package/lib/dispatch/evidence.js.map +1 -1
  61. package/lib/dispatch/reconcile.js +3 -9
  62. package/lib/dispatch/reconcile.js.map +1 -1
  63. package/lib/dispatch/service.js +464 -64
  64. package/lib/dispatch/service.js.map +1 -1
  65. package/lib/gui/assets/characters/chancellor-idle.svg +67 -0
  66. package/lib/gui/assets/characters/chancellor-sleeping.svg +67 -0
  67. package/lib/gui/assets/characters/chancellor-thinking.svg +67 -0
  68. package/lib/gui/assets/characters/chancellor-working.svg +67 -0
  69. package/lib/gui/assets/characters/knight-redraw-r1-idle.svg +67 -0
  70. package/lib/gui/assets/characters/knight-redraw-r1-sleeping.svg +67 -0
  71. package/lib/gui/assets/characters/knight-redraw-r1-thinking.svg +67 -0
  72. package/lib/gui/assets/characters/knight-redraw-r1-working.svg +67 -0
  73. package/lib/gui/assets/characters/supervisor-idle.svg +67 -0
  74. package/lib/gui/assets/characters/supervisor-sleeping.svg +67 -0
  75. package/lib/gui/assets/characters/supervisor-thinking.svg +67 -0
  76. package/lib/gui/assets/characters/supervisor-working.svg +67 -0
  77. package/lib/gui/console-app.js +2330 -0
  78. package/lib/gui/console-app.js.map +1 -0
  79. package/lib/gui/contract.js +5 -5
  80. package/lib/gui/contract.js.map +1 -1
  81. package/lib/gui/control-contract.js +232 -0
  82. package/lib/gui/control-contract.js.map +1 -0
  83. package/lib/gui/local-control.js +423 -0
  84. package/lib/gui/local-control.js.map +1 -0
  85. package/lib/gui/owner-control.js +310 -0
  86. package/lib/gui/owner-control.js.map +1 -0
  87. package/lib/gui/owner-ui.js +191 -0
  88. package/lib/gui/owner-ui.js.map +1 -0
  89. package/lib/gui/server.js +445 -35
  90. package/lib/gui/server.js.map +1 -1
  91. package/lib/gui/snapshot.js +1346 -67
  92. package/lib/gui/snapshot.js.map +1 -1
  93. package/lib/gui/visual-assets.js +56 -0
  94. package/lib/gui/visual-assets.js.map +1 -0
  95. package/lib/gui/visual-system.js +272 -0
  96. package/lib/gui/visual-system.js.map +1 -0
  97. package/lib/gui/workbench-ui.js +358 -0
  98. package/lib/gui/workbench-ui.js.map +1 -0
  99. package/lib/gui/workbench.js +163 -0
  100. package/lib/gui/workbench.js.map +1 -0
  101. package/lib/index.js +1384 -361
  102. package/lib/index.js.map +1 -1
  103. package/lib/runner-context-broker.js +1134 -0
  104. package/lib/runner-context-broker.js.map +1 -0
  105. package/lib/runtime-cost-observer.js +145 -0
  106. package/lib/runtime-cost-observer.js.map +1 -0
  107. package/lib/types/adapter/contract.d.ts +61 -1
  108. package/lib/types/adapter/dsh-backend.d.ts +32 -13
  109. package/lib/types/adapter/dsh-cost.d.ts +13 -0
  110. package/lib/types/adapter/dsh-session-events.d.ts +16 -0
  111. package/lib/types/adapter/dsh-usage.d.ts +36 -0
  112. package/lib/types/capability/admin.d.ts +13 -0
  113. package/lib/types/capability/dsh-enforcement.d.ts +11 -7
  114. package/lib/types/capability/service.d.ts +10 -3
  115. package/lib/types/capability/tool-disclosure.d.ts +36 -0
  116. package/lib/types/core/binding.d.ts +19 -10
  117. package/lib/types/core/budget.d.ts +81 -0
  118. package/lib/types/core/collaboration.d.ts +110 -0
  119. package/lib/types/core/cost.d.ts +99 -0
  120. package/lib/types/core/db.d.ts +44 -4
  121. package/lib/types/core/execution.d.ts +1 -1
  122. package/lib/types/core/governed-claim.d.ts +7 -0
  123. package/lib/types/core/governed.d.ts +182 -1
  124. package/lib/types/core/kingdom.d.ts +3 -0
  125. package/lib/types/core/owner-binding-intent.d.ts +176 -0
  126. package/lib/types/core/owner-control.d.ts +53 -0
  127. package/lib/types/core/owner-window.d.ts +226 -0
  128. package/lib/types/core/task-service.d.ts +60 -13
  129. package/lib/types/core/territory.d.ts +9 -2
  130. package/lib/types/core/usage.d.ts +26 -0
  131. package/lib/types/core/workspace-admission.d.ts +43 -0
  132. package/lib/types/dispatch/evidence.d.ts +2 -5
  133. package/lib/types/dispatch/service.d.ts +62 -4
  134. package/lib/types/gui/console-app.d.ts +137 -0
  135. package/lib/types/gui/contract.d.ts +396 -16
  136. package/lib/types/gui/control-contract.d.ts +111 -0
  137. package/lib/types/gui/local-control.d.ts +120 -0
  138. package/lib/types/gui/owner-control.d.ts +45 -0
  139. package/lib/types/gui/owner-ui.d.ts +2 -0
  140. package/lib/types/gui/server.d.ts +17 -3
  141. package/lib/types/gui/snapshot.d.ts +33 -11
  142. package/lib/types/gui/visual-assets.d.ts +27 -0
  143. package/lib/types/gui/visual-system.d.ts +2 -0
  144. package/lib/types/gui/workbench-ui.d.ts +5 -0
  145. package/lib/types/gui/workbench.d.ts +33 -0
  146. package/lib/types/index.d.ts +157 -6
  147. package/lib/types/runner-context-broker.d.ts +119 -0
  148. package/lib/types/runtime-cost-observer.d.ts +22 -0
  149. package/lib/types/worker/collaboration.d.ts +35 -0
  150. package/lib/types/worker/dsh-subagent.d.ts +4 -4
  151. package/lib/types/worker/executor-factory.d.ts +2 -1
  152. package/lib/types/worker/executor.d.ts +8 -3
  153. package/lib/types/worker/governed-executor.d.ts +8 -1
  154. package/lib/worker/collaboration.js +172 -0
  155. package/lib/worker/collaboration.js.map +1 -0
  156. package/lib/worker/dsh-subagent.js +4 -4
  157. package/lib/worker/executor-factory.js.map +1 -1
  158. package/lib/worker/executor.js +7 -2
  159. package/lib/worker/executor.js.map +1 -1
  160. package/lib/worker/governed-executor.js +295 -84
  161. package/lib/worker/governed-executor.js.map +1 -1
  162. package/package.json +23 -8
@@ -0,0 +1,212 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ const count = (value) => typeof value === 'number' && Number.isSafeInteger(value) && value >= 0;
3
+ const ref = (value) => typeof value === 'string' && value.length > 0 && value.length <= 768;
4
+ export function validProviderCounts(usage) {
5
+ if (!usage || !count(usage.uncachedInputTokens) || !count(usage.outputTokens) || !count(usage.totalTokens))
6
+ return false;
7
+ for (const key of ['cacheReadTokens', 'cacheWriteTokens', 'reasoningTokens'])
8
+ if (usage[key] !== undefined && !count(usage[key]))
9
+ return false;
10
+ const prompt = usage.uncachedInputTokens + (usage.cacheReadTokens ?? 0) + (usage.cacheWriteTokens ?? 0);
11
+ return count(prompt) && usage.totalTokens >= prompt + usage.outputTokens
12
+ && (usage.reasoningTokens === undefined || usage.reasoningTokens <= usage.outputTokens)
13
+ && (usage.cacheReadTokens === undefined || usage.cacheWriteTokens === undefined || usage.totalTokens === prompt + usage.outputTokens)
14
+ && (usage.routes === undefined || Array.isArray(usage.routes) && usage.routes.length <= 128 && usage.routes.every(route => ref(route.provider) && ref(route.model)));
15
+ }
16
+ function roleRecords(store, kingdomId) {
17
+ const latest = new Map();
18
+ for (const event of store.listRuntimeCostEvents(kingdomId)) {
19
+ if (event.event_type !== 'RUNTIME_ROLE_USAGE_OBSERVED')
20
+ continue;
21
+ try {
22
+ const value = JSON.parse(event.payload_json);
23
+ if (value.type !== 'KingdomRoleUsage/v1' || value.sourceUnitRef !== event.target_id)
24
+ continue;
25
+ const previous = latest.get(value.sourceUnitRef);
26
+ if (previous && (previous.value.observationSequence > value.observationSequence || previous.value.status === 'COMPLETE' && value.status !== 'COMPLETE'))
27
+ continue;
28
+ latest.set(value.sourceUnitRef, { value, firstSeq: previous?.firstSeq ?? event.seq, seq: event.seq });
29
+ }
30
+ catch { /* An invalid historical observation is not free usage. */ }
31
+ }
32
+ return latest;
33
+ }
34
+ function coverageGaps(store, kingdomId, sinceSeq = 0, carriedSourceRefs = []) {
35
+ const units = new Set();
36
+ const carried = new Set(carriedSourceRefs);
37
+ for (const event of store.listRuntimeCostEvents(kingdomId)) {
38
+ if (event.event_type !== 'RUNTIME_ROLE_USAGE_OBSERVED')
39
+ continue;
40
+ try {
41
+ const value = JSON.parse(event.payload_json);
42
+ if (value.type === 'KingdomUsageCoverageGap/v1' && (event.seq > sinceSeq || carried.has(value.sourceUnitRef)))
43
+ units.add(value.sourceUnitRef);
44
+ }
45
+ catch {
46
+ if (event.seq > sinceSeq || carried.has(event.target_id ?? event.event_id))
47
+ units.add(event.target_id ?? event.event_id);
48
+ }
49
+ }
50
+ return units.size;
51
+ }
52
+ export function recordUsageCoverageGap(store, kingdomId, sourceUnitRef, reasonCode) {
53
+ if (!ref(sourceUnitRef) || store.getDefaultKingdom()?.kingdom_id !== kingdomId)
54
+ return;
55
+ const previous = store.getLatestRuntimeRoleUsageEvent(kingdomId, sourceUnitRef);
56
+ if (previous)
57
+ return;
58
+ const value = { type: 'KingdomUsageCoverageGap/v1', sourceUnitRef, reasonCode };
59
+ store.appendEvent({ event_id: randomUUID(), kingdom_id: kingdomId, event_type: 'RUNTIME_ROLE_USAGE_OBSERVED', actor_role: 'SYSTEM',
60
+ actor_id: 'kingdom-cost-observer', target_type: 'runtime-usage', target_id: sourceUnitRef, payload_json: JSON.stringify(value), created_at: new Date().toISOString() });
61
+ }
62
+ /** Arbitrary plugin names are not trusted metadata. Only fixed public categories reach the ledger. */
63
+ export function safePromptPartName(value, index, type) {
64
+ const known = { 'harness:identity': 'harness identity', 'agent:identity': 'agent identity',
65
+ 'tools': 'tool guidance', 'skills': 'skill catalog', 'plugins': 'plugin guidance', 'AGENTS.md': 'workspace guidance',
66
+ 'runtime': 'runtime context', 'runtime:snapshot': 'runtime snapshot' };
67
+ return known[value] ?? `${type} ${index + 1}`;
68
+ }
69
+ export function recordRoleUsage(store, kingdomId, input) {
70
+ const value = structuredClone(input);
71
+ const binding = store.getBindingById(value.bindingId);
72
+ if (!binding || binding.kingdom_id !== kingdomId || !['CHANCELLOR', 'SUPERVISOR'].includes(binding.role_type)
73
+ || binding.role_type !== value.roleType || value.type !== 'KingdomRoleUsage/v1' || value.source !== 'provider-reported'
74
+ || ![value.sourceUnitRef, value.runtimeInstanceRef, value.sessionRef].every(ref)
75
+ || !count(value.startedLedgerSeq) || !count(value.observationSequence) || !Number.isFinite(Date.parse(value.startedAt))
76
+ || !count(value.observedRequests) || !count(value.reportedRequests) || value.reportedRequests > value.observedRequests
77
+ || !['IN_PROGRESS', 'COMPLETE', 'UNAVAILABLE'].includes(value.status)
78
+ || !['TASK', 'SHARED', 'UNATTRIBUTED'].includes(value.attribution)
79
+ || !Array.isArray(value.taskIds) || value.taskIds.length > 32 || new Set(value.taskIds).size !== value.taskIds.length
80
+ || value.taskIds.some(id => { const task = store.getTask(id); return !task || store.getTerritoryById(task.territory_id)?.kingdom_id !== kingdomId; })
81
+ || (value.attribution === 'TASK' ? value.taskIds.length !== 1 : value.attribution === 'UNATTRIBUTED' ? value.taskIds.length !== 0 : value.taskIds.length < 1)
82
+ || (value.status === 'COMPLETE' ? !value.usage || !validProviderCounts(value.usage) || value.observedRequests !== value.reportedRequests : value.usage !== null))
83
+ return false;
84
+ return store.withImmediateTransaction(() => {
85
+ const event = store.getLatestRuntimeRoleUsageEvent(kingdomId, value.sourceUnitRef);
86
+ let previous;
87
+ try {
88
+ previous = event ? JSON.parse(event.payload_json) : undefined;
89
+ }
90
+ catch {
91
+ return false;
92
+ }
93
+ if (previous && previous.type !== 'KingdomRoleUsage/v1')
94
+ return false;
95
+ if (previous && (previous.bindingId !== value.bindingId || previous.sessionRef !== value.sessionRef
96
+ || previous.runtimeInstanceRef !== value.runtimeInstanceRef || previous.startedLedgerSeq !== value.startedLedgerSeq
97
+ || previous.observationSequence > value.observationSequence || previous.status === 'COMPLETE' && value.status !== 'COMPLETE'))
98
+ return false;
99
+ if (previous && JSON.stringify(previous) === JSON.stringify(value))
100
+ return true;
101
+ // A complete turn is an immutable source unit; rescanning after a budget
102
+ // boundary must not move old usage into the new accounting period.
103
+ if (previous?.status === 'COMPLETE')
104
+ return false;
105
+ store.appendEvent({ event_id: randomUUID(), kingdom_id: kingdomId, event_type: 'RUNTIME_ROLE_USAGE_OBSERVED',
106
+ actor_role: 'SYSTEM', actor_id: 'kingdom-cost-observer', target_type: 'runtime-usage', target_id: value.sourceUnitRef,
107
+ payload_json: JSON.stringify(value), created_at: new Date().toISOString() });
108
+ return true;
109
+ });
110
+ }
111
+ /** Lost observer continuity is unknown usage, never proof a Runtime stopped. */
112
+ export function closeInterruptedRoleObservations(store, kingdomId, runtimeInstanceRef) {
113
+ let closed = 0;
114
+ for (const { value } of roleRecords(store, kingdomId).values()) {
115
+ if (value.runtimeInstanceRef !== runtimeInstanceRef || value.status !== 'IN_PROGRESS')
116
+ continue;
117
+ if (recordRoleUsage(store, kingdomId, { ...value, status: 'UNAVAILABLE', reasonCode: 'OBSERVER_RESTARTED', usage: null }))
118
+ closed++;
119
+ }
120
+ return closed;
121
+ }
122
+ export function readAdditionalRoleCost(store, kingdomId, taskId) {
123
+ const all = [...roleRecords(store, kingdomId).values()].map(record => record.value);
124
+ const values = taskId ? all.filter(value => value.attribution === 'TASK' && value.taskIds[0] === taskId) : all;
125
+ const complete = values.filter(value => value.status === 'COMPLETE' && value.usage && validProviderCounts(value.usage));
126
+ const sum = (items) => {
127
+ if (!items.length)
128
+ return null;
129
+ const total = items.reduce((total, item) => total + item.usage.totalTokens, 0);
130
+ return count(total) ? total : null;
131
+ };
132
+ const shared = all.filter(value => value.attribution === 'SHARED' && value.status === 'COMPLETE' && value.usage);
133
+ const unassigned = all.filter(value => value.attribution === 'UNATTRIBUTED' && value.status === 'COMPLETE' && value.usage);
134
+ return { scope: 'OBSERVED_GOVERNANCE_TURNS', units: values.length, completeUnits: complete.length,
135
+ pendingUnits: values.filter(value => value.status === 'IN_PROGRESS').length,
136
+ unknownUnits: values.filter(value => value.status === 'UNAVAILABLE').length + coverageGaps(store, kingdomId),
137
+ attributionGapCount: all.filter(value => value.attribution !== 'TASK').length,
138
+ observedRequests: values.reduce((sum, value) => sum + value.observedRequests, 0),
139
+ reportedRequests: values.reduce((sum, value) => sum + value.reportedRequests, 0), verifiedTokens: sum(complete),
140
+ byRole: ['CHANCELLOR', 'SUPERVISOR'].map(roleType => ({ roleType,
141
+ units: values.filter(value => value.roleType === roleType).length,
142
+ completeUnits: complete.filter(value => value.roleType === roleType).length,
143
+ verifiedTokens: sum(complete.filter(value => value.roleType === roleType)) })),
144
+ sharedTokens: sum(shared), unattributedTokens: sum(unassigned), amount: null, amountStatus: 'PRICE_NOT_CONFIGURED',
145
+ coverageNote: '仅包含本次观测接入后可核对的宰相/主管轮次;共享及未归属不摊入单任务,未接入的外部参与者和旧历史仍是覆盖缺口。' };
146
+ }
147
+ /** Add only non-Worker observations; Worker dispatch reports are already counted by budget.ts. */
148
+ export function readIncompleteRoleUsageSourceRefs(store, kingdomId) {
149
+ const refs = new Set([...roleRecords(store, kingdomId).values()].filter(record => record.value.status !== 'COMPLETE')
150
+ .map(record => record.value.sourceUnitRef));
151
+ for (const event of store.listRuntimeCostEvents(kingdomId)) {
152
+ if (event.event_type !== 'RUNTIME_ROLE_USAGE_OBSERVED')
153
+ continue;
154
+ try {
155
+ const value = JSON.parse(event.payload_json);
156
+ if (value.type === 'KingdomUsageCoverageGap/v1' && ref(value.sourceUnitRef))
157
+ refs.add(value.sourceUnitRef);
158
+ }
159
+ catch {
160
+ refs.add(event.target_id ?? event.event_id);
161
+ }
162
+ }
163
+ return [...refs];
164
+ }
165
+ /** Frozen carry-in sources preserve work already pending when the first policy was created. */
166
+ export function readAdditionalBudgetUsage(store, kingdomId, sinceEventSeq, carriedSourceRefs = []) {
167
+ const carried = new Set(carriedSourceRefs);
168
+ const records = [...roleRecords(store, kingdomId).values()].filter(record => record.seq > sinceEventSeq || carried.has(record.value.sourceUnitRef));
169
+ let verifiedTokens = 0, unknownUnits = 0, pendingUnits = 0, attributionGapCount = 0;
170
+ for (const { value } of records) {
171
+ if (value.status === 'IN_PROGRESS')
172
+ pendingUnits++;
173
+ else if (value.status !== 'COMPLETE' || !value.usage || !validProviderCounts(value.usage))
174
+ unknownUnits++;
175
+ else if (count(verifiedTokens + value.usage.totalTokens))
176
+ verifiedTokens += value.usage.totalTokens;
177
+ else
178
+ unknownUnits++;
179
+ if (value.attribution !== 'TASK')
180
+ attributionGapCount++;
181
+ }
182
+ return { verifiedTokens, unknownUnits: unknownUnits + coverageGaps(store, kingdomId, sinceEventSeq, carriedSourceRefs), pendingUnits, attributionGapCount };
183
+ }
184
+ export function recordPromptCost(store, kingdomId, input) {
185
+ const binding = store.getBindingById(input.bindingId);
186
+ const parts = [...input.sections, ...input.contexts];
187
+ if (!binding || binding.kingdom_id !== kingdomId || !ref(input.sourceUnitRef) || parts.length > 256
188
+ || parts.some(part => !ref(part.name) || !count(part.bytes))
189
+ || ![input.toolsBefore, input.toolsAfter, input.toolsBytesBefore, input.toolsBytesAfter].every(count))
190
+ return;
191
+ const value = { ...input,
192
+ sections: input.sections.map((part, index) => ({ name: safePromptPartName(part.name, index, 'section'), bytes: part.bytes })),
193
+ contexts: input.contexts.map((part, index) => ({ name: safePromptPartName(part.name, index, 'context'), bytes: part.bytes })) };
194
+ store.appendEvent({ event_id: randomUUID(), kingdom_id: kingdomId, event_type: 'RUNTIME_PROMPT_COST_OBSERVED', actor_role: 'SYSTEM',
195
+ actor_id: 'kingdom-cost-observer', target_type: 'runtime-prompt', target_id: input.sourceUnitRef,
196
+ payload_json: JSON.stringify(value), created_at: new Date().toISOString() });
197
+ }
198
+ export function readLatestPromptCosts(store, kingdomId) {
199
+ const latest = new Map();
200
+ for (const event of store.listRuntimeCostEvents(kingdomId)) {
201
+ if (event.event_type !== 'RUNTIME_PROMPT_COST_OBSERVED')
202
+ continue;
203
+ try {
204
+ const value = JSON.parse(event.payload_json);
205
+ if (value.type === 'KingdomPromptCost/v1')
206
+ latest.set(value.bindingId, value);
207
+ }
208
+ catch { /* Omit corrupt observations rather than inventing measurements. */ }
209
+ }
210
+ return [...latest.values()];
211
+ }
212
+ //# sourceMappingURL=cost.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost.js","sourceRoot":"","sources":["../../src/core/cost.ts"],"names":[],"mappings":"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"}
package/lib/core/db.js CHANGED
@@ -372,7 +372,7 @@ export class KingdomStore {
372
372
  }
373
373
  // ── v0.8(M3-S2 Schema v4 Design v6,Owner 三次 Review APPROVED)─────────
374
374
  //
375
- // 忠实实现 v6(D:\dsh\kingdom\docs\M3-S2-SCHEMA-V4-DESIGN-v6.md + 49/49 验证脚本):
375
+ // 忠实实现 v6(M3-S2 Schema v4 Design v6 + 当时的 49/49 验证脚本):
376
376
  // - 四套独立 Core Ledger:session_territory_affinities / execution_leases /
377
377
  // capability_decisions / dispatch_records;
378
378
  // - executions 重建(v6 §14):建 executions_v4 暂存表(v2 证据列 + 新增
@@ -945,6 +945,23 @@ BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
945
945
  updateTerritorySupervisor(territoryId, supervisorBindingId) {
946
946
  this.db.prepare('UPDATE territories SET supervisor_binding_id = ? WHERE territory_id = ?').run(supervisorBindingId, territoryId);
947
947
  }
948
+ updateTerritoryMetadata(territoryId, name, summary) {
949
+ this.db.prepare('UPDATE territories SET name = ?, summary = ? WHERE territory_id = ?').run(name, summary, territoryId);
950
+ }
951
+ getEventById(eventId) {
952
+ return this.db.prepare('SELECT * FROM events WHERE event_id = ?').get(eventId) ?? null;
953
+ }
954
+ /** Global append cursor; callers predicting a receipt sequence must hold the write transaction. */
955
+ eventSequence() {
956
+ const row = this.db.prepare('SELECT COALESCE(MAX(seq), 0) AS n FROM events').get();
957
+ return row.n;
958
+ }
959
+ /** Owner topology guards include RECOVERING and unknown future nonterminal states. */
960
+ listUnsettledOwnerExecutions(kingdomId) {
961
+ return this.db.prepare(`SELECT e.* FROM executions e JOIN tasks t ON t.task_id = e.task_id
962
+ JOIN territories te ON te.territory_id = t.territory_id WHERE te.kingdom_id = ?
963
+ AND e.state NOT IN ('COMPLETED', 'FAILED', 'ABORTED') ORDER BY e.started_at`).all(kingdomId);
964
+ }
948
965
  // ── task_assignments(v0.7.0 M2-B Assignment Ledger)──────────
949
966
  insertTaskAssignment(row) {
950
967
  this.db
@@ -1083,6 +1100,57 @@ BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
1083
1100
  .prepare('SELECT * FROM events WHERE kingdom_id = ? AND seq > ? ORDER BY seq ASC LIMIT ?')
1084
1101
  .all(kingdomId, afterSeq, limit);
1085
1102
  }
1103
+ /**
1104
+ * Exact Dispatch lookup for one Task attempt.
1105
+ *
1106
+ * Integrity decisions must not scan a bounded event projection: the
1107
+ * dispatch/task/attempt relation is authoritative in dispatch_records.
1108
+ */
1109
+ listDispatchesForTaskAttempt(taskId, attemptNo) {
1110
+ return this.db
1111
+ .prepare(`SELECT * FROM dispatch_records
1112
+ WHERE task_id = ? AND attempt_no = ?
1113
+ ORDER BY created_at ASC`)
1114
+ .all(taskId, attemptNo);
1115
+ }
1116
+ /**
1117
+ * Exact, replay-safe lookup for an open terminal integrity incident.
1118
+ * The SQL predicate narrows by the exact Dispatch target; the bounded JSON
1119
+ * payload is then checked against the exact Task/attempt correlation.
1120
+ */
1121
+ getOpenDispatchTerminalIntegrityIncident(kingdomId, dispatchId, taskId, attemptNo) {
1122
+ // The Dispatch row is authoritative for the Task/attempt relation. Do
1123
+ // not accept an event merely because its target_id happens to match a
1124
+ // caller-supplied string.
1125
+ const dispatch = this.getDispatch(dispatchId);
1126
+ if (!dispatch
1127
+ || dispatch.kingdom_id !== kingdomId
1128
+ || dispatch.task_id !== taskId
1129
+ || dispatch.attempt_no !== attemptNo)
1130
+ return null;
1131
+ const rows = this.db
1132
+ .prepare(`SELECT * FROM events
1133
+ WHERE kingdom_id = ?
1134
+ AND event_type = 'DISPATCH_TERMINAL_INTEGRITY_INCIDENT'
1135
+ AND target_type = 'dispatch'
1136
+ AND target_id = ?
1137
+ ORDER BY seq ASC`)
1138
+ .all(kingdomId, dispatchId);
1139
+ for (const row of rows) {
1140
+ try {
1141
+ const payload = JSON.parse(row.payload_json);
1142
+ if (payload.incident_code === 'DISPATCH_TERMINAL_INTEGRITY_INCIDENT'
1143
+ && payload.state === 'OPEN'
1144
+ && payload.attempt_no === attemptNo) {
1145
+ return row;
1146
+ }
1147
+ }
1148
+ catch {
1149
+ // A malformed incident payload is not trusted as a matching incident.
1150
+ }
1151
+ }
1152
+ return null;
1153
+ }
1086
1154
  /**
1087
1155
  * 王国当前 revision = 最大事件序号。
1088
1156
  *
@@ -1095,6 +1163,73 @@ BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
1095
1163
  .get(kingdomId);
1096
1164
  return row?.n ?? 0;
1097
1165
  }
1166
+ /** Observations and future admission/window policy cannot change an in-flight Runner relation. */
1167
+ runnerContextRevision(kingdomId, scope) {
1168
+ const rows = this.db.prepare(`SELECT * FROM events
1169
+ WHERE kingdom_id = ? AND event_type NOT IN (
1170
+ 'RUNTIME_ROLE_USAGE_OBSERVED', 'RUNTIME_PROMPT_COST_OBSERVED', 'DISPATCH_USAGE_OBSERVED',
1171
+ 'BUDGET_POLICY_UPDATED', 'BUDGET_ADMISSION_RESERVED', 'BUDGET_ADMISSION_BOUND', 'BUDGET_ADMISSION_CANCELLED',
1172
+ 'OWNER_DECISION_CREATED', 'OWNER_DECISION_REVOKED', 'OWNER_DECISION_CONSUMED'
1173
+ ) AND NOT (event_type = 'OWNER_OPERATION_APPLIED' AND COALESCE(
1174
+ CASE WHEN json_valid(payload_json) THEN json_extract(payload_json, '$.action') = 'budget.policy' ELSE 0 END, 0
1175
+ )) ORDER BY seq DESC`).all(kingdomId);
1176
+ if (!scope)
1177
+ return rows[0]?.seq ?? 0;
1178
+ // Only a known event with a provably independent live Core relation can be
1179
+ // ignored. Missing/corrupt targets and future event kinds remain invalidating.
1180
+ const independentTask = (taskId, worker, session) => {
1181
+ if (!taskId || taskId === scope.taskId || worker === scope.workerBindingId || session === scope.sessionRef)
1182
+ return false;
1183
+ const task = this.getTask(taskId), territory = task ? this.getTerritoryById(task.territory_id) : null;
1184
+ if (!task || territory?.kingdom_id !== kingdomId || task.assigned_binding_id === scope.workerBindingId)
1185
+ return false;
1186
+ return !this.listExecutions(taskId).some(row => row.worker_binding_id === scope.workerBindingId || row.session_id === scope.sessionRef)
1187
+ && !this.listTaskAssignments(taskId).some(row => row.worker_binding_id === scope.workerBindingId);
1188
+ };
1189
+ for (const event of rows) {
1190
+ let independent = false;
1191
+ const id = event.target_id;
1192
+ if (id) {
1193
+ if (event.target_type === 'task' && ['TASK_PLANNED', 'TASK_ASSIGNED', 'TASK_ACCEPTED', 'TASK_REWORK_REQUESTED', 'TASK_FAILED',
1194
+ 'TASK_HANDED_OFF', 'WORKER_RESULT_SUBMITTED', 'WORKER_EXECUTION_STARTED', 'WORKER_EXECUTION_FAILED', 'COLLABORATION_CHILD_CREATED'].includes(event.event_type)) {
1195
+ independent = independentTask(id);
1196
+ }
1197
+ else if (event.target_type === 'execution' && ['EXECUTION_GOVERNED_CREATED', 'EXECUTION_RECOVERING', 'SESSION_STARTED',
1198
+ 'SESSION_STOPPED', 'SESSION_FAILED', 'SESSION_PAUSED', 'SESSION_RESUMED'].includes(event.event_type)) {
1199
+ const row = this.getExecution(id);
1200
+ independent = !!row && independentTask(row.task_id, row.worker_binding_id, row.session_id);
1201
+ }
1202
+ else if (event.target_type === 'lease' && ['LEASE_ACQUIRED', 'LEASE_STATE_CHANGED', 'LEASE_RELEASED'].includes(event.event_type)) {
1203
+ const row = this.getLease(id);
1204
+ independent = row?.kingdom_id === kingdomId && independentTask(row.task_id, row.worker_binding_id, row.session_ref);
1205
+ }
1206
+ else if (event.target_type === 'dispatch' && ['DISPATCH_INTENDED', 'DISPATCH_STATE_CHANGED'].includes(event.event_type)) {
1207
+ const row = this.getDispatch(id), lease = row ? this.getLease(row.lease_id) : null;
1208
+ independent = row?.kingdom_id === kingdomId && !!lease && lease.task_id === row.task_id
1209
+ && independentTask(row.task_id, lease.worker_binding_id, row.session_ref);
1210
+ }
1211
+ else if (event.target_type === 'decision' && event.event_type === 'CAPABILITY_DECISION_RECORDED') {
1212
+ const row = this.getCapabilityDecision(id);
1213
+ independent = row?.kingdom_id === kingdomId && independentTask(row.task_id, row.worker_binding_id);
1214
+ }
1215
+ else if (event.target_type === 'affinity' && ['AFFINITY_ESTABLISHED', 'AFFINITY_RETIRED'].includes(event.event_type)) {
1216
+ const row = this.getAffinity(id);
1217
+ independent = row?.kingdom_id === kingdomId && row.worker_binding_id !== scope.workerBindingId && row.session_ref !== scope.sessionRef;
1218
+ }
1219
+ else if (event.target_type === 'workspace-admission' && ['WORKSPACE_ADMISSION_RESERVED', 'WORKSPACE_ADMISSION_BOUND', 'WORKSPACE_ADMISSION_CANCELLED'].includes(event.event_type)) {
1220
+ try {
1221
+ const row = JSON.parse(event.payload_json);
1222
+ independent = row.type === 'KingdomWorkspaceAdmission/v1' && row.admissionId === id
1223
+ && row.kingdomId === kingdomId && independentTask(row.taskId, row.workerBindingId);
1224
+ }
1225
+ catch { /* retain invalidation */ }
1226
+ }
1227
+ }
1228
+ if (!independent)
1229
+ return event.seq;
1230
+ }
1231
+ return 0;
1232
+ }
1098
1233
  /**
1099
1234
  * v0.7.0(M2):外层事务包装——HANDOFF 等**原子治理操作**(多步写 + 事件)整体提交/回滚。
1100
1235
  * appendEvent 的内层 BEGIN 在事务中会抛错,由 appendEvent 的嵌套容忍逻辑接管(见下)。
@@ -1178,12 +1313,21 @@ BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
1178
1313
  .all(...params);
1179
1314
  }
1180
1315
  insertTask(row) {
1316
+ const hasRequirementColumn = this.db
1317
+ .prepare('PRAGMA table_info(tasks)')
1318
+ .all()
1319
+ .some(column => column.name === 'capability_requirement_json');
1320
+ if (!hasRequirementColumn && row.capability_requirement_json != null) {
1321
+ throw new Error('TASK_CAPABILITY_REQUIREMENT_UNAVAILABLE: Schema v4 未迁移,拒绝丢弃 Task requirement');
1322
+ }
1323
+ const columns = hasRequirementColumn ? ', capability_requirement_json' : '';
1324
+ const values = hasRequirementColumn ? ', ?' : '';
1181
1325
  this.db
1182
1326
  .prepare(`INSERT INTO tasks
1183
1327
  (task_id, territory_id, parent_task_id, title, description, assigned_binding_id,
1184
- status, acceptance_criteria, result_summary, created_at, updated_at)
1185
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
1186
- .run(row.task_id, row.territory_id, row.parent_task_id, row.title, row.description, row.assigned_binding_id, row.status, row.acceptance_criteria, row.result_summary, row.created_at, row.updated_at);
1328
+ status, acceptance_criteria, result_summary, created_at, updated_at${columns})
1329
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?${values})`)
1330
+ .run(row.task_id, row.territory_id, row.parent_task_id, row.title, row.description, row.assigned_binding_id, row.status, row.acceptance_criteria, row.result_summary, row.created_at, row.updated_at, ...(hasRequirementColumn ? [row.capability_requirement_json ?? null] : []));
1187
1331
  return row;
1188
1332
  }
1189
1333
  /**
@@ -1224,6 +1368,46 @@ BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
1224
1368
  .all(taskId);
1225
1369
  return rows[0] ?? null;
1226
1370
  }
1371
+ /** Exact task/attempt lookup; unrelated kingdom activity cannot hide the reviewed attempt. */
1372
+ latestTaskReworkEvent(kingdomId, taskId, reviewedAttemptNo) {
1373
+ const rows = this.db.prepare("SELECT * FROM events WHERE kingdom_id = ? AND event_type = 'TASK_REWORK_REQUESTED' AND target_type = 'task' AND target_id = ? ORDER BY seq DESC")
1374
+ .all(kingdomId, taskId);
1375
+ for (const row of rows) {
1376
+ try {
1377
+ if (JSON.parse(row.payload_json).reviewed_attempt_no === reviewedAttemptNo)
1378
+ return row;
1379
+ }
1380
+ catch { /* Malformed historical evidence cannot establish a review reference. */ }
1381
+ }
1382
+ return null;
1383
+ }
1384
+ listDispatchUsageEvents(dispatchId) {
1385
+ return this.db.prepare("SELECT * FROM events WHERE event_type = 'DISPATCH_USAGE_OBSERVED' AND target_type = 'dispatch' AND target_id = ? ORDER BY seq")
1386
+ .all(dispatchId);
1387
+ }
1388
+ /** Complete exact budget ledger; display event windows must never be used as accounting history. */
1389
+ listBudgetEvents(kingdomId) {
1390
+ return this.db.prepare(`SELECT * FROM events WHERE kingdom_id = ? AND event_type IN
1391
+ ('BUDGET_POLICY_UPDATED', 'BUDGET_ADMISSION_RESERVED', 'BUDGET_ADMISSION_BOUND', 'BUDGET_ADMISSION_CANCELLED', 'DISPATCH_INTENDED')
1392
+ ORDER BY seq ASC`).all(kingdomId);
1393
+ }
1394
+ listWorkspaceAdmissionEvents(kingdomId) {
1395
+ return this.db.prepare(`SELECT * FROM events WHERE kingdom_id = ? AND event_type IN
1396
+ ('WORKSPACE_ADMISSION_RESERVED', 'WORKSPACE_ADMISSION_BOUND', 'WORKSPACE_ADMISSION_CANCELLED')
1397
+ ORDER BY seq ASC`).all(kingdomId);
1398
+ }
1399
+ listRuntimeCostEvents(kingdomId) {
1400
+ return this.db.prepare(`SELECT * FROM events WHERE kingdom_id = ? AND event_type IN
1401
+ ('RUNTIME_ROLE_USAGE_OBSERVED', 'RUNTIME_PROMPT_COST_OBSERVED') ORDER BY seq ASC`).all(kingdomId);
1402
+ }
1403
+ listActorEventsSince(kingdomId, actorId, afterSeq) {
1404
+ return this.db.prepare('SELECT * FROM events WHERE kingdom_id = ? AND actor_id = ? AND seq > ? ORDER BY seq ASC')
1405
+ .all(kingdomId, actorId, afterSeq);
1406
+ }
1407
+ getLatestRuntimeRoleUsageEvent(kingdomId, sourceUnitRef) {
1408
+ return this.db.prepare("SELECT * FROM events WHERE kingdom_id = ? AND event_type = 'RUNTIME_ROLE_USAGE_OBSERVED' AND target_id = ? ORDER BY seq DESC LIMIT 1")
1409
+ .get(kingdomId, sourceUnitRef) ?? null;
1410
+ }
1227
1411
  /** 已落库的最大 attempt_no;无结果时为 0。下一次尝试 = 本值 + 1。 */
1228
1412
  maxAttemptNo(taskId) {
1229
1413
  const row = this.db
@@ -1546,12 +1730,21 @@ BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
1546
1730
  }
1547
1731
  // tasks.capability_requirement_json / kingdoms.capability_ceiling_json(v6 增量)────
1548
1732
  getTaskCapabilityRequirement(taskId) {
1733
+ if (!this.getTaskCapabilityRequirementColumn())
1734
+ return null;
1549
1735
  const row = this.db.prepare('SELECT capability_requirement_json FROM tasks WHERE task_id = ?').get(taskId);
1550
1736
  return row?.capability_requirement_json ?? null;
1551
1737
  }
1552
1738
  setTaskCapabilityRequirement(taskId, json) {
1739
+ if (!this.getTaskCapabilityRequirementColumn()) {
1740
+ throw new Error('TASK_CAPABILITY_REQUIREMENT_UNAVAILABLE: Schema v4 未迁移');
1741
+ }
1553
1742
  this.db.prepare('UPDATE tasks SET capability_requirement_json = ? WHERE task_id = ?').run(json, taskId);
1554
1743
  }
1744
+ getTaskCapabilityRequirementColumn() {
1745
+ return this.db.prepare('PRAGMA table_info(tasks)').all()
1746
+ .some(column => column.name === 'capability_requirement_json');
1747
+ }
1555
1748
  getKingdomCapabilityCeiling(kingdomId) {
1556
1749
  const row = this.db.prepare('SELECT capability_ceiling_json FROM kingdoms WHERE kingdom_id = ?').get(kingdomId);
1557
1750
  return row?.capability_ceiling_json ?? null;