@company-semantics/contracts 101.0.0 → 101.1.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/package.json
CHANGED
package/src/schedules/README.md
CHANGED
|
@@ -23,6 +23,8 @@ ledger and reconciles) can never disagree about a slot.
|
|
|
23
23
|
`contentHash` is computed over.
|
|
24
24
|
- Response schemas only; request bodies live in the backend beside their routes
|
|
25
25
|
(ScheduleTickRequest is a type, not a schema).
|
|
26
|
+
- A re-prove grants exactly one extra attempt for a named execution; the route
|
|
27
|
+
only grants, the backend clock dispatches.
|
|
26
28
|
- Pure: no clock reads, no I/O, only `zod`.
|
|
27
29
|
|
|
28
30
|
## Dependencies
|
|
@@ -64,6 +66,9 @@ ledger and reconciles) can never disagree about a slot.
|
|
|
64
66
|
- `SCHEDULE_MODES` — off: GitHub cron only, clock ignores it. shadow: clock plans, never dispatches. live: clock dispatches…
|
|
65
67
|
- `SCHEDULE_OUTPUT_VERIFIERS` — Closed catalog. v0 has one verifier.
|
|
66
68
|
- `SCHEDULE_REGISTRY_SCHEMA_VERSION`
|
|
69
|
+
- `SCHEDULE_REPROVE_PATH` — The operator re-prove route (control ADR slug operator-schedule-reprove).
|
|
70
|
+
- `SCHEDULE_REPROVE_REASON_MAX_LENGTH` — Upper bound of a re-prove reason (operator prose, kept for audit only).
|
|
71
|
+
- `SCHEDULE_REPROVE_REFUSALS` — Why a re-prove was refused.
|
|
67
72
|
- `SCHEDULE_RUN_CONCLUSIONS`
|
|
68
73
|
- `SCHEDULE_RUN_NAME` — The exact `run-name:` a registered workflow declares, so displaytitle = executionid#attempt.
|
|
69
74
|
- `SCHEDULE_SEVERITIES`
|
|
@@ -91,6 +96,10 @@ ledger and reconciles) can never disagree about a slot.
|
|
|
91
96
|
- `ScheduleOutputVerifier` _(type)_
|
|
92
97
|
- `ScheduleRegistrySnapshot` _(type)_
|
|
93
98
|
- `ScheduleRegistrySnapshotSchema`
|
|
99
|
+
- `ScheduleReproveRefusal` _(type)_
|
|
100
|
+
- `ScheduleReproveRequest` _(type)_ — Re-prove request body, as a TYPE only: the backend binds its zod schema to it with `satisfies…
|
|
101
|
+
- `ScheduleReproveResponse` _(type)_
|
|
102
|
+
- `ScheduleReproveResponseSchema` — `granted`: the clock will dispatch `<executionId>#<grantedAttempt>` on its next pass.
|
|
94
103
|
- `ScheduleRunConclusion` _(type)_
|
|
95
104
|
- `ScheduleSeverity` _(type)_
|
|
96
105
|
- `ScheduleTickRequest` _(type)_ — Tick request body, as a TYPE only: request schemas stay in the backend beside the route (contracts…
|
|
@@ -5,9 +5,12 @@ import {
|
|
|
5
5
|
SCHEDULE_METRIC_TICK,
|
|
6
6
|
SCHEDULE_METRIC_TICK_SOURCE_DIMENSION,
|
|
7
7
|
SCHEDULE_METRIC_ENVIRONMENT_DIMENSION,
|
|
8
|
+
SCHEDULE_REPROVE_PATH,
|
|
9
|
+
SCHEDULE_REPROVE_REFUSALS,
|
|
8
10
|
SCHEDULE_TICK_PATH,
|
|
9
11
|
ScheduleClaimResponseSchema,
|
|
10
12
|
ScheduleFinishResponseSchema,
|
|
13
|
+
ScheduleReproveResponseSchema,
|
|
11
14
|
ScheduleTickResponseSchema,
|
|
12
15
|
} from "../api";
|
|
13
16
|
|
|
@@ -69,4 +72,52 @@ describe("schedules api responses", () => {
|
|
|
69
72
|
"environment",
|
|
70
73
|
]);
|
|
71
74
|
});
|
|
75
|
+
|
|
76
|
+
it("grants a re-prove for a named attempt", () => {
|
|
77
|
+
expect(SCHEDULE_REPROVE_PATH).toBe("/api/schedules/executions/reprove");
|
|
78
|
+
expect(
|
|
79
|
+
ScheduleReproveResponseSchema.safeParse({
|
|
80
|
+
outcome: "granted",
|
|
81
|
+
executionId: "control-pin-audit/2026-10-12T15:00:00Z",
|
|
82
|
+
grantedAttempt: 4,
|
|
83
|
+
incidentKey:
|
|
84
|
+
"schedule:execution:control-pin-audit/2026-10-12T15:00:00Z",
|
|
85
|
+
incidentNoted: true,
|
|
86
|
+
}).success,
|
|
87
|
+
).toBe(true);
|
|
88
|
+
expect(
|
|
89
|
+
ScheduleReproveResponseSchema.safeParse({
|
|
90
|
+
outcome: "granted",
|
|
91
|
+
executionId: "control-pin-audit/2026-10-12T15:00:00Z",
|
|
92
|
+
grantedAttempt: 1,
|
|
93
|
+
incidentKey: null,
|
|
94
|
+
incidentNoted: false,
|
|
95
|
+
}).success,
|
|
96
|
+
).toBe(false);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("refuses a re-prove with a closed reason", () => {
|
|
100
|
+
expect(SCHEDULE_REPROVE_REFUSALS).toEqual([
|
|
101
|
+
"unknown_execution",
|
|
102
|
+
"schedule_not_live",
|
|
103
|
+
"not_exhausted",
|
|
104
|
+
"not_reprovable",
|
|
105
|
+
"schedule_busy",
|
|
106
|
+
"grant_lost",
|
|
107
|
+
]);
|
|
108
|
+
expect(
|
|
109
|
+
ScheduleReproveResponseSchema.safeParse({
|
|
110
|
+
outcome: "refused",
|
|
111
|
+
executionId: "x/2026-10-12T15:00:00Z",
|
|
112
|
+
refusal: "not_exhausted",
|
|
113
|
+
}).success,
|
|
114
|
+
).toBe(true);
|
|
115
|
+
expect(
|
|
116
|
+
ScheduleReproveResponseSchema.safeParse({
|
|
117
|
+
outcome: "refused",
|
|
118
|
+
executionId: "x/2026-10-12T15:00:00Z",
|
|
119
|
+
refusal: "because",
|
|
120
|
+
}).success,
|
|
121
|
+
).toBe(false);
|
|
122
|
+
});
|
|
72
123
|
});
|
|
@@ -19,6 +19,9 @@ describe("schedules exports", () => {
|
|
|
19
19
|
"ScheduleClaimResponseSchema",
|
|
20
20
|
"SCHEDULE_TICK_PATH",
|
|
21
21
|
"SCHEDULE_METRICS_NAMESPACE",
|
|
22
|
+
"SCHEDULE_REPROVE_PATH",
|
|
23
|
+
"SCHEDULE_REPROVE_REFUSALS",
|
|
24
|
+
"ScheduleReproveResponseSchema",
|
|
22
25
|
]) {
|
|
23
26
|
expect(root).toHaveProperty(name);
|
|
24
27
|
}
|
package/src/schedules/api.ts
CHANGED
|
@@ -137,3 +137,76 @@ export const ScheduleTickResponseSchema = z
|
|
|
137
137
|
})
|
|
138
138
|
.strict();
|
|
139
139
|
export type ScheduleTickResponse = z.infer<typeof ScheduleTickResponseSchema>;
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* The operator re-prove route (control ADR slug operator-schedule-reprove).
|
|
143
|
+
* Its only caller is control's schedules-reprove.yml on main, authenticated by
|
|
144
|
+
* that job's GitHub OIDC token; an operator starts the workflow with
|
|
145
|
+
* `pnpm schedules:reprove <scheduleId> <slot> --reason "…"`. The route only
|
|
146
|
+
* GRANTS one extra attempt for a named execution; the backend clock dispatches
|
|
147
|
+
* it through the normal claim-before-call path.
|
|
148
|
+
*/
|
|
149
|
+
export const SCHEDULE_REPROVE_PATH = "/api/schedules/executions/reprove";
|
|
150
|
+
|
|
151
|
+
/** Upper bound of a re-prove reason (operator prose, kept for audit only). */
|
|
152
|
+
export const SCHEDULE_REPROVE_REASON_MAX_LENGTH = 500;
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Re-prove request body, as a TYPE only: the backend binds its zod schema to it
|
|
156
|
+
* with `satisfies z.ZodType<ScheduleReproveRequest>`. `executionId` names the
|
|
157
|
+
* exhausted slot (`<schedule_id>/<slot>`); `reason` (1..500 chars) says why the
|
|
158
|
+
* operator believes the cause is fixed.
|
|
159
|
+
*/
|
|
160
|
+
export interface ScheduleReproveRequest {
|
|
161
|
+
readonly executionId: string;
|
|
162
|
+
readonly reason: string;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Why a re-prove was refused. Closed.
|
|
167
|
+
* - unknown_execution: no ledger row for that execution id.
|
|
168
|
+
* - schedule_not_live: not in the active registry, or its mode is not live.
|
|
169
|
+
* - not_exhausted: the clock still owns the slot (attempts remain and effects
|
|
170
|
+
* allow re-execution, a grant is unspent, or admission has not timed out).
|
|
171
|
+
* - not_reprovable: succeeded, settled, due, started, or failed only its
|
|
172
|
+
* output verification.
|
|
173
|
+
* - schedule_busy: another execution of the same schedule is in flight.
|
|
174
|
+
* - grant_lost: a concurrent grant or dispatch changed the row first.
|
|
175
|
+
*/
|
|
176
|
+
export const SCHEDULE_REPROVE_REFUSALS = [
|
|
177
|
+
"unknown_execution",
|
|
178
|
+
"schedule_not_live",
|
|
179
|
+
"not_exhausted",
|
|
180
|
+
"not_reprovable",
|
|
181
|
+
"schedule_busy",
|
|
182
|
+
"grant_lost",
|
|
183
|
+
] as const;
|
|
184
|
+
export type ScheduleReproveRefusal = (typeof SCHEDULE_REPROVE_REFUSALS)[number];
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* `granted`: the clock will dispatch `<executionId>#<grantedAttempt>` on its
|
|
188
|
+
* next pass. `incidentKey` is the open execution/admission incident naming the
|
|
189
|
+
* slot (null when none); `incidentNoted` says whether the grant was commented
|
|
190
|
+
* on its issue (a failed comment never revokes the grant).
|
|
191
|
+
*/
|
|
192
|
+
export const ScheduleReproveResponseSchema = z.discriminatedUnion("outcome", [
|
|
193
|
+
z
|
|
194
|
+
.object({
|
|
195
|
+
outcome: z.literal("granted"),
|
|
196
|
+
executionId: z.string(),
|
|
197
|
+
grantedAttempt: z.number().int().min(2),
|
|
198
|
+
incidentKey: z.string().nullable(),
|
|
199
|
+
incidentNoted: z.boolean(),
|
|
200
|
+
})
|
|
201
|
+
.strict(),
|
|
202
|
+
z
|
|
203
|
+
.object({
|
|
204
|
+
outcome: z.literal("refused"),
|
|
205
|
+
executionId: z.string(),
|
|
206
|
+
refusal: z.enum(SCHEDULE_REPROVE_REFUSALS),
|
|
207
|
+
})
|
|
208
|
+
.strict(),
|
|
209
|
+
]);
|
|
210
|
+
export type ScheduleReproveResponse = z.infer<
|
|
211
|
+
typeof ScheduleReproveResponseSchema
|
|
212
|
+
>;
|
package/src/schedules/index.ts
CHANGED
|
@@ -108,6 +108,10 @@ export {
|
|
|
108
108
|
ScheduleFinishResponseSchema,
|
|
109
109
|
ScheduleTickResponseSchema,
|
|
110
110
|
SCHEDULE_TICK_PATH,
|
|
111
|
+
SCHEDULE_REPROVE_PATH,
|
|
112
|
+
SCHEDULE_REPROVE_REASON_MAX_LENGTH,
|
|
113
|
+
SCHEDULE_REPROVE_REFUSALS,
|
|
114
|
+
ScheduleReproveResponseSchema,
|
|
111
115
|
SCHEDULE_METRICS_NAMESPACE,
|
|
112
116
|
SCHEDULE_METRIC_TICK,
|
|
113
117
|
SCHEDULE_METRIC_TICK_SOURCE_DIMENSION,
|
|
@@ -121,4 +125,7 @@ export type {
|
|
|
121
125
|
ScheduleFinishResponse,
|
|
122
126
|
ScheduleTickResponse,
|
|
123
127
|
ScheduleTickRequest,
|
|
128
|
+
ScheduleReproveRequest,
|
|
129
|
+
ScheduleReproveRefusal,
|
|
130
|
+
ScheduleReproveResponse,
|
|
124
131
|
} from "./api";
|