@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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@company-semantics/contracts",
3
- "version": "101.0.0",
3
+ "version": "101.1.0",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
@@ -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
  }
@@ -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
+ >;
@@ -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";