@generacy-ai/cockpit 0.5.0 → 0.7.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/README.md +148 -0
- package/dist/gates/clarification-hash.d.ts +33 -0
- package/dist/gates/clarification-hash.d.ts.map +1 -0
- package/dist/gates/clarification-hash.js +27 -0
- package/dist/gates/clarification-hash.js.map +1 -0
- package/dist/gates/fixtures.d.ts +15 -0
- package/dist/gates/fixtures.d.ts.map +1 -0
- package/dist/gates/fixtures.js +227 -0
- package/dist/gates/fixtures.js.map +1 -0
- package/dist/gates/gate-id.d.ts +11 -0
- package/dist/gates/gate-id.d.ts.map +1 -0
- package/dist/gates/gate-id.js +11 -0
- package/dist/gates/gate-id.js.map +1 -0
- package/dist/gates/generation.d.ts +39 -0
- package/dist/gates/generation.d.ts.map +1 -0
- package/dist/gates/generation.js +31 -0
- package/dist/gates/generation.js.map +1 -0
- package/dist/gates/index.d.ts +10 -0
- package/dist/gates/index.d.ts.map +1 -0
- package/dist/gates/index.js +19 -0
- package/dist/gates/index.js.map +1 -0
- package/dist/gates/schema.d.ts +192 -0
- package/dist/gates/schema.d.ts.map +1 -0
- package/dist/gates/schema.js +136 -0
- package/dist/gates/schema.js.map +1 -0
- package/dist/gates/schemas.d.ts +28 -0
- package/dist/gates/schemas.d.ts.map +1 -0
- package/dist/gates/schemas.js +21 -0
- package/dist/gates/schemas.js.map +1 -0
- package/dist/gates/types.d.ts +15 -0
- package/dist/gates/types.d.ts.map +1 -0
- package/dist/gates/types.js +19 -0
- package/dist/gates/types.js.map +1 -0
- package/dist/gates/wire-fixtures.d.ts +84 -0
- package/dist/gates/wire-fixtures.d.ts.map +1 -0
- package/dist/gates/wire-fixtures.js +107 -0
- package/dist/gates/wire-fixtures.js.map +1 -0
- package/dist/gh/wrapper.d.ts +22 -0
- package/dist/gh/wrapper.d.ts.map +1 -1
- package/dist/gh/wrapper.js +47 -6
- package/dist/gh/wrapper.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -1
- package/dist/resolver/parse-epic-body.d.ts +9 -3
- package/dist/resolver/parse-epic-body.d.ts.map +1 -1
- package/dist/resolver/parse-epic-body.js +81 -5
- package/dist/resolver/parse-epic-body.js.map +1 -1
- package/dist/resolver/resolve.d.ts.map +1 -1
- package/dist/resolver/resolve.js +3 -1
- package/dist/resolver/resolve.js.map +1 -1
- package/dist/resolver/types.d.ts +19 -0
- package/dist/resolver/types.d.ts.map +1 -1
- package/dist/state/precedence.d.ts.map +1 -1
- package/dist/state/precedence.js +16 -0
- package/dist/state/precedence.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Canonical cockpit gate wire schemas — the cluster (generacy) side of the
|
|
4
|
+
* frozen contract in tetrad-development/docs/cockpit-remote-gates-plan.md
|
|
5
|
+
* § "Wire contracts" and generacy-cloud/specs/843-part-cockpit-remote-gates/
|
|
6
|
+
* contracts/gates-wire.md (Shapes 1/2/3).
|
|
7
|
+
*
|
|
8
|
+
* The cloud is the authoritative RECEIVER; these schemas MUST stay
|
|
9
|
+
* field-for-field compatible with generacy-cloud:
|
|
10
|
+
* - services/api/src/services/relay/message-handler.ts
|
|
11
|
+
* gateOpenPayloadSchema / gateOutcomePayloadSchema
|
|
12
|
+
* - packages/db/src/collections/cockpit-gates.ts
|
|
13
|
+
* cockpitGateTypeEnum / cockpitGateOptionSchema / cockpitGateAnswerSchema
|
|
14
|
+
*
|
|
15
|
+
* Wire values are JSON, so all timestamps are ISO-8601 strings here; the cloud
|
|
16
|
+
* ingests them with `z.coerce.date()`.
|
|
17
|
+
*/
|
|
18
|
+
export declare const GateTypeSchema: z.ZodEnum<["clarification", "artifact-review", "implementation-review", "manual-validation", "escalation", "phase-queue", "filing", "scope-drained"]>;
|
|
19
|
+
export type GateType = z.infer<typeof GateTypeSchema>;
|
|
20
|
+
export declare const GateOptionSchema: z.ZodObject<{
|
|
21
|
+
id: z.ZodString;
|
|
22
|
+
label: z.ZodString;
|
|
23
|
+
description: z.ZodOptional<z.ZodString>;
|
|
24
|
+
recommended: z.ZodOptional<z.ZodBoolean>;
|
|
25
|
+
}, "strip", z.ZodTypeAny, {
|
|
26
|
+
id: string;
|
|
27
|
+
label: string;
|
|
28
|
+
description?: string | undefined;
|
|
29
|
+
recommended?: boolean | undefined;
|
|
30
|
+
}, {
|
|
31
|
+
id: string;
|
|
32
|
+
label: string;
|
|
33
|
+
description?: string | undefined;
|
|
34
|
+
recommended?: boolean | undefined;
|
|
35
|
+
}>;
|
|
36
|
+
export type GateOption = z.infer<typeof GateOptionSchema>;
|
|
37
|
+
export declare const GateOpenSchema: z.ZodObject<{
|
|
38
|
+
type: z.ZodLiteral<"gate-open">;
|
|
39
|
+
gateId: z.ZodString;
|
|
40
|
+
gateKey: z.ZodString;
|
|
41
|
+
gateType: z.ZodEnum<["clarification", "artifact-review", "implementation-review", "manual-validation", "escalation", "phase-queue", "filing", "scope-drained"]>;
|
|
42
|
+
epicRef: z.ZodString;
|
|
43
|
+
issueRef: z.ZodString;
|
|
44
|
+
issueTitle: z.ZodString;
|
|
45
|
+
issueUrl: z.ZodString;
|
|
46
|
+
branch: z.ZodOptional<z.ZodString>;
|
|
47
|
+
prNumber: z.ZodOptional<z.ZodNumber>;
|
|
48
|
+
title: z.ZodString;
|
|
49
|
+
body: z.ZodString;
|
|
50
|
+
options: z.ZodArray<z.ZodObject<{
|
|
51
|
+
id: z.ZodString;
|
|
52
|
+
label: z.ZodString;
|
|
53
|
+
description: z.ZodOptional<z.ZodString>;
|
|
54
|
+
recommended: z.ZodOptional<z.ZodBoolean>;
|
|
55
|
+
}, "strip", z.ZodTypeAny, {
|
|
56
|
+
id: string;
|
|
57
|
+
label: string;
|
|
58
|
+
description?: string | undefined;
|
|
59
|
+
recommended?: boolean | undefined;
|
|
60
|
+
}, {
|
|
61
|
+
id: string;
|
|
62
|
+
label: string;
|
|
63
|
+
description?: string | undefined;
|
|
64
|
+
recommended?: boolean | undefined;
|
|
65
|
+
}>, "many">;
|
|
66
|
+
allowFreeText: z.ZodBoolean;
|
|
67
|
+
sessionId: z.ZodString;
|
|
68
|
+
askedAt: z.ZodString;
|
|
69
|
+
frameId: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodEffects<z.ZodLiteral<"">, undefined, "">, z.ZodEffects<z.ZodNull, undefined, null>]>>;
|
|
70
|
+
}, "strip", z.ZodTypeAny, {
|
|
71
|
+
options: {
|
|
72
|
+
id: string;
|
|
73
|
+
label: string;
|
|
74
|
+
description?: string | undefined;
|
|
75
|
+
recommended?: boolean | undefined;
|
|
76
|
+
}[];
|
|
77
|
+
type: "gate-open";
|
|
78
|
+
title: string;
|
|
79
|
+
body: string;
|
|
80
|
+
gateId: string;
|
|
81
|
+
gateKey: string;
|
|
82
|
+
gateType: "clarification" | "artifact-review" | "implementation-review" | "manual-validation" | "escalation" | "phase-queue" | "filing" | "scope-drained";
|
|
83
|
+
epicRef: string;
|
|
84
|
+
issueRef: string;
|
|
85
|
+
issueTitle: string;
|
|
86
|
+
issueUrl: string;
|
|
87
|
+
allowFreeText: boolean;
|
|
88
|
+
sessionId: string;
|
|
89
|
+
askedAt: string;
|
|
90
|
+
prNumber?: number | undefined;
|
|
91
|
+
branch?: string | undefined;
|
|
92
|
+
frameId?: string | undefined;
|
|
93
|
+
}, {
|
|
94
|
+
options: {
|
|
95
|
+
id: string;
|
|
96
|
+
label: string;
|
|
97
|
+
description?: string | undefined;
|
|
98
|
+
recommended?: boolean | undefined;
|
|
99
|
+
}[];
|
|
100
|
+
type: "gate-open";
|
|
101
|
+
title: string;
|
|
102
|
+
body: string;
|
|
103
|
+
gateId: string;
|
|
104
|
+
gateKey: string;
|
|
105
|
+
gateType: "clarification" | "artifact-review" | "implementation-review" | "manual-validation" | "escalation" | "phase-queue" | "filing" | "scope-drained";
|
|
106
|
+
epicRef: string;
|
|
107
|
+
issueRef: string;
|
|
108
|
+
issueTitle: string;
|
|
109
|
+
issueUrl: string;
|
|
110
|
+
allowFreeText: boolean;
|
|
111
|
+
sessionId: string;
|
|
112
|
+
askedAt: string;
|
|
113
|
+
prNumber?: number | undefined;
|
|
114
|
+
branch?: string | undefined;
|
|
115
|
+
frameId?: string | null | undefined;
|
|
116
|
+
}>;
|
|
117
|
+
export type GateOpen = z.infer<typeof GateOpenSchema>;
|
|
118
|
+
export declare const GateOutcomeSchema: z.ZodObject<{
|
|
119
|
+
type: z.ZodLiteral<"gate-outcome">;
|
|
120
|
+
gateId: z.ZodString;
|
|
121
|
+
outcome: z.ZodEnum<["applied", "superseded", "failed"]>;
|
|
122
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
123
|
+
at: z.ZodString;
|
|
124
|
+
frameId: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodEffects<z.ZodLiteral<"">, undefined, "">, z.ZodEffects<z.ZodNull, undefined, null>]>>;
|
|
125
|
+
}, "strip", z.ZodTypeAny, {
|
|
126
|
+
type: "gate-outcome";
|
|
127
|
+
at: string;
|
|
128
|
+
outcome: "applied" | "superseded" | "failed";
|
|
129
|
+
gateId: string;
|
|
130
|
+
frameId?: string | undefined;
|
|
131
|
+
detail?: string | undefined;
|
|
132
|
+
}, {
|
|
133
|
+
type: "gate-outcome";
|
|
134
|
+
at: string;
|
|
135
|
+
outcome: "applied" | "superseded" | "failed";
|
|
136
|
+
gateId: string;
|
|
137
|
+
frameId?: string | null | undefined;
|
|
138
|
+
detail?: string | undefined;
|
|
139
|
+
}>;
|
|
140
|
+
export type GateOutcome = z.infer<typeof GateOutcomeSchema>;
|
|
141
|
+
export declare const GateAnswerSchema: z.ZodObject<{
|
|
142
|
+
type: z.ZodLiteral<"gate-answer">;
|
|
143
|
+
gateId: z.ZodString;
|
|
144
|
+
gateKey: z.ZodString;
|
|
145
|
+
optionId: z.ZodNullable<z.ZodString>;
|
|
146
|
+
freeText: z.ZodNullable<z.ZodString>;
|
|
147
|
+
actor: z.ZodObject<{
|
|
148
|
+
userId: z.ZodString;
|
|
149
|
+
email: z.ZodNullable<z.ZodString>;
|
|
150
|
+
displayName: z.ZodNullable<z.ZodString>;
|
|
151
|
+
}, "strip", z.ZodTypeAny, {
|
|
152
|
+
userId: string;
|
|
153
|
+
email: string | null;
|
|
154
|
+
displayName: string | null;
|
|
155
|
+
}, {
|
|
156
|
+
userId: string;
|
|
157
|
+
email: string | null;
|
|
158
|
+
displayName: string | null;
|
|
159
|
+
}>;
|
|
160
|
+
answeredAt: z.ZodString;
|
|
161
|
+
deliveryId: z.ZodString;
|
|
162
|
+
}, "strip", z.ZodTypeAny, {
|
|
163
|
+
type: "gate-answer";
|
|
164
|
+
gateId: string;
|
|
165
|
+
gateKey: string;
|
|
166
|
+
optionId: string | null;
|
|
167
|
+
freeText: string | null;
|
|
168
|
+
actor: {
|
|
169
|
+
userId: string;
|
|
170
|
+
email: string | null;
|
|
171
|
+
displayName: string | null;
|
|
172
|
+
};
|
|
173
|
+
answeredAt: string;
|
|
174
|
+
deliveryId: string;
|
|
175
|
+
}, {
|
|
176
|
+
type: "gate-answer";
|
|
177
|
+
gateId: string;
|
|
178
|
+
gateKey: string;
|
|
179
|
+
optionId: string | null;
|
|
180
|
+
freeText: string | null;
|
|
181
|
+
actor: {
|
|
182
|
+
userId: string;
|
|
183
|
+
email: string | null;
|
|
184
|
+
displayName: string | null;
|
|
185
|
+
};
|
|
186
|
+
answeredAt: string;
|
|
187
|
+
deliveryId: string;
|
|
188
|
+
}>;
|
|
189
|
+
export type GateAnswer = z.infer<typeof GateAnswerSchema>;
|
|
190
|
+
export declare function deriveGateKey(issueRef: string, gateType: GateType, generation: string | number, runId?: string): string;
|
|
191
|
+
export declare function deriveGateId(gateKey: string): string;
|
|
192
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/gates/schema.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;;;;GAeG;AAKH,eAAO,MAAM,cAAc,uJASzB,CAAC;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAKtD,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;EAK3B,CAAC;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAQ1D,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+BzB,CAAC;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAMtD,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;EAc5B,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAQ5D,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAa3B,CAAC;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAa1D,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,QAAQ,EAClB,UAAU,EAAE,MAAM,GAAG,MAAM,EAC3B,KAAK,CAAC,EAAE,MAAM,GACb,MAAM,CAGR;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEpD"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
/**
|
|
4
|
+
* Canonical cockpit gate wire schemas — the cluster (generacy) side of the
|
|
5
|
+
* frozen contract in tetrad-development/docs/cockpit-remote-gates-plan.md
|
|
6
|
+
* § "Wire contracts" and generacy-cloud/specs/843-part-cockpit-remote-gates/
|
|
7
|
+
* contracts/gates-wire.md (Shapes 1/2/3).
|
|
8
|
+
*
|
|
9
|
+
* The cloud is the authoritative RECEIVER; these schemas MUST stay
|
|
10
|
+
* field-for-field compatible with generacy-cloud:
|
|
11
|
+
* - services/api/src/services/relay/message-handler.ts
|
|
12
|
+
* gateOpenPayloadSchema / gateOutcomePayloadSchema
|
|
13
|
+
* - packages/db/src/collections/cockpit-gates.ts
|
|
14
|
+
* cockpitGateTypeEnum / cockpitGateOptionSchema / cockpitGateAnswerSchema
|
|
15
|
+
*
|
|
16
|
+
* Wire values are JSON, so all timestamps are ISO-8601 strings here; the cloud
|
|
17
|
+
* ingests them with `z.coerce.date()`.
|
|
18
|
+
*/
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Gate type enum — mirrors cloud `cockpitGateTypeEnum` exactly (8 values, order preserved).
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
export const GateTypeSchema = z.enum([
|
|
23
|
+
'clarification',
|
|
24
|
+
'artifact-review',
|
|
25
|
+
'implementation-review',
|
|
26
|
+
'manual-validation',
|
|
27
|
+
'escalation',
|
|
28
|
+
'phase-queue',
|
|
29
|
+
'filing',
|
|
30
|
+
'scope-drained',
|
|
31
|
+
]);
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// Option — mirrors cloud `cockpitGateOptionSchema`.
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
export const GateOptionSchema = z.object({
|
|
36
|
+
id: z.string(),
|
|
37
|
+
label: z.string(),
|
|
38
|
+
description: z.string().optional(),
|
|
39
|
+
recommended: z.boolean().optional(),
|
|
40
|
+
});
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
// Shape 1 — gate-open (cluster → cloud, up-path).
|
|
43
|
+
// Mirrors cloud `gateOpenPayloadSchema` (message-handler.ts).
|
|
44
|
+
// Flat, type-literal 'gate-open'. gateId/gateKey are DERIVED by the MCP tool
|
|
45
|
+
// (cockpit_gate_open) — the plugin/LLM never hand-builds a sha256.
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
export const GateOpenSchema = z.object({
|
|
48
|
+
type: z.literal('gate-open'),
|
|
49
|
+
gateId: z.string().length(24),
|
|
50
|
+
gateKey: z.string().min(1),
|
|
51
|
+
gateType: GateTypeSchema,
|
|
52
|
+
epicRef: z.string().min(1),
|
|
53
|
+
issueRef: z.string().min(1),
|
|
54
|
+
issueTitle: z.string(),
|
|
55
|
+
issueUrl: z.string().url(),
|
|
56
|
+
branch: z.string().optional(),
|
|
57
|
+
prNumber: z.number().int().positive().optional(),
|
|
58
|
+
title: z.string(),
|
|
59
|
+
body: z.string(),
|
|
60
|
+
options: z.array(GateOptionSchema).min(0).max(20),
|
|
61
|
+
allowFreeText: z.boolean(),
|
|
62
|
+
sessionId: z.string().min(1),
|
|
63
|
+
askedAt: z.string().datetime(),
|
|
64
|
+
// #1066 — preserved for cloud per-frame reply correlation. Cloud reads at
|
|
65
|
+
// services/api/src/services/relay/message-handler.ts:804 (raw `data.frameId`,
|
|
66
|
+
// upstream of the frozen payload schema). Three encodings of "no correlation"
|
|
67
|
+
// are normalized to absent: omitted, `""`, and `null`. `null` matches the
|
|
68
|
+
// cloud's own vocabulary (see `packages/cluster-relay/src/messages.ts:154`
|
|
69
|
+
// + `:387` — reply `frameId: string | null`), so a caller doing
|
|
70
|
+
// `?? null` round-trips without a 400.
|
|
71
|
+
frameId: z
|
|
72
|
+
.union([
|
|
73
|
+
z.string().min(1),
|
|
74
|
+
z.literal('').transform(() => undefined),
|
|
75
|
+
z.null().transform(() => undefined),
|
|
76
|
+
])
|
|
77
|
+
.optional(),
|
|
78
|
+
});
|
|
79
|
+
// ---------------------------------------------------------------------------
|
|
80
|
+
// Shape 2 — gate-outcome (cluster → cloud, up-path). THE ACK.
|
|
81
|
+
// Replaces the invented GateAckSchema. Mirrors cloud `gateOutcomePayloadSchema`.
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
export const GateOutcomeSchema = z.object({
|
|
84
|
+
type: z.literal('gate-outcome'),
|
|
85
|
+
gateId: z.string().length(24),
|
|
86
|
+
outcome: z.enum(['applied', 'superseded', 'failed']),
|
|
87
|
+
detail: z.string().optional(),
|
|
88
|
+
at: z.string().datetime(),
|
|
89
|
+
// Same shape and rationale as GateOpenSchema.frameId — #1066.
|
|
90
|
+
frameId: z
|
|
91
|
+
.union([
|
|
92
|
+
z.string().min(1),
|
|
93
|
+
z.literal('').transform(() => undefined),
|
|
94
|
+
z.null().transform(() => undefined),
|
|
95
|
+
])
|
|
96
|
+
.optional(),
|
|
97
|
+
});
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
// Shape 3 — gate-answer (cloud → cluster, down-path).
|
|
100
|
+
// Consumed by the orchestrator `POST /cockpit/answers` route + doorbell parser.
|
|
101
|
+
// Mirrors cloud stored `cockpitGateAnswerSchema` (nullable optionId/freeText and
|
|
102
|
+
// nullable actor.email/displayName) plus the wire-only type/gateId/gateKey.
|
|
103
|
+
// ---------------------------------------------------------------------------
|
|
104
|
+
export const GateAnswerSchema = z.object({
|
|
105
|
+
type: z.literal('gate-answer'),
|
|
106
|
+
gateId: z.string().length(24),
|
|
107
|
+
gateKey: z.string().min(1),
|
|
108
|
+
optionId: z.string().nullable(), // null on pure free-text
|
|
109
|
+
freeText: z.string().nullable(),
|
|
110
|
+
actor: z.object({
|
|
111
|
+
userId: z.string(),
|
|
112
|
+
email: z.string().email().nullable(),
|
|
113
|
+
displayName: z.string().nullable(),
|
|
114
|
+
}),
|
|
115
|
+
answeredAt: z.string().datetime(),
|
|
116
|
+
deliveryId: z.string(), // unique per delivery attempt; cluster dedups on this
|
|
117
|
+
});
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
// Gate identity derivation.
|
|
120
|
+
// gateKey = "<owner>/<repo>#<issue>:<gateType>:<generation>[:<runId>]"
|
|
121
|
+
// = `${issueRef}:${gateType}:${generation}[:${runId}]`
|
|
122
|
+
// gateId = sha256(gateKey) hex, first 24 chars.
|
|
123
|
+
// `generation` is gateType-specific (batch id, head SHA, phase number, drain
|
|
124
|
+
// counter, …); coerced to string so numeric discriminators (phase 2) are stable.
|
|
125
|
+
// `runId` (#1053) is the optional per-run discriminator that guarantees a
|
|
126
|
+
// fresh gateId across independent runs of the same natural gate. When absent
|
|
127
|
+
// the output is byte-for-byte compatible with the pre-#1053 shape.
|
|
128
|
+
// ---------------------------------------------------------------------------
|
|
129
|
+
export function deriveGateKey(issueRef, gateType, generation, runId) {
|
|
130
|
+
const base = `${issueRef}:${gateType}:${String(generation)}`;
|
|
131
|
+
return runId === undefined ? base : `${base}:${runId}`;
|
|
132
|
+
}
|
|
133
|
+
export function deriveGateId(gateKey) {
|
|
134
|
+
return createHash('sha256').update(gateKey, 'utf8').digest('hex').slice(0, 24);
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/gates/schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Object form of an issue reference. This is a cluster-local convenience shape
|
|
4
|
+
* used by the gate-generation helpers (`deriveScopeDrainedGeneration`) and by
|
|
5
|
+
* MCP callers before they format it to the flat `owner/repo#N` wire string.
|
|
6
|
+
*
|
|
7
|
+
* The WIRE shapes in `./schema.ts` carry `issueRef` / `epicRef` as plain
|
|
8
|
+
* strings (Shapes 1/3, mirroring the cloud); this object shape never crosses
|
|
9
|
+
* the wire. Format it with {@link issueRefToString} before calling
|
|
10
|
+
* `deriveGateKey`.
|
|
11
|
+
*/
|
|
12
|
+
export declare const IssueRefSchema: z.ZodObject<{
|
|
13
|
+
owner: z.ZodString;
|
|
14
|
+
repo: z.ZodString;
|
|
15
|
+
number: z.ZodNumber;
|
|
16
|
+
}, "strip", z.ZodTypeAny, {
|
|
17
|
+
number: number;
|
|
18
|
+
owner: string;
|
|
19
|
+
repo: string;
|
|
20
|
+
}, {
|
|
21
|
+
number: number;
|
|
22
|
+
owner: string;
|
|
23
|
+
repo: string;
|
|
24
|
+
}>;
|
|
25
|
+
export type IssueRef = z.infer<typeof IssueRefSchema>;
|
|
26
|
+
/** Format an object {@link IssueRef} to the canonical `owner/repo#N` wire ref. */
|
|
27
|
+
export declare function issueRefToString(ref: IssueRef): string;
|
|
28
|
+
//# sourceMappingURL=schemas.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../src/gates/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;EAIzB,CAAC;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD,kFAAkF;AAClF,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,QAAQ,GAAG,MAAM,CAEtD"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Object form of an issue reference. This is a cluster-local convenience shape
|
|
4
|
+
* used by the gate-generation helpers (`deriveScopeDrainedGeneration`) and by
|
|
5
|
+
* MCP callers before they format it to the flat `owner/repo#N` wire string.
|
|
6
|
+
*
|
|
7
|
+
* The WIRE shapes in `./schema.ts` carry `issueRef` / `epicRef` as plain
|
|
8
|
+
* strings (Shapes 1/3, mirroring the cloud); this object shape never crosses
|
|
9
|
+
* the wire. Format it with {@link issueRefToString} before calling
|
|
10
|
+
* `deriveGateKey`.
|
|
11
|
+
*/
|
|
12
|
+
export const IssueRefSchema = z.object({
|
|
13
|
+
owner: z.string().min(1).regex(/^[a-zA-Z0-9-_.]+$/),
|
|
14
|
+
repo: z.string().min(1).regex(/^[a-zA-Z0-9-_.]+$/),
|
|
15
|
+
number: z.number().int().positive(),
|
|
16
|
+
});
|
|
17
|
+
/** Format an object {@link IssueRef} to the canonical `owner/repo#N` wire ref. */
|
|
18
|
+
export function issueRefToString(ref) {
|
|
19
|
+
return `${ref.owner}/${ref.repo}#${ref.number}`;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=schemas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../src/gates/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IACrC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,mBAAmB,CAAC;IACnD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,mBAAmB,CAAC;IAClD,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;CACpC,CAAC,CAAC;AAGH,kFAAkF;AAClF,MAAM,UAAU,gBAAgB,CAAC,GAAa;IAC5C,OAAO,GAAG,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;AAClD,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Artifact-review kinds — a cluster-local enumeration used only by the
|
|
4
|
+
* `deriveArtifactReviewGeneration` helper (generation.ts) to build the
|
|
5
|
+
* `<kind>:<headSha>` discriminator. It is NOT a wire type: the gate-open
|
|
6
|
+
* record carries `gateType: 'artifact-review'`, and the kind is folded into
|
|
7
|
+
* `gateKey`'s generation slot.
|
|
8
|
+
*
|
|
9
|
+
* The wire enum (`GateTypeSchema`), the gate option/answer/outcome shapes and
|
|
10
|
+
* the gateKey/gateId derivation all live in `./schema.ts` — the single source.
|
|
11
|
+
*/
|
|
12
|
+
export declare const ARTIFACT_REVIEW_KINDS: readonly ["spec-review", "plan-review", "tasks-review", "clarification-review"];
|
|
13
|
+
export declare const ArtifactReviewKindSchema: z.ZodEnum<["spec-review", "plan-review", "tasks-review", "clarification-review"]>;
|
|
14
|
+
export type ArtifactReviewKind = z.infer<typeof ArtifactReviewKindSchema>;
|
|
15
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/gates/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;GASG;AACH,eAAO,MAAM,qBAAqB,iFAKxB,CAAC;AAEX,eAAO,MAAM,wBAAwB,mFAAgC,CAAC;AACtE,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Artifact-review kinds — a cluster-local enumeration used only by the
|
|
4
|
+
* `deriveArtifactReviewGeneration` helper (generation.ts) to build the
|
|
5
|
+
* `<kind>:<headSha>` discriminator. It is NOT a wire type: the gate-open
|
|
6
|
+
* record carries `gateType: 'artifact-review'`, and the kind is folded into
|
|
7
|
+
* `gateKey`'s generation slot.
|
|
8
|
+
*
|
|
9
|
+
* The wire enum (`GateTypeSchema`), the gate option/answer/outcome shapes and
|
|
10
|
+
* the gateKey/gateId derivation all live in `./schema.ts` — the single source.
|
|
11
|
+
*/
|
|
12
|
+
export const ARTIFACT_REVIEW_KINDS = [
|
|
13
|
+
'spec-review',
|
|
14
|
+
'plan-review',
|
|
15
|
+
'tasks-review',
|
|
16
|
+
'clarification-review',
|
|
17
|
+
];
|
|
18
|
+
export const ArtifactReviewKindSchema = z.enum(ARTIFACT_REVIEW_KINDS);
|
|
19
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/gates/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,aAAa;IACb,aAAa;IACb,cAAc;IACd,sBAAsB;CACd,CAAC;AAEX,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire-envelope fixture builders for the cluster-side transport contracts
|
|
3
|
+
* (#1024). These build the exact JSON frames that cross the cluster-side wire,
|
|
4
|
+
* all validated against the canonical schemas in `./schema.ts`:
|
|
5
|
+
*
|
|
6
|
+
* - `gateOpenFixture()` → body of `POST /cockpit/gates` (`GateOpenSchema`, Shape 1)
|
|
7
|
+
* - `gateOutcomeFixture()` → body of `POST /cockpit/gates/:id/ack` (`GateOutcomeSchema`, Shape 2 — THE ACK)
|
|
8
|
+
* - `answerLineFixture()` → body of `POST /cockpit/answers` AND the NDJSON
|
|
9
|
+
* line the doorbell tails (`GateAnswerSchema`, Shape 3)
|
|
10
|
+
*
|
|
11
|
+
* The #1024 integration harness single-sources every wire body through these
|
|
12
|
+
* builders (FR-009 / SC-004) so a drift in the transport shape fails the
|
|
13
|
+
* harness in one place rather than silently passing an inline literal.
|
|
14
|
+
*
|
|
15
|
+
* NB: the frozen frames are FLAT with a `type` discriminator ('gate-open' |
|
|
16
|
+
* 'gate-outcome' | 'gate-answer'); there is no `kind`, no `scope` wrapper and no
|
|
17
|
+
* top-level `generation` (generation is folded into `gateKey`). gateId/gateKey
|
|
18
|
+
* are DERIVED, so the default frame carries a real 24-hex gateId.
|
|
19
|
+
*/
|
|
20
|
+
import { type GateAnswer, type GateOpen, type GateOutcome } from './schema.js';
|
|
21
|
+
/** Epic/issue scope the harness binds the doorbell to. The wire carries the ref
|
|
22
|
+
* as the flat `owner/repo#N` string ({@link DEFAULT_WIRE_EPIC_REF}); this object
|
|
23
|
+
* form is a convenience for callers that need the parts. */
|
|
24
|
+
export interface WireScope {
|
|
25
|
+
owner: string;
|
|
26
|
+
repo: string;
|
|
27
|
+
number: number;
|
|
28
|
+
}
|
|
29
|
+
export declare const DEFAULT_WIRE_SCOPE: WireScope;
|
|
30
|
+
/** `owner/repo#number` for the default scope — the epic ref the harness binds
|
|
31
|
+
* the doorbell to. Kept in lockstep with {@link DEFAULT_WIRE_SCOPE}. */
|
|
32
|
+
export declare const DEFAULT_WIRE_EPIC_REF: string;
|
|
33
|
+
export interface GateOpenFixtureOverrides {
|
|
34
|
+
gateId?: string;
|
|
35
|
+
gateKey?: string;
|
|
36
|
+
gateType?: GateOpen['gateType'];
|
|
37
|
+
epicRef?: string;
|
|
38
|
+
issueRef?: string;
|
|
39
|
+
issueTitle?: string;
|
|
40
|
+
issueUrl?: string;
|
|
41
|
+
title?: string;
|
|
42
|
+
body?: string;
|
|
43
|
+
options?: GateOpen['options'];
|
|
44
|
+
allowFreeText?: boolean;
|
|
45
|
+
sessionId?: string;
|
|
46
|
+
askedAt?: string;
|
|
47
|
+
frameId?: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Build a `POST /cockpit/gates` body (Shape 1). Validated against
|
|
51
|
+
* `GateOpenSchema` before return so a builder that drifts from the transport
|
|
52
|
+
* contract throws at the call site.
|
|
53
|
+
*/
|
|
54
|
+
export declare function gateOpenFixture(overrides?: GateOpenFixtureOverrides): GateOpen;
|
|
55
|
+
export interface GateOutcomeFixtureOverrides {
|
|
56
|
+
gateId?: string;
|
|
57
|
+
outcome?: GateOutcome['outcome'];
|
|
58
|
+
detail?: string;
|
|
59
|
+
at?: string;
|
|
60
|
+
frameId?: string;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Build a `POST /cockpit/gates/:id/ack` body (Shape 2, the gate-outcome ACK).
|
|
64
|
+
* The route injects the path `:id` as `gateId`; the fixture carries a matching
|
|
65
|
+
* `gateId` so a direct POST with `body.gateId === :id` passes any equality guard.
|
|
66
|
+
*/
|
|
67
|
+
export declare function gateOutcomeFixture(overrides?: GateOutcomeFixtureOverrides): GateOutcome;
|
|
68
|
+
export interface AnswerLineFixtureOverrides {
|
|
69
|
+
deliveryId?: string;
|
|
70
|
+
gateId?: string;
|
|
71
|
+
gateKey?: string;
|
|
72
|
+
optionId?: string | null;
|
|
73
|
+
freeText?: string | null;
|
|
74
|
+
actor?: GateAnswer['actor'];
|
|
75
|
+
answeredAt?: string;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Build a gate-answer line (Shape 3, down-path). This is the single wire shape
|
|
79
|
+
* that flows peer/cloud → `POST /cockpit/answers` → answers file → doorbell
|
|
80
|
+
* tail (FR-005) — the seam the #1024 harness exists to pin. Validated against
|
|
81
|
+
* `GateAnswerSchema`.
|
|
82
|
+
*/
|
|
83
|
+
export declare function answerLineFixture(overrides?: AnswerLineFixtureOverrides): GateAnswer;
|
|
84
|
+
//# sourceMappingURL=wire-fixtures.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wire-fixtures.d.ts","sourceRoot":"","sources":["../../src/gates/wire-fixtures.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAML,KAAK,UAAU,EACf,KAAK,QAAQ,EACb,KAAK,WAAW,EACjB,MAAM,aAAa,CAAC;AAGrB;;6DAE6D;AAC7D,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,kBAAkB,EAAE,SAIhC,CAAC;AAEF;yEACyE;AACzE,eAAO,MAAM,qBAAqB,QAAmD,CAAC;AAiBtF,MAAM,WAAW,wBAAwB;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC9B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,SAAS,GAAE,wBAA6B,GAAG,QAAQ,CAwBlF;AAED,MAAM,WAAW,2BAA2B;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,GAAE,2BAAgC,GAAG,WAAW,CAU3F;AAED,MAAM,WAAW,0BAA0B;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,GAAE,0BAA+B,GAAG,UAAU,CAYxF"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire-envelope fixture builders for the cluster-side transport contracts
|
|
3
|
+
* (#1024). These build the exact JSON frames that cross the cluster-side wire,
|
|
4
|
+
* all validated against the canonical schemas in `./schema.ts`:
|
|
5
|
+
*
|
|
6
|
+
* - `gateOpenFixture()` → body of `POST /cockpit/gates` (`GateOpenSchema`, Shape 1)
|
|
7
|
+
* - `gateOutcomeFixture()` → body of `POST /cockpit/gates/:id/ack` (`GateOutcomeSchema`, Shape 2 — THE ACK)
|
|
8
|
+
* - `answerLineFixture()` → body of `POST /cockpit/answers` AND the NDJSON
|
|
9
|
+
* line the doorbell tails (`GateAnswerSchema`, Shape 3)
|
|
10
|
+
*
|
|
11
|
+
* The #1024 integration harness single-sources every wire body through these
|
|
12
|
+
* builders (FR-009 / SC-004) so a drift in the transport shape fails the
|
|
13
|
+
* harness in one place rather than silently passing an inline literal.
|
|
14
|
+
*
|
|
15
|
+
* NB: the frozen frames are FLAT with a `type` discriminator ('gate-open' |
|
|
16
|
+
* 'gate-outcome' | 'gate-answer'); there is no `kind`, no `scope` wrapper and no
|
|
17
|
+
* top-level `generation` (generation is folded into `gateKey`). gateId/gateKey
|
|
18
|
+
* are DERIVED, so the default frame carries a real 24-hex gateId.
|
|
19
|
+
*/
|
|
20
|
+
import { GateAnswerSchema, GateOpenSchema, GateOutcomeSchema, deriveGateId, deriveGateKey, } from './schema.js';
|
|
21
|
+
import { issueRefToString } from './schemas.js';
|
|
22
|
+
export const DEFAULT_WIRE_SCOPE = {
|
|
23
|
+
owner: 'generacy-ai',
|
|
24
|
+
repo: 'generacy',
|
|
25
|
+
number: 1024,
|
|
26
|
+
};
|
|
27
|
+
/** `owner/repo#number` for the default scope — the epic ref the harness binds
|
|
28
|
+
* the doorbell to. Kept in lockstep with {@link DEFAULT_WIRE_SCOPE}. */
|
|
29
|
+
export const DEFAULT_WIRE_EPIC_REF = issueRefToString(DEFAULT_WIRE_SCOPE);
|
|
30
|
+
const DEFAULT_GATE_TYPE = 'phase-queue';
|
|
31
|
+
const DEFAULT_GENERATION = '2';
|
|
32
|
+
const DEFAULT_GATE_KEY = deriveGateKey(DEFAULT_WIRE_EPIC_REF, DEFAULT_GATE_TYPE, DEFAULT_GENERATION);
|
|
33
|
+
const DEFAULT_GATE_ID = deriveGateId(DEFAULT_GATE_KEY);
|
|
34
|
+
const DEFAULT_SESSION_ID = 'sess-1024-default';
|
|
35
|
+
const DEFAULT_ASKED_AT = '2026-07-21T12:00:00.000Z';
|
|
36
|
+
const DEFAULT_ANSWERED_AT = '2026-07-21T12:05:00.000Z';
|
|
37
|
+
const DEFAULT_OUTCOME_AT = '2026-07-21T12:05:01.000Z';
|
|
38
|
+
const DEFAULT_ACTOR = {
|
|
39
|
+
userId: 'user-1024',
|
|
40
|
+
email: 'operator@example.com',
|
|
41
|
+
displayName: 'Operator One',
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Build a `POST /cockpit/gates` body (Shape 1). Validated against
|
|
45
|
+
* `GateOpenSchema` before return so a builder that drifts from the transport
|
|
46
|
+
* contract throws at the call site.
|
|
47
|
+
*/
|
|
48
|
+
export function gateOpenFixture(overrides = {}) {
|
|
49
|
+
const body = {
|
|
50
|
+
type: 'gate-open',
|
|
51
|
+
gateId: overrides.gateId ?? DEFAULT_GATE_ID,
|
|
52
|
+
gateKey: overrides.gateKey ?? DEFAULT_GATE_KEY,
|
|
53
|
+
gateType: overrides.gateType ?? DEFAULT_GATE_TYPE,
|
|
54
|
+
epicRef: overrides.epicRef ?? DEFAULT_WIRE_EPIC_REF,
|
|
55
|
+
issueRef: overrides.issueRef ?? DEFAULT_WIRE_EPIC_REF,
|
|
56
|
+
issueTitle: overrides.issueTitle ?? 'Phase 2: cockpit remote gates',
|
|
57
|
+
issueUrl: overrides.issueUrl ??
|
|
58
|
+
`https://github.com/${DEFAULT_WIRE_SCOPE.owner}/${DEFAULT_WIRE_SCOPE.repo}/issues/${DEFAULT_WIRE_SCOPE.number}`,
|
|
59
|
+
title: overrides.title ?? 'Queue phase 2?',
|
|
60
|
+
body: overrides.body ?? 'Proceed with the next phase?',
|
|
61
|
+
options: overrides.options ?? [
|
|
62
|
+
{ id: 'proceed', label: 'Proceed', recommended: true },
|
|
63
|
+
{ id: 'hold', label: 'Hold' },
|
|
64
|
+
],
|
|
65
|
+
allowFreeText: overrides.allowFreeText ?? true,
|
|
66
|
+
sessionId: overrides.sessionId ?? DEFAULT_SESSION_ID,
|
|
67
|
+
askedAt: overrides.askedAt ?? DEFAULT_ASKED_AT,
|
|
68
|
+
...(overrides.frameId !== undefined ? { frameId: overrides.frameId } : {}),
|
|
69
|
+
};
|
|
70
|
+
return GateOpenSchema.parse(body);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Build a `POST /cockpit/gates/:id/ack` body (Shape 2, the gate-outcome ACK).
|
|
74
|
+
* The route injects the path `:id` as `gateId`; the fixture carries a matching
|
|
75
|
+
* `gateId` so a direct POST with `body.gateId === :id` passes any equality guard.
|
|
76
|
+
*/
|
|
77
|
+
export function gateOutcomeFixture(overrides = {}) {
|
|
78
|
+
const body = {
|
|
79
|
+
type: 'gate-outcome',
|
|
80
|
+
gateId: overrides.gateId ?? DEFAULT_GATE_ID,
|
|
81
|
+
outcome: overrides.outcome ?? 'applied',
|
|
82
|
+
...(overrides.detail !== undefined ? { detail: overrides.detail } : {}),
|
|
83
|
+
at: overrides.at ?? DEFAULT_OUTCOME_AT,
|
|
84
|
+
...(overrides.frameId !== undefined ? { frameId: overrides.frameId } : {}),
|
|
85
|
+
};
|
|
86
|
+
return GateOutcomeSchema.parse(body);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Build a gate-answer line (Shape 3, down-path). This is the single wire shape
|
|
90
|
+
* that flows peer/cloud → `POST /cockpit/answers` → answers file → doorbell
|
|
91
|
+
* tail (FR-005) — the seam the #1024 harness exists to pin. Validated against
|
|
92
|
+
* `GateAnswerSchema`.
|
|
93
|
+
*/
|
|
94
|
+
export function answerLineFixture(overrides = {}) {
|
|
95
|
+
const body = {
|
|
96
|
+
type: 'gate-answer',
|
|
97
|
+
gateId: overrides.gateId ?? DEFAULT_GATE_ID,
|
|
98
|
+
gateKey: overrides.gateKey ?? DEFAULT_GATE_KEY,
|
|
99
|
+
optionId: overrides.optionId !== undefined ? overrides.optionId : 'proceed',
|
|
100
|
+
freeText: overrides.freeText !== undefined ? overrides.freeText : null,
|
|
101
|
+
actor: overrides.actor ?? { ...DEFAULT_ACTOR },
|
|
102
|
+
answeredAt: overrides.answeredAt ?? DEFAULT_ANSWERED_AT,
|
|
103
|
+
deliveryId: overrides.deliveryId ?? 'dlv_1024_default',
|
|
104
|
+
};
|
|
105
|
+
return GateAnswerSchema.parse(body);
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=wire-fixtures.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wire-fixtures.js","sourceRoot":"","sources":["../../src/gates/wire-fixtures.ts"],"names":[],"mappings":"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"}
|