owlrunkit 0.19.2 → 0.20.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.
- package/CHANGELOG.md +15 -0
- package/README.md +38 -5
- package/docs/architecture/OWLCODA_RUNKIT_020_TEAM_DELIVERY_PHASE1_PRODUCT_DECISION_20260813.md +296 -0
- package/integrations/codex/skills/owlcoda-runkit/SKILL.md +28 -6
- package/integrations/codex/skills/owlcoda-runkit/assets/templates/config.json +3 -3
- package/package.json +1 -1
- package/packages/attest/distribution-manifest-v1.json +5 -0
- package/packages/attest/src/quick.mjs +5 -0
- package/registry-release-policy-v1.json +5 -5
- package/sbom.spdx.json +4 -4
- package/scripts/runkit-contract/core-contract.mjs +8 -1
- package/scripts/runkit-contract/formal-workflow.mjs +1 -1
- package/scripts/runkit-contract/project-cli-resolver.mjs +4 -1
- package/scripts/runkit-contract/runkit-cli.mjs +80 -3
- package/scripts/runkit-contract/schemas/candidate-transfer-packet-v1.schema.json +98 -0
- package/scripts/runkit-contract/schemas/team-acceptance-packet-v2.schema.json +109 -0
- package/scripts/runkit-contract/schemas/team-delivery-status-v1.schema.json +72 -0
- package/scripts/runkit-contract/schemas/team-packet-validation-v1.schema.json +33 -0
- package/scripts/runkit-contract/schemas/team-recommendation-v1.schema.json +121 -0
- package/scripts/runkit-contract/schemas/team-task-packet-v2.schema.json +228 -0
- package/scripts/runkit-contract/team-delivery.mjs +906 -0
|
@@ -0,0 +1,906 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
decodeUtf8Strict,
|
|
6
|
+
readFileBytesBounded,
|
|
7
|
+
} from "../../packages/attest/src/formal.mjs";
|
|
8
|
+
import { parseJsonStrict } from "./quick-canonical.mjs";
|
|
9
|
+
import {
|
|
10
|
+
normalizeTeamProjectDefinitionV1,
|
|
11
|
+
readTeamProjectStatusV3,
|
|
12
|
+
teamProjectDefinitionBindingV1,
|
|
13
|
+
} from "./team-project.mjs";
|
|
14
|
+
|
|
15
|
+
const AUTHORITY_BOUNDARY = Object.freeze({
|
|
16
|
+
agentDispatch: false,
|
|
17
|
+
git: false,
|
|
18
|
+
release: false,
|
|
19
|
+
deployment: false,
|
|
20
|
+
production: false,
|
|
21
|
+
business: false,
|
|
22
|
+
automation: false,
|
|
23
|
+
money: false,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const ACCEPTANCE_LEVELS = new Set(["L0", "L1", "L2", "L3"]);
|
|
27
|
+
const SECOND_ORDER_RISKS = new Set(["low", "medium", "high"]);
|
|
28
|
+
const JUDGMENT_LEVELS = new Set(["low", "medium", "high"]);
|
|
29
|
+
const CONTEXT_DEPTHS = new Set(["local", "cross-module", "product-wide"]);
|
|
30
|
+
const SURFACE_WIDTHS = new Set(["narrow", "multi-module", "product-wide"]);
|
|
31
|
+
const DETERMINISM_LEVELS = new Set(["deterministic", "mixed", "exploratory"]);
|
|
32
|
+
const AUTHORITY_SPANS = new Set(["source-only", "integration", "runtime", "production"]);
|
|
33
|
+
const WORKTREE_MODES = new Set(["new_clean_worktree", "existing_dirty_candidate"]);
|
|
34
|
+
const ACCEPTANCE_VERDICTS = new Set(["ACCEPT", "REWORK", "BLOCKED"]);
|
|
35
|
+
const INDEPENDENCE_STATUSES = new Set([
|
|
36
|
+
"independent",
|
|
37
|
+
"same_family_not_independent",
|
|
38
|
+
"control_tower",
|
|
39
|
+
]);
|
|
40
|
+
const TRANSFER_LIFECYCLES = new Set([
|
|
41
|
+
"candidate_active",
|
|
42
|
+
"transfer_requested",
|
|
43
|
+
"packet_generated",
|
|
44
|
+
"new_owner_validation",
|
|
45
|
+
"handoff_ack",
|
|
46
|
+
"old_writer_release",
|
|
47
|
+
]);
|
|
48
|
+
const TRANSFER_VERIFICATION_STATUSES = new Set([
|
|
49
|
+
"source_candidate_unverified",
|
|
50
|
+
"source_candidate_verified",
|
|
51
|
+
"accepted",
|
|
52
|
+
"rework_required",
|
|
53
|
+
]);
|
|
54
|
+
const PACKET_KINDS = new Map([
|
|
55
|
+
["OwlCodaRunKitTeamTaskPacketV2", "task"],
|
|
56
|
+
["OwlCodaRunKitTeamAcceptancePacketV2", "acceptance"],
|
|
57
|
+
["OwlCodaRunKitCandidateTransferPacketV1", "transfer"],
|
|
58
|
+
]);
|
|
59
|
+
|
|
60
|
+
function isRecord(value) {
|
|
61
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function exactKeys(value, keys) {
|
|
65
|
+
return isRecord(value)
|
|
66
|
+
&& Object.keys(value).sort().join("\0") === [...keys].sort().join("\0");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function nonEmptyString(value) {
|
|
70
|
+
return typeof value === "string" && value.length > 0;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function nullableString(value) {
|
|
74
|
+
return value === null || nonEmptyString(value);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function id(value) {
|
|
78
|
+
return nonEmptyString(value) && /^[A-Za-z0-9][A-Za-z0-9._:-]*$/u.test(value);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function sha256Ref(value) {
|
|
82
|
+
return typeof value === "string" && /^sha256:[a-f0-9]{64}$/u.test(value);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function artifactSha256Ref(value) {
|
|
86
|
+
return typeof value === "string" && /^artifact:sha256:[a-f0-9]{64}$/u.test(value);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function gitRef(value) {
|
|
90
|
+
return typeof value === "string" && /^git:[a-f0-9]{40}(?:[a-f0-9]{24})?$/u.test(value);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function projectTruthHash(value) {
|
|
94
|
+
return typeof value === "string" && /^[a-f0-9]{64}$/u.test(value);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function absolutePath(value) {
|
|
98
|
+
return nonEmptyString(value)
|
|
99
|
+
&& (path.isAbsolute(value) || path.win32.isAbsolute(value));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function stringArray(value, { allowEmpty = true } = {}) {
|
|
103
|
+
return Array.isArray(value)
|
|
104
|
+
&& (allowEmpty || value.length > 0)
|
|
105
|
+
&& value.every(nonEmptyString)
|
|
106
|
+
&& new Set(value).size === value.length;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function nonnegativeInteger(value) {
|
|
110
|
+
return Number.isSafeInteger(value) && value >= 0;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function nullableIsoUtc(value) {
|
|
114
|
+
return value === null || (
|
|
115
|
+
typeof value === "string"
|
|
116
|
+
&& /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/u.test(value)
|
|
117
|
+
&& !Number.isNaN(Date.parse(value))
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function sameStringSet(left, right) {
|
|
122
|
+
return stringArray(left)
|
|
123
|
+
&& stringArray(right)
|
|
124
|
+
&& left.length === right.length
|
|
125
|
+
&& [...left].sort().every((value, index) => value === [...right].sort()[index]);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function validAuthorityBoundary(value) {
|
|
129
|
+
return exactKeys(value, Object.keys(AUTHORITY_BOUNDARY))
|
|
130
|
+
&& Object.entries(AUTHORITY_BOUNDARY).every(([key, expected]) => value[key] === expected);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function commonPacketContractValid(packet, expectedKeys) {
|
|
134
|
+
return exactKeys(packet, expectedKeys)
|
|
135
|
+
&& validAuthorityBoundary(packet.authorityBoundary)
|
|
136
|
+
&& packet.authorizationGranted === false;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function projectBindingValid(value) {
|
|
140
|
+
return exactKeys(value, ["projectId", "projectTruthHash"])
|
|
141
|
+
&& id(value.projectId)
|
|
142
|
+
&& projectTruthHash(value.projectTruthHash);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function actorValid(value) {
|
|
146
|
+
return exactKeys(value, ["executingAgent", "modelFamily", "modelVersion", "role"])
|
|
147
|
+
&& id(value.executingAgent)
|
|
148
|
+
&& nonEmptyString(value.modelFamily)
|
|
149
|
+
&& nonEmptyString(value.modelVersion)
|
|
150
|
+
&& nonEmptyString(value.role);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function modelIdentityValid(value) {
|
|
154
|
+
return exactKeys(value, ["agent", "modelFamily", "modelVersion"])
|
|
155
|
+
&& id(value.agent)
|
|
156
|
+
&& nonEmptyString(value.modelFamily)
|
|
157
|
+
&& nonEmptyString(value.modelVersion);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function taskPacketContractValid(packet) {
|
|
161
|
+
return commonPacketContractValid(packet, [
|
|
162
|
+
"schemaVersion",
|
|
163
|
+
"packetId",
|
|
164
|
+
"projectBinding",
|
|
165
|
+
"gateId",
|
|
166
|
+
"observableSuccess",
|
|
167
|
+
"workItem",
|
|
168
|
+
"actor",
|
|
169
|
+
"risk",
|
|
170
|
+
"acceptance",
|
|
171
|
+
"entry",
|
|
172
|
+
"scope",
|
|
173
|
+
"evidence",
|
|
174
|
+
"verificationCadence",
|
|
175
|
+
"handoff",
|
|
176
|
+
"escalationBudget",
|
|
177
|
+
"stop",
|
|
178
|
+
"authorityBoundary",
|
|
179
|
+
"authorizationGranted",
|
|
180
|
+
])
|
|
181
|
+
&& packet.schemaVersion === "OwlCodaRunKitTeamTaskPacketV2"
|
|
182
|
+
&& id(packet.packetId)
|
|
183
|
+
&& projectBindingValid(packet.projectBinding)
|
|
184
|
+
&& id(packet.gateId)
|
|
185
|
+
&& nonEmptyString(packet.observableSuccess)
|
|
186
|
+
&& exactKeys(packet.workItem, ["workItemId", "title", "dependencies", "ownedPaths"])
|
|
187
|
+
&& id(packet.workItem.workItemId)
|
|
188
|
+
&& nonEmptyString(packet.workItem.title)
|
|
189
|
+
&& stringArray(packet.workItem.dependencies)
|
|
190
|
+
&& stringArray(packet.workItem.ownedPaths, { allowEmpty: false })
|
|
191
|
+
&& actorValid(packet.actor)
|
|
192
|
+
&& exactKeys(packet.risk, [
|
|
193
|
+
"productJudgment",
|
|
194
|
+
"semanticAmbiguity",
|
|
195
|
+
"contextDepth",
|
|
196
|
+
"surfaceWidth",
|
|
197
|
+
"determinism",
|
|
198
|
+
"secondOrderRisk",
|
|
199
|
+
"authoritySpan",
|
|
200
|
+
])
|
|
201
|
+
&& JUDGMENT_LEVELS.has(packet.risk.productJudgment)
|
|
202
|
+
&& JUDGMENT_LEVELS.has(packet.risk.semanticAmbiguity)
|
|
203
|
+
&& CONTEXT_DEPTHS.has(packet.risk.contextDepth)
|
|
204
|
+
&& SURFACE_WIDTHS.has(packet.risk.surfaceWidth)
|
|
205
|
+
&& DETERMINISM_LEVELS.has(packet.risk.determinism)
|
|
206
|
+
&& SECOND_ORDER_RISKS.has(packet.risk.secondOrderRisk)
|
|
207
|
+
&& AUTHORITY_SPANS.has(packet.risk.authoritySpan)
|
|
208
|
+
&& exactKeys(packet.acceptance, [
|
|
209
|
+
"requiredLevel",
|
|
210
|
+
"implementationModelFamily",
|
|
211
|
+
"implementationModelVersion",
|
|
212
|
+
"verificationModelFamily",
|
|
213
|
+
"verificationModelVersion",
|
|
214
|
+
"sameFamilyAllowed",
|
|
215
|
+
"freshAdversarialFamilies",
|
|
216
|
+
])
|
|
217
|
+
&& ACCEPTANCE_LEVELS.has(packet.acceptance.requiredLevel)
|
|
218
|
+
&& nonEmptyString(packet.acceptance.implementationModelFamily)
|
|
219
|
+
&& nonEmptyString(packet.acceptance.implementationModelVersion)
|
|
220
|
+
&& nonEmptyString(packet.acceptance.verificationModelFamily)
|
|
221
|
+
&& nonEmptyString(packet.acceptance.verificationModelVersion)
|
|
222
|
+
&& typeof packet.acceptance.sameFamilyAllowed === "boolean"
|
|
223
|
+
&& stringArray(packet.acceptance.freshAdversarialFamilies)
|
|
224
|
+
&& exactKeys(packet.entry, [
|
|
225
|
+
"worktreeMode",
|
|
226
|
+
"worktree",
|
|
227
|
+
"branch",
|
|
228
|
+
"baseSha",
|
|
229
|
+
"candidateIdentity",
|
|
230
|
+
"dirtyStateManifest",
|
|
231
|
+
"soleWriter",
|
|
232
|
+
"upstreamAcceptedPackets",
|
|
233
|
+
])
|
|
234
|
+
&& WORKTREE_MODES.has(packet.entry.worktreeMode)
|
|
235
|
+
&& absolutePath(packet.entry.worktree)
|
|
236
|
+
&& nonEmptyString(packet.entry.branch)
|
|
237
|
+
&& gitRef(packet.entry.baseSha)
|
|
238
|
+
&& sha256Ref(packet.entry.candidateIdentity)
|
|
239
|
+
&& sha256Ref(packet.entry.dirtyStateManifest)
|
|
240
|
+
&& id(packet.entry.soleWriter)
|
|
241
|
+
&& stringArray(packet.entry.upstreamAcceptedPackets)
|
|
242
|
+
&& exactKeys(packet.scope, [
|
|
243
|
+
"allowedChangedPaths",
|
|
244
|
+
"prohibitedPathsAndActions",
|
|
245
|
+
"protectedArtifactsAndAuthority",
|
|
246
|
+
])
|
|
247
|
+
&& stringArray(packet.scope.allowedChangedPaths, { allowEmpty: false })
|
|
248
|
+
&& stringArray(packet.scope.prohibitedPathsAndActions)
|
|
249
|
+
&& stringArray(packet.scope.protectedArtifactsAndAuthority)
|
|
250
|
+
&& exactKeys(packet.evidence, [
|
|
251
|
+
"positiveEvidence",
|
|
252
|
+
"negativeAndSecondOrderTests",
|
|
253
|
+
"deliveryPacketFields",
|
|
254
|
+
])
|
|
255
|
+
&& stringArray(packet.evidence.positiveEvidence)
|
|
256
|
+
&& stringArray(packet.evidence.negativeAndSecondOrderTests)
|
|
257
|
+
&& stringArray(packet.evidence.deliveryPacketFields)
|
|
258
|
+
&& exactKeys(packet.verificationCadence, [
|
|
259
|
+
"microBatchId",
|
|
260
|
+
"closureHypothesis",
|
|
261
|
+
"includedChanges",
|
|
262
|
+
"implementationSmoke",
|
|
263
|
+
"frozenCandidateFocusedGate",
|
|
264
|
+
"candidateCloseoutChecks",
|
|
265
|
+
"independentAdversarialDelta",
|
|
266
|
+
"deferredTransitionGates",
|
|
267
|
+
"trustedReceipts",
|
|
268
|
+
"receiptInvalidationTriggers",
|
|
269
|
+
])
|
|
270
|
+
&& id(packet.verificationCadence.microBatchId)
|
|
271
|
+
&& nonEmptyString(packet.verificationCadence.closureHypothesis)
|
|
272
|
+
&& stringArray(packet.verificationCadence.includedChanges)
|
|
273
|
+
&& stringArray(packet.verificationCadence.implementationSmoke)
|
|
274
|
+
&& stringArray(packet.verificationCadence.frozenCandidateFocusedGate)
|
|
275
|
+
&& stringArray(packet.verificationCadence.candidateCloseoutChecks)
|
|
276
|
+
&& stringArray(packet.verificationCadence.independentAdversarialDelta)
|
|
277
|
+
&& stringArray(packet.verificationCadence.deferredTransitionGates)
|
|
278
|
+
&& stringArray(packet.verificationCadence.trustedReceipts)
|
|
279
|
+
&& stringArray(packet.verificationCadence.receiptInvalidationTriggers)
|
|
280
|
+
&& exactKeys(packet.handoff, ["required", "nextOwner"])
|
|
281
|
+
&& typeof packet.handoff.required === "boolean"
|
|
282
|
+
&& nullableString(packet.handoff.nextOwner)
|
|
283
|
+
&& (!packet.handoff.required || id(packet.handoff.nextOwner))
|
|
284
|
+
&& exactKeys(packet.escalationBudget, [
|
|
285
|
+
"implementationAttempts",
|
|
286
|
+
"narrowRework",
|
|
287
|
+
"harnessFailure",
|
|
288
|
+
"controllerIntervention",
|
|
289
|
+
"semanticEscape",
|
|
290
|
+
])
|
|
291
|
+
&& nonnegativeInteger(packet.escalationBudget.implementationAttempts)
|
|
292
|
+
&& packet.escalationBudget.implementationAttempts > 0
|
|
293
|
+
&& nonnegativeInteger(packet.escalationBudget.narrowRework)
|
|
294
|
+
&& nonnegativeInteger(packet.escalationBudget.harnessFailure)
|
|
295
|
+
&& nonnegativeInteger(packet.escalationBudget.controllerIntervention)
|
|
296
|
+
&& packet.escalationBudget.semanticEscape === 0
|
|
297
|
+
&& exactKeys(packet.stop, ["exactStopPoint", "nextGateProhibited"])
|
|
298
|
+
&& nonEmptyString(packet.stop.exactStopPoint)
|
|
299
|
+
&& nullableString(packet.stop.nextGateProhibited);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function findingValid(value) {
|
|
303
|
+
return exactKeys(value, ["severity", "code", "message", "evidenceRefs"])
|
|
304
|
+
&& new Set(["critical", "important", "minor", "note"]).has(value.severity)
|
|
305
|
+
&& id(value.code)
|
|
306
|
+
&& nonEmptyString(value.message)
|
|
307
|
+
&& stringArray(value.evidenceRefs);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function acceptancePacketContractValid(packet) {
|
|
311
|
+
return commonPacketContractValid(packet, [
|
|
312
|
+
"schemaVersion",
|
|
313
|
+
"packetId",
|
|
314
|
+
"projectBinding",
|
|
315
|
+
"gateId",
|
|
316
|
+
"workItemId",
|
|
317
|
+
"candidateId",
|
|
318
|
+
"taskPacketSha256",
|
|
319
|
+
"implementation",
|
|
320
|
+
"verification",
|
|
321
|
+
"secondOrderRisk",
|
|
322
|
+
"independenceStatus",
|
|
323
|
+
"acceptanceLevel",
|
|
324
|
+
"candidateIdentityBefore",
|
|
325
|
+
"candidateIdentityAfter",
|
|
326
|
+
"freshAdversarialFamilies",
|
|
327
|
+
"coverageLedger",
|
|
328
|
+
"protectedArtifactReadback",
|
|
329
|
+
"productionWriteCount",
|
|
330
|
+
"findings",
|
|
331
|
+
"verdict",
|
|
332
|
+
"allowedNextGate",
|
|
333
|
+
"remainingAcceptanceLevels",
|
|
334
|
+
"authorityBoundary",
|
|
335
|
+
"authorizationGranted",
|
|
336
|
+
])
|
|
337
|
+
&& packet.schemaVersion === "OwlCodaRunKitTeamAcceptancePacketV2"
|
|
338
|
+
&& id(packet.packetId)
|
|
339
|
+
&& projectBindingValid(packet.projectBinding)
|
|
340
|
+
&& id(packet.gateId)
|
|
341
|
+
&& id(packet.workItemId)
|
|
342
|
+
&& id(packet.candidateId)
|
|
343
|
+
&& sha256Ref(packet.taskPacketSha256)
|
|
344
|
+
&& modelIdentityValid(packet.implementation)
|
|
345
|
+
&& modelIdentityValid(packet.verification)
|
|
346
|
+
&& SECOND_ORDER_RISKS.has(packet.secondOrderRisk)
|
|
347
|
+
&& INDEPENDENCE_STATUSES.has(packet.independenceStatus)
|
|
348
|
+
&& ACCEPTANCE_LEVELS.has(packet.acceptanceLevel)
|
|
349
|
+
&& sha256Ref(packet.candidateIdentityBefore)
|
|
350
|
+
&& sha256Ref(packet.candidateIdentityAfter)
|
|
351
|
+
&& stringArray(packet.freshAdversarialFamilies)
|
|
352
|
+
&& exactKeys(packet.coverageLedger, [
|
|
353
|
+
"evidenceReused",
|
|
354
|
+
"checksRunFresh",
|
|
355
|
+
"coveredChecksNotRepeated",
|
|
356
|
+
"receiptInvalidations",
|
|
357
|
+
"deferredTransitionGates",
|
|
358
|
+
])
|
|
359
|
+
&& stringArray(packet.coverageLedger.evidenceReused)
|
|
360
|
+
&& stringArray(packet.coverageLedger.checksRunFresh)
|
|
361
|
+
&& stringArray(packet.coverageLedger.coveredChecksNotRepeated)
|
|
362
|
+
&& stringArray(packet.coverageLedger.receiptInvalidations)
|
|
363
|
+
&& stringArray(packet.coverageLedger.deferredTransitionGates)
|
|
364
|
+
&& stringArray(packet.protectedArtifactReadback)
|
|
365
|
+
&& nonnegativeInteger(packet.productionWriteCount)
|
|
366
|
+
&& Array.isArray(packet.findings)
|
|
367
|
+
&& packet.findings.every(findingValid)
|
|
368
|
+
&& ACCEPTANCE_VERDICTS.has(packet.verdict)
|
|
369
|
+
&& nullableString(packet.allowedNextGate)
|
|
370
|
+
&& stringArray(packet.remainingAcceptanceLevels)
|
|
371
|
+
&& packet.remainingAcceptanceLevels.every(level => ACCEPTANCE_LEVELS.has(level));
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function handoffAckValid(value) {
|
|
375
|
+
return exactKeys(value, ["status", "agent", "occurredAt", "evidenceRefs"])
|
|
376
|
+
&& new Set(["pending", "accepted", "rejected"]).has(value.status)
|
|
377
|
+
&& (value.agent === null || id(value.agent))
|
|
378
|
+
&& nullableIsoUtc(value.occurredAt)
|
|
379
|
+
&& stringArray(value.evidenceRefs)
|
|
380
|
+
&& (value.status === "pending"
|
|
381
|
+
? value.agent === null && value.occurredAt === null && value.evidenceRefs.length === 0
|
|
382
|
+
: value.agent !== null && value.occurredAt !== null);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function transferPacketContractValid(packet) {
|
|
386
|
+
return commonPacketContractValid(packet, [
|
|
387
|
+
"schemaVersion",
|
|
388
|
+
"packetId",
|
|
389
|
+
"projectBinding",
|
|
390
|
+
"gateId",
|
|
391
|
+
"workItemId",
|
|
392
|
+
"candidateId",
|
|
393
|
+
"candidateSha256",
|
|
394
|
+
"baseSha",
|
|
395
|
+
"head",
|
|
396
|
+
"branch",
|
|
397
|
+
"worktree",
|
|
398
|
+
"dirtyManifestSha256",
|
|
399
|
+
"patchBundleRef",
|
|
400
|
+
"snapshotRef",
|
|
401
|
+
"reconstructionRefs",
|
|
402
|
+
"protectedArtifacts",
|
|
403
|
+
"previousOwner",
|
|
404
|
+
"nextOwner",
|
|
405
|
+
"lifecycle",
|
|
406
|
+
"handoffAck",
|
|
407
|
+
"verificationStatus",
|
|
408
|
+
"authorityBoundary",
|
|
409
|
+
"authorizationGranted",
|
|
410
|
+
])
|
|
411
|
+
&& packet.schemaVersion === "OwlCodaRunKitCandidateTransferPacketV1"
|
|
412
|
+
&& id(packet.packetId)
|
|
413
|
+
&& projectBindingValid(packet.projectBinding)
|
|
414
|
+
&& id(packet.gateId)
|
|
415
|
+
&& id(packet.workItemId)
|
|
416
|
+
&& id(packet.candidateId)
|
|
417
|
+
&& sha256Ref(packet.candidateSha256)
|
|
418
|
+
&& gitRef(packet.baseSha)
|
|
419
|
+
&& gitRef(packet.head)
|
|
420
|
+
&& nonEmptyString(packet.branch)
|
|
421
|
+
&& absolutePath(packet.worktree)
|
|
422
|
+
&& sha256Ref(packet.dirtyManifestSha256)
|
|
423
|
+
&& (packet.patchBundleRef === null || artifactSha256Ref(packet.patchBundleRef))
|
|
424
|
+
&& artifactSha256Ref(packet.snapshotRef)
|
|
425
|
+
&& stringArray(packet.reconstructionRefs, { allowEmpty: false })
|
|
426
|
+
&& stringArray(packet.protectedArtifacts)
|
|
427
|
+
&& id(packet.previousOwner)
|
|
428
|
+
&& id(packet.nextOwner)
|
|
429
|
+
&& packet.previousOwner !== packet.nextOwner
|
|
430
|
+
&& TRANSFER_LIFECYCLES.has(packet.lifecycle)
|
|
431
|
+
&& handoffAckValid(packet.handoffAck)
|
|
432
|
+
&& TRANSFER_VERIFICATION_STATUSES.has(packet.verificationStatus);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
function pathPrefix(value) {
|
|
436
|
+
return value.endsWith("/**") ? value.slice(0, -3) : null;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
function pathCovers(owner, candidate) {
|
|
440
|
+
if (owner === candidate) return true;
|
|
441
|
+
const prefix = pathPrefix(owner);
|
|
442
|
+
if (prefix === null) return false;
|
|
443
|
+
const candidatePrefix = pathPrefix(candidate) ?? candidate;
|
|
444
|
+
return candidatePrefix === prefix || candidatePrefix.startsWith(`${prefix}/`);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
function conflictsBetween(left, right) {
|
|
448
|
+
const conflicts = [];
|
|
449
|
+
for (const leftPath of left.ownedPaths) {
|
|
450
|
+
for (const rightPath of right.ownedPaths) {
|
|
451
|
+
if (pathCovers(leftPath, rightPath) || pathCovers(rightPath, leftPath)) {
|
|
452
|
+
conflicts.push({
|
|
453
|
+
leftWorkItemId: left.workItemId,
|
|
454
|
+
leftPath,
|
|
455
|
+
rightWorkItemId: right.workItemId,
|
|
456
|
+
rightPath,
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
return conflicts;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
function projectDefinitionPath(root) {
|
|
465
|
+
return path.join(path.resolve(root), ".owlcoda/runkit/project/definition.json");
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
function currentProjectStatus(workspaceRoot) {
|
|
469
|
+
if (!existsSync(projectDefinitionPath(workspaceRoot))) return null;
|
|
470
|
+
return readTeamProjectStatusV3({ workspaceRoot });
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
function readProjectDefinition(workspaceRoot) {
|
|
474
|
+
const { bytes } = readFileBytesBounded(projectDefinitionPath(workspaceRoot));
|
|
475
|
+
return normalizeTeamProjectDefinitionV1(parseJsonStrict(decodeUtf8Strict(bytes)));
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
function laneProjection(project) {
|
|
479
|
+
if (project === null) return [];
|
|
480
|
+
const ready = new Set(project.readyQueue);
|
|
481
|
+
return project.workItems
|
|
482
|
+
.filter(workItem => workItem.status !== "completed")
|
|
483
|
+
.map(workItem => {
|
|
484
|
+
const actionable = ready.has(workItem.workItemId)
|
|
485
|
+
|| new Set([
|
|
486
|
+
"active",
|
|
487
|
+
"waiting_decision",
|
|
488
|
+
"verifying",
|
|
489
|
+
"ready_to_integrate",
|
|
490
|
+
"failed",
|
|
491
|
+
]).has(workItem.status);
|
|
492
|
+
const coordinationFacts = [
|
|
493
|
+
...(workItem.pendingHandoff ? ["pending_handoff"] : []),
|
|
494
|
+
...(workItem.rework ? ["rework_active"] : []),
|
|
495
|
+
...(workItem.latestSourceDelivery ? ["source_delivery_present"] : []),
|
|
496
|
+
...(workItem.status === "verifying" ? ["independent_verification"] : []),
|
|
497
|
+
];
|
|
498
|
+
return {
|
|
499
|
+
workItemId: workItem.workItemId,
|
|
500
|
+
title: workItem.title,
|
|
501
|
+
status: workItem.status,
|
|
502
|
+
agentId: workItem.agentId,
|
|
503
|
+
dependencies: [...workItem.dependencies],
|
|
504
|
+
unresolvedDependencies: [...workItem.unresolvedDependencies],
|
|
505
|
+
ownedPaths: [...workItem.ownedPaths],
|
|
506
|
+
actionable,
|
|
507
|
+
parallelEligible: false,
|
|
508
|
+
coordinationFacts,
|
|
509
|
+
};
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
function deriveProjection(project) {
|
|
514
|
+
const lanes = laneProjection(project);
|
|
515
|
+
const actionable = lanes.filter(lane => lane.actionable);
|
|
516
|
+
const pathConflicts = [];
|
|
517
|
+
for (let left = 0; left < actionable.length; left += 1) {
|
|
518
|
+
for (let right = left + 1; right < actionable.length; right += 1) {
|
|
519
|
+
pathConflicts.push(...conflictsBetween(actionable[left], actionable[right]));
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
const conflicted = new Set(pathConflicts.flatMap(conflict => [
|
|
523
|
+
conflict.leftWorkItemId,
|
|
524
|
+
conflict.rightWorkItemId,
|
|
525
|
+
]));
|
|
526
|
+
for (const lane of lanes) {
|
|
527
|
+
lane.parallelEligible = actionable.length > 1
|
|
528
|
+
&& lane.actionable
|
|
529
|
+
&& !conflicted.has(lane.workItemId);
|
|
530
|
+
}
|
|
531
|
+
const acceptanceGaps = lanes
|
|
532
|
+
.filter(lane => lane.status === "verifying")
|
|
533
|
+
.map(lane => ({
|
|
534
|
+
workItemId: lane.workItemId,
|
|
535
|
+
code: "verification_model_family_unbound",
|
|
536
|
+
message: "Project Driver requires a different verifier Agent; model-family independence remains packet-bound.",
|
|
537
|
+
}));
|
|
538
|
+
const ownerTransitions = lanes
|
|
539
|
+
.filter(lane => lane.coordinationFacts.length > 0)
|
|
540
|
+
.map(lane => ({
|
|
541
|
+
workItemId: lane.workItemId,
|
|
542
|
+
facts: [...lane.coordinationFacts],
|
|
543
|
+
}));
|
|
544
|
+
return { lanes, actionable, pathConflicts, acceptanceGaps, ownerTransitions };
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
function uniqueSorted(values) {
|
|
548
|
+
return [...new Set(values)].sort();
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
function shellQuote(value) {
|
|
552
|
+
return `'${String(value).replaceAll("'", `'"'"'`)}'`;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
function recommendationFromProject(project, workspaceRoot) {
|
|
556
|
+
const projection = deriveProjection(project);
|
|
557
|
+
const activeOwners = uniqueSorted(projection.actionable
|
|
558
|
+
.map(lane => lane.agentId)
|
|
559
|
+
.filter(value => value !== null));
|
|
560
|
+
const reasonCodes = [];
|
|
561
|
+
if (project === null) {
|
|
562
|
+
reasonCodes.push("project_driver_not_initialized");
|
|
563
|
+
} else if (projection.actionable.length === 0) {
|
|
564
|
+
reasonCodes.push("no_actionable_work_items");
|
|
565
|
+
} else if (projection.actionable.length === 1) {
|
|
566
|
+
reasonCodes.push("single_actionable_work_item");
|
|
567
|
+
}
|
|
568
|
+
if (projection.pathConflicts.length > 0) {
|
|
569
|
+
reasonCodes.push("owned_path_conflict_requires_coordination");
|
|
570
|
+
} else if (projection.actionable.length > 1) {
|
|
571
|
+
reasonCodes.push("multiple_independent_actionable_work_items");
|
|
572
|
+
}
|
|
573
|
+
if (activeOwners.length > 1) reasonCodes.push("multiple_active_owners");
|
|
574
|
+
if (projection.acceptanceGaps.length > 0) reasonCodes.push("independent_acceptance_lane");
|
|
575
|
+
if (projection.ownerTransitions.length > 0) reasonCodes.push("candidate_owner_transition");
|
|
576
|
+
|
|
577
|
+
const teamRecommended = projection.actionable.length > 1
|
|
578
|
+
|| projection.pathConflicts.length > 0
|
|
579
|
+
|| activeOwners.length > 1
|
|
580
|
+
|| projection.acceptanceGaps.length > 0
|
|
581
|
+
|| projection.ownerTransitions.length > 0;
|
|
582
|
+
const hasUnassignedActionable = projection.actionable.some(
|
|
583
|
+
lane => lane.agentId === null,
|
|
584
|
+
);
|
|
585
|
+
const nextCommand = projection.pathConflicts.length > 0
|
|
586
|
+
? "npx --no-install owlrunkit project work-item revise-scope --help"
|
|
587
|
+
: teamRecommended && hasUnassignedActionable
|
|
588
|
+
? "npx --no-install owlrunkit project assign --help"
|
|
589
|
+
: teamRecommended && projection.ownerTransitions.length > 0
|
|
590
|
+
? "npx --no-install owlrunkit project takeover --help"
|
|
591
|
+
: teamRecommended
|
|
592
|
+
? "npx --no-install owlrunkit team packet validate --help"
|
|
593
|
+
: project === null
|
|
594
|
+
? null
|
|
595
|
+
: `npx --no-install owlrunkit project status --workspace ${shellQuote(workspaceRoot)}`;
|
|
596
|
+
|
|
597
|
+
return {
|
|
598
|
+
schemaVersion: "OwlCodaRunKitTeamRecommendationV1",
|
|
599
|
+
status: "team_delivery_recommended",
|
|
600
|
+
project: project === null
|
|
601
|
+
? { present: false, projectId: null, projectTruthHash: null, overall: null }
|
|
602
|
+
: {
|
|
603
|
+
present: true,
|
|
604
|
+
projectId: project.projectId,
|
|
605
|
+
projectTruthHash: project.projectTruthHash,
|
|
606
|
+
overall: project.overall,
|
|
607
|
+
},
|
|
608
|
+
recommendedMode: teamRecommended ? "team" : "off",
|
|
609
|
+
continuity: project === null ? "none" : "project_driver",
|
|
610
|
+
coordination: teamRecommended ? "project_driver_team" : "none",
|
|
611
|
+
assurance: {
|
|
612
|
+
changed: false,
|
|
613
|
+
selection: "unchanged",
|
|
614
|
+
reason: "team_delivery_does_not_select_assurance",
|
|
615
|
+
},
|
|
616
|
+
reasonCodes: uniqueSorted(reasonCodes),
|
|
617
|
+
rejectedLighterModes: teamRecommended
|
|
618
|
+
? [{ mode: "off", reasonCodes: uniqueSorted(reasonCodes) }]
|
|
619
|
+
: [],
|
|
620
|
+
lanes: projection.lanes,
|
|
621
|
+
pathConflicts: projection.pathConflicts,
|
|
622
|
+
acceptanceGaps: projection.acceptanceGaps,
|
|
623
|
+
ownerTransitions: projection.ownerTransitions,
|
|
624
|
+
estimatedOverhead: {
|
|
625
|
+
additionalOperatorSteps: teamRecommended ? 1 : 0,
|
|
626
|
+
potentialPortablePackets: teamRecommended ? projection.actionable.length : 0,
|
|
627
|
+
},
|
|
628
|
+
nextCommand,
|
|
629
|
+
dispatch: {
|
|
630
|
+
mode: "none",
|
|
631
|
+
permitted: false,
|
|
632
|
+
nextCommand: null,
|
|
633
|
+
},
|
|
634
|
+
authorityBoundary: { ...AUTHORITY_BOUNDARY },
|
|
635
|
+
authorizationGranted: false,
|
|
636
|
+
exitCode: 0,
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
export function recommendTeamDeliveryV1({ workspaceRoot } = {}) {
|
|
641
|
+
if (!nonEmptyString(workspaceRoot)) throw new Error("workspaceRoot is required.");
|
|
642
|
+
return recommendationFromProject(currentProjectStatus(workspaceRoot), workspaceRoot);
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
export function readTeamDeliveryStatusV1({ workspaceRoot } = {}) {
|
|
646
|
+
if (!nonEmptyString(workspaceRoot)) throw new Error("workspaceRoot is required.");
|
|
647
|
+
const project = currentProjectStatus(workspaceRoot);
|
|
648
|
+
const recommendation = recommendationFromProject(project, workspaceRoot);
|
|
649
|
+
return {
|
|
650
|
+
schemaVersion: "OwlCodaRunKitTeamDeliveryStatusV1",
|
|
651
|
+
status: "team_delivery_status",
|
|
652
|
+
graphSource: "project_driver",
|
|
653
|
+
persistedTeamGraph: false,
|
|
654
|
+
projectId: project?.projectId ?? null,
|
|
655
|
+
projectTruthHash: project?.projectTruthHash ?? null,
|
|
656
|
+
projectOverall: project?.overall ?? "not_initialized",
|
|
657
|
+
recommendation: {
|
|
658
|
+
recommendedMode: recommendation.recommendedMode,
|
|
659
|
+
coordination: recommendation.coordination,
|
|
660
|
+
reasonCodes: recommendation.reasonCodes,
|
|
661
|
+
},
|
|
662
|
+
lanes: recommendation.lanes,
|
|
663
|
+
pathConflicts: recommendation.pathConflicts,
|
|
664
|
+
acceptanceGaps: recommendation.acceptanceGaps,
|
|
665
|
+
ownerTransitions: recommendation.ownerTransitions,
|
|
666
|
+
nextAction: recommendation.nextCommand,
|
|
667
|
+
dispatch: { ...recommendation.dispatch },
|
|
668
|
+
authorityBoundary: { ...AUTHORITY_BOUNDARY },
|
|
669
|
+
authorizationGranted: false,
|
|
670
|
+
exitCode: 0,
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
function bindPacketToProject(packet, project, definition, issueCodes) {
|
|
675
|
+
if (!projectBindingValid(packet.projectBinding)) return;
|
|
676
|
+
if (project === null) {
|
|
677
|
+
issueCodes.push("packet_project_not_initialized");
|
|
678
|
+
return;
|
|
679
|
+
}
|
|
680
|
+
if (packet.projectBinding.projectId !== project.projectId) {
|
|
681
|
+
issueCodes.push("packet_project_id_mismatch");
|
|
682
|
+
}
|
|
683
|
+
if (packet.projectBinding.projectTruthHash !== project.projectTruthHash) {
|
|
684
|
+
issueCodes.push("packet_project_truth_mismatch");
|
|
685
|
+
}
|
|
686
|
+
const gate = id(packet.gateId)
|
|
687
|
+
? definition.integrationGates.find(row => row.id === packet.gateId) ?? null
|
|
688
|
+
: null;
|
|
689
|
+
if (id(packet.gateId) && gate === null) {
|
|
690
|
+
issueCodes.push("packet_gate_unknown");
|
|
691
|
+
}
|
|
692
|
+
const workItemId = packet.schemaVersion === "OwlCodaRunKitTeamTaskPacketV2"
|
|
693
|
+
? packet.workItem?.workItemId
|
|
694
|
+
: packet.workItemId;
|
|
695
|
+
const current = project.workItems.find(workItem => workItem.workItemId === workItemId);
|
|
696
|
+
if (!current) {
|
|
697
|
+
issueCodes.push("packet_work_item_unknown");
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
if (gate !== null && !gate.requiredWorkItemIds.includes(workItemId)) {
|
|
701
|
+
issueCodes.push("packet_gate_work_item_mismatch");
|
|
702
|
+
}
|
|
703
|
+
if (packet.schemaVersion === "OwlCodaRunKitTeamTaskPacketV2") {
|
|
704
|
+
if (packet.workItem.title !== current.title
|
|
705
|
+
|| !sameStringSet(packet.workItem.dependencies, current.dependencies)) {
|
|
706
|
+
issueCodes.push("packet_work_item_truth_mismatch");
|
|
707
|
+
}
|
|
708
|
+
if (!sameStringSet(packet.workItem.ownedPaths, current.ownedPaths)
|
|
709
|
+
|| !sameStringSet(packet.scope.allowedChangedPaths, current.ownedPaths)) {
|
|
710
|
+
issueCodes.push("packet_owned_paths_mismatch");
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
export function validateTeamPacketV1({ workspaceRoot, packet } = {}) {
|
|
716
|
+
if (!nonEmptyString(workspaceRoot)) throw new Error("workspaceRoot is required.");
|
|
717
|
+
const kind = PACKET_KINDS.get(packet?.schemaVersion) ?? "unknown";
|
|
718
|
+
const contractValid = kind === "task"
|
|
719
|
+
? taskPacketContractValid(packet)
|
|
720
|
+
: kind === "acceptance"
|
|
721
|
+
? acceptancePacketContractValid(packet)
|
|
722
|
+
: kind === "transfer"
|
|
723
|
+
? transferPacketContractValid(packet)
|
|
724
|
+
: false;
|
|
725
|
+
const issueCodes = [];
|
|
726
|
+
if (!contractValid) issueCodes.push("packet_contract_invalid");
|
|
727
|
+
if (contractValid) {
|
|
728
|
+
if (!existsSync(projectDefinitionPath(workspaceRoot))) {
|
|
729
|
+
bindPacketToProject(packet, null, null, issueCodes);
|
|
730
|
+
} else {
|
|
731
|
+
const definitionBefore = readProjectDefinition(workspaceRoot);
|
|
732
|
+
const projectBefore = currentProjectStatus(workspaceRoot);
|
|
733
|
+
const projectAfter = currentProjectStatus(workspaceRoot);
|
|
734
|
+
const definitionAfter = readProjectDefinition(workspaceRoot);
|
|
735
|
+
if (teamProjectDefinitionBindingV1(definitionBefore).projectDefinitionSha256
|
|
736
|
+
!== teamProjectDefinitionBindingV1(definitionAfter).projectDefinitionSha256
|
|
737
|
+
|| projectBefore.projectTruthHash !== projectAfter.projectTruthHash) {
|
|
738
|
+
issueCodes.push("packet_project_truth_changed_during_validation");
|
|
739
|
+
} else {
|
|
740
|
+
bindPacketToProject(packet, projectAfter, definitionAfter, issueCodes);
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
if (kind === "task"
|
|
744
|
+
&& new Set(["medium", "high"]).has(packet.risk.secondOrderRisk)
|
|
745
|
+
&& packet.acceptance.sameFamilyAllowed) {
|
|
746
|
+
issueCodes.push("same_family_acceptance_forbidden_for_risk");
|
|
747
|
+
}
|
|
748
|
+
if (kind === "task") {
|
|
749
|
+
if (packet.actor.executingAgent !== packet.entry.soleWriter) {
|
|
750
|
+
issueCodes.push("task_sole_writer_mismatch");
|
|
751
|
+
}
|
|
752
|
+
if (packet.actor.modelFamily !== packet.acceptance.implementationModelFamily
|
|
753
|
+
|| packet.actor.modelVersion !== packet.acceptance.implementationModelVersion) {
|
|
754
|
+
issueCodes.push("task_implementation_identity_mismatch");
|
|
755
|
+
}
|
|
756
|
+
if (new Set(["medium", "high"]).has(packet.risk.secondOrderRisk)
|
|
757
|
+
&& packet.actor.modelFamily === packet.acceptance.verificationModelFamily) {
|
|
758
|
+
issueCodes.push("planned_acceptance_same_model_family");
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
if (kind === "acceptance") {
|
|
762
|
+
const requiresIndependence = new Set(["medium", "high"]).has(packet.secondOrderRisk);
|
|
763
|
+
if (requiresIndependence
|
|
764
|
+
&& packet.independenceStatus === "independent"
|
|
765
|
+
&& packet.implementation.modelFamily === packet.verification.modelFamily) {
|
|
766
|
+
issueCodes.push("independent_acceptance_same_model_family");
|
|
767
|
+
}
|
|
768
|
+
if (requiresIndependence
|
|
769
|
+
&& packet.independenceStatus === "independent"
|
|
770
|
+
&& packet.implementation.agent === packet.verification.agent) {
|
|
771
|
+
issueCodes.push("independent_acceptance_same_agent");
|
|
772
|
+
}
|
|
773
|
+
if (packet.independenceStatus === "independent"
|
|
774
|
+
&& packet.implementation.modelFamily === packet.verification.modelFamily) {
|
|
775
|
+
issueCodes.push("independence_status_inconsistent");
|
|
776
|
+
}
|
|
777
|
+
if (packet.independenceStatus === "same_family_not_independent"
|
|
778
|
+
&& packet.implementation.modelFamily !== packet.verification.modelFamily) {
|
|
779
|
+
issueCodes.push("independence_status_inconsistent");
|
|
780
|
+
}
|
|
781
|
+
if (requiresIndependence
|
|
782
|
+
&& packet.verdict === "ACCEPT"
|
|
783
|
+
&& (
|
|
784
|
+
packet.implementation.modelFamily === packet.verification.modelFamily
|
|
785
|
+
|| packet.implementation.agent === packet.verification.agent
|
|
786
|
+
)) {
|
|
787
|
+
issueCodes.push("accepted_packet_requires_independent_verifier");
|
|
788
|
+
}
|
|
789
|
+
if (packet.verdict === "ACCEPT"
|
|
790
|
+
&& packet.candidateIdentityBefore !== packet.candidateIdentityAfter) {
|
|
791
|
+
issueCodes.push("accepted_candidate_identity_drift");
|
|
792
|
+
}
|
|
793
|
+
if (packet.verdict === "ACCEPT"
|
|
794
|
+
&& packet.acceptanceLevel !== "L0"
|
|
795
|
+
&& (
|
|
796
|
+
packet.freshAdversarialFamilies.length === 0
|
|
797
|
+
|| packet.coverageLedger.checksRunFresh.length === 0
|
|
798
|
+
)) {
|
|
799
|
+
issueCodes.push("accepted_packet_requires_fresh_adversarial_evidence");
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
if (kind === "transfer") {
|
|
803
|
+
if (packet.handoffAck.status === "accepted"
|
|
804
|
+
&& (
|
|
805
|
+
packet.handoffAck.agent !== packet.nextOwner
|
|
806
|
+
|| packet.handoffAck.evidenceRefs.length === 0
|
|
807
|
+
)) {
|
|
808
|
+
issueCodes.push("accepted_handoff_ack_invalid");
|
|
809
|
+
}
|
|
810
|
+
if (packet.lifecycle === "old_writer_release"
|
|
811
|
+
&& (
|
|
812
|
+
packet.handoffAck.status !== "accepted"
|
|
813
|
+
|| packet.handoffAck.agent !== packet.nextOwner
|
|
814
|
+
|| packet.handoffAck.evidenceRefs.length === 0
|
|
815
|
+
)) {
|
|
816
|
+
issueCodes.push("old_writer_release_requires_accepted_handoff_ack");
|
|
817
|
+
}
|
|
818
|
+
if (packet.lifecycle === "handoff_ack"
|
|
819
|
+
&& (
|
|
820
|
+
packet.handoffAck.status !== "accepted"
|
|
821
|
+
|| packet.handoffAck.agent !== packet.nextOwner
|
|
822
|
+
|| packet.handoffAck.evidenceRefs.length === 0
|
|
823
|
+
)) {
|
|
824
|
+
issueCodes.push("handoff_ack_lifecycle_requires_accepted_ack");
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
const uniqueIssues = uniqueSorted(issueCodes);
|
|
829
|
+
return {
|
|
830
|
+
schemaVersion: "OwlCodaRunKitTeamPacketValidationV1",
|
|
831
|
+
status: uniqueIssues.length === 0 ? "team_packet_valid" : "team_packet_invalid",
|
|
832
|
+
packetKind: kind,
|
|
833
|
+
packetSchemaVersion: packet?.schemaVersion ?? null,
|
|
834
|
+
issueCodes: uniqueIssues,
|
|
835
|
+
authorityBoundary: { ...AUTHORITY_BOUNDARY },
|
|
836
|
+
authorizationGranted: false,
|
|
837
|
+
exitCode: uniqueIssues.length === 0 ? 0 : 2,
|
|
838
|
+
};
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
export function validateTeamPacketFileV1({ workspaceRoot, packetPath } = {}) {
|
|
842
|
+
if (!nonEmptyString(packetPath)) throw new Error("packetPath is required.");
|
|
843
|
+
try {
|
|
844
|
+
const { bytes } = readFileBytesBounded(packetPath);
|
|
845
|
+
const packet = parseJsonStrict(decodeUtf8Strict(bytes));
|
|
846
|
+
return validateTeamPacketV1({ workspaceRoot, packet });
|
|
847
|
+
} catch (error) {
|
|
848
|
+
const duplicate = error?.code === "receipt_duplicate_key"
|
|
849
|
+
|| error?.code === "DUPLICATE_OBJECT_KEY";
|
|
850
|
+
return {
|
|
851
|
+
schemaVersion: "OwlCodaRunKitTeamPacketValidationV1",
|
|
852
|
+
status: "team_packet_invalid",
|
|
853
|
+
packetKind: "unknown",
|
|
854
|
+
packetSchemaVersion: null,
|
|
855
|
+
issueCodes: [duplicate ? "packet_duplicate_object_key" : "packet_unreadable"],
|
|
856
|
+
authorityBoundary: { ...AUTHORITY_BOUNDARY },
|
|
857
|
+
authorizationGranted: false,
|
|
858
|
+
exitCode: 2,
|
|
859
|
+
};
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
export function formatTeamDeliveryRecommendationHumanV1(result) {
|
|
864
|
+
return [
|
|
865
|
+
`Recommended Team mode: ${result.recommendedMode}`,
|
|
866
|
+
`Continuity: ${result.continuity}`,
|
|
867
|
+
`Coordination: ${result.coordination}`,
|
|
868
|
+
`Why: ${result.reasonCodes.join(", ") || "none"}`,
|
|
869
|
+
`Lanes: ${result.lanes.length}`,
|
|
870
|
+
`Path conflicts: ${result.pathConflicts.length}`,
|
|
871
|
+
`Acceptance gaps: ${result.acceptanceGaps.length}`,
|
|
872
|
+
`Next: ${result.nextCommand ?? "none"}`,
|
|
873
|
+
"Agent dispatch: not permitted.",
|
|
874
|
+
"Authority: no Git, release, deployment, production, business, automation, or money authorization granted.",
|
|
875
|
+
"",
|
|
876
|
+
].join("\n");
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
export function formatTeamDeliveryStatusHumanV1(result) {
|
|
880
|
+
return [
|
|
881
|
+
`Team Delivery: ${result.recommendation.recommendedMode}`,
|
|
882
|
+
`Project: ${result.projectId ?? "not initialized"}`,
|
|
883
|
+
`Project state: ${result.projectOverall}`,
|
|
884
|
+
`Graph source: ${result.graphSource}`,
|
|
885
|
+
`Persisted team graph: ${result.persistedTeamGraph ? "yes" : "no"}`,
|
|
886
|
+
`Lanes: ${result.lanes.length}`,
|
|
887
|
+
`Path conflicts: ${result.pathConflicts.length}`,
|
|
888
|
+
`Acceptance gaps: ${result.acceptanceGaps.length}`,
|
|
889
|
+
`Next: ${result.nextAction ?? "none"}`,
|
|
890
|
+
"Agent dispatch: not permitted.",
|
|
891
|
+
"Authority: not granted.",
|
|
892
|
+
"",
|
|
893
|
+
].join("\n");
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
export function formatTeamPacketValidationHumanV1(result) {
|
|
897
|
+
return [
|
|
898
|
+
`Team packet: ${result.status}`,
|
|
899
|
+
`Kind: ${result.packetKind}`,
|
|
900
|
+
`Schema: ${result.packetSchemaVersion ?? "unknown"}`,
|
|
901
|
+
`Issues: ${result.issueCodes.join(", ") || "none"}`,
|
|
902
|
+
"Agent dispatch: not permitted.",
|
|
903
|
+
"Authority: not granted.",
|
|
904
|
+
"",
|
|
905
|
+
].join("\n");
|
|
906
|
+
}
|