@company-semantics/contracts 79.2.0 → 80.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/api/generated-spec-hash.ts +2 -2
- package/src/api/generated.ts +6 -1
- package/src/source-sync/README.md +6 -3
- package/src/source-sync/__tests__/schemas.test.ts +16 -1
- package/src/source-sync/candidate-totals.ts +42 -0
- package/src/source-sync/index.ts +5 -0
- package/src/source-sync/schemas.ts +25 -1
package/package.json
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// AUTO-GENERATED — do not edit. Run pnpm generate:spec-hash to regenerate.
|
|
2
|
-
export const SPEC_HASH = '
|
|
3
|
-
export const SPEC_HASH_FULL = '
|
|
2
|
+
export const SPEC_HASH = 'c2954b6d06a9' as const;
|
|
3
|
+
export const SPEC_HASH_FULL = 'c2954b6d06a981632d4d61991aa61f16ee28485116ec66949fe08d64cbde4ceb' as const;
|
package/src/api/generated.ts
CHANGED
|
@@ -8653,6 +8653,7 @@ export interface components {
|
|
|
8653
8653
|
/** @enum {string} */
|
|
8654
8654
|
recommendedUse: "attached" | "direction_only" | "excluded";
|
|
8655
8655
|
use: ("attached" | "direction_only" | "excluded") | null;
|
|
8656
|
+
included: boolean;
|
|
8656
8657
|
treatmentUnresolved: boolean;
|
|
8657
8658
|
matchReason: string;
|
|
8658
8659
|
unreadableReason: ("unsupported_type" | "needs_ocr" | "unsupported_kind") | null;
|
|
@@ -8690,7 +8691,11 @@ export interface components {
|
|
|
8690
8691
|
};
|
|
8691
8692
|
}[];
|
|
8692
8693
|
withheldQuestionCount: number;
|
|
8693
|
-
|
|
8694
|
+
totals: {
|
|
8695
|
+
files: number;
|
|
8696
|
+
filesIncluded: number;
|
|
8697
|
+
filesNeedingChoice: number;
|
|
8698
|
+
};
|
|
8694
8699
|
scopes: {
|
|
8695
8700
|
scopeKey: string;
|
|
8696
8701
|
/** @enum {string} */
|
|
@@ -127,10 +127,13 @@ way. This directory holds that shared spelling.
|
|
|
127
127
|
- `SourceSyncDiscoveryRunResponseSchema` / `SourceSyncDiscoveryRunResponse` —
|
|
128
128
|
the discovery run started, and the workflow narrating it.
|
|
129
129
|
- `SourceSyncCandidateItemSchema` / `SourceSyncCandidateItem` — one source
|
|
130
|
-
proposed for one target document
|
|
130
|
+
proposed for one target document, with the server's `included`.
|
|
131
131
|
- `SourceSyncCandidateSetResponseSchema` / `SourceSyncCandidateSetResponse` —
|
|
132
|
-
the draft set under review: its revision, items, presented questions
|
|
133
|
-
cost estimate.
|
|
132
|
+
the draft set under review: its revision, items, presented questions,
|
|
133
|
+
distinct-file `totals` and cost estimate.
|
|
134
|
+
- `SourceSyncCandidateTotalsSchema` / `SourceSyncCandidateTotals` and
|
|
135
|
+
`candidateTotalsOf(items)` — THE file count: distinct `sourceId`, never lines
|
|
136
|
+
(ADR-CONTRACTS-195).
|
|
134
137
|
- `SourceSyncCandidateItemPatchSchema` / `SourceSyncCandidateItemPatch` — one
|
|
135
138
|
edit to one candidate item (use, class or target); never empty.
|
|
136
139
|
- `SourceSyncAddCandidateRequestSchema` / `SourceSyncAddCandidateRequest` —
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
import { describe, expect, it } from "vitest";
|
|
17
17
|
import {
|
|
18
|
+
candidateTotalsOf,
|
|
18
19
|
SourceSyncCandidateItemSchema,
|
|
19
20
|
SourceSyncCandidateSetResponseSchema,
|
|
20
21
|
SourceSyncDiscoveryRunResponseSchema,
|
|
@@ -50,6 +51,7 @@ function candidateItem(overrides: Record<string, unknown> = {}) {
|
|
|
50
51
|
audienceFit: "fits",
|
|
51
52
|
recommendedUse: "direction_only",
|
|
52
53
|
use: null,
|
|
54
|
+
included: true,
|
|
53
55
|
treatmentUnresolved: false,
|
|
54
56
|
matchReason: "A board deck for the current quarter.",
|
|
55
57
|
unreadableReason: null,
|
|
@@ -96,7 +98,7 @@ function candidateSet(overrides: Record<string, unknown> = {}) {
|
|
|
96
98
|
items: [candidateItem()],
|
|
97
99
|
questions: [presentedQuestion()],
|
|
98
100
|
withheldQuestionCount: 0,
|
|
99
|
-
|
|
101
|
+
totals: { files: 1, filesIncluded: 1, filesNeedingChoice: 0 },
|
|
100
102
|
scopes: [],
|
|
101
103
|
estimate: {
|
|
102
104
|
lowMicroUsd: "250000",
|
|
@@ -279,3 +281,16 @@ describe("SourceSyncDiscoveryRunResponseSchema", () => {
|
|
|
279
281
|
).toBe(true);
|
|
280
282
|
});
|
|
281
283
|
});
|
|
284
|
+
|
|
285
|
+
describe("candidateTotalsOf", () => {
|
|
286
|
+
it("counts distinct files, never lines", () => {
|
|
287
|
+
expect(
|
|
288
|
+
candidateTotalsOf([
|
|
289
|
+
{ sourceId: "a", included: true, treatmentUnresolved: true },
|
|
290
|
+
{ sourceId: "a", included: true, treatmentUnresolved: false },
|
|
291
|
+
{ sourceId: "b", included: false, treatmentUnresolved: true },
|
|
292
|
+
{ sourceId: "c", included: true, treatmentUnresolved: false },
|
|
293
|
+
]),
|
|
294
|
+
).toEqual({ files: 3, filesIncluded: 2, filesNeedingChoice: 1 });
|
|
295
|
+
});
|
|
296
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE ONE FILE COUNT for a candidate review: distinct `sourceId`, never lines.
|
|
3
|
+
*
|
|
4
|
+
* A file routed to two company.md documents is two lines and ONE file. The
|
|
5
|
+
* server computes `SourceSyncCandidateSetResponse.totals` with this over every
|
|
6
|
+
* line the reader may see; a client that overlays an optimistic edit recomputes
|
|
7
|
+
* with the same function, so no surface counts "files" its own way.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type {
|
|
11
|
+
SourceSyncCandidateItem,
|
|
12
|
+
SourceSyncCandidateTotals,
|
|
13
|
+
} from "./schemas";
|
|
14
|
+
|
|
15
|
+
/** The item facts the count reads. */
|
|
16
|
+
export type CandidateTotalsInput = Pick<
|
|
17
|
+
SourceSyncCandidateItem,
|
|
18
|
+
"sourceId" | "included" | "treatmentUnresolved"
|
|
19
|
+
>;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Included when any of the file's lines is; in need of a choice when any
|
|
23
|
+
* included line's treatment is unresolved.
|
|
24
|
+
*/
|
|
25
|
+
export function candidateTotalsOf(
|
|
26
|
+
items: readonly CandidateTotalsInput[],
|
|
27
|
+
): SourceSyncCandidateTotals {
|
|
28
|
+
const files = new Set<string>();
|
|
29
|
+
const included = new Set<string>();
|
|
30
|
+
const needingChoice = new Set<string>();
|
|
31
|
+
for (const item of items) {
|
|
32
|
+
files.add(item.sourceId);
|
|
33
|
+
if (!item.included) continue;
|
|
34
|
+
included.add(item.sourceId);
|
|
35
|
+
if (item.treatmentUnresolved) needingChoice.add(item.sourceId);
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
files: files.size,
|
|
39
|
+
filesIncluded: included.size,
|
|
40
|
+
filesNeedingChoice: needingChoice.size,
|
|
41
|
+
};
|
|
42
|
+
}
|
package/src/source-sync/index.ts
CHANGED
|
@@ -48,6 +48,7 @@ export type {
|
|
|
48
48
|
SourceSyncDiscoveryRunResponse,
|
|
49
49
|
SourceSyncCandidateItem,
|
|
50
50
|
SourceSyncCandidateSetResponse,
|
|
51
|
+
SourceSyncCandidateTotals,
|
|
51
52
|
SourceSyncCandidateItemPatch,
|
|
52
53
|
SourceSyncAddCandidateRequest,
|
|
53
54
|
SourceSyncApproveRequest,
|
|
@@ -69,6 +70,7 @@ export {
|
|
|
69
70
|
SourceSyncDiscoveryRunResponseSchema,
|
|
70
71
|
SourceSyncCandidateItemSchema,
|
|
71
72
|
SourceSyncCandidateSetResponseSchema,
|
|
73
|
+
SourceSyncCandidateTotalsSchema,
|
|
72
74
|
SourceSyncCandidateItemPatchSchema,
|
|
73
75
|
SourceSyncAddCandidateRequestSchema,
|
|
74
76
|
SourceSyncApproveRequestSchema,
|
|
@@ -139,3 +141,6 @@ export {
|
|
|
139
141
|
SourceSyncReachUpgradeRequestSchema,
|
|
140
142
|
SourceSyncReachUpgradeResponseSchema,
|
|
141
143
|
} from "./reach";
|
|
144
|
+
|
|
145
|
+
export type { CandidateTotalsInput } from "./candidate-totals";
|
|
146
|
+
export { candidateTotalsOf } from "./candidate-totals";
|
|
@@ -118,6 +118,12 @@ export const SourceSyncCandidateItemSchema = z.object({
|
|
|
118
118
|
recommendedUse: z.enum(SOURCE_USES),
|
|
119
119
|
/** What the person has chosen; null until they (or an accepted default) decide. */
|
|
120
120
|
use: z.enum(SOURCE_USES).nullable(),
|
|
121
|
+
/**
|
|
122
|
+
* Whether this line is in the set that approval would land — the SERVER's
|
|
123
|
+
* answer, never derived from `use`. A decoy, a series' history or a line a
|
|
124
|
+
* person left out is false while its `use` is still null.
|
|
125
|
+
*/
|
|
126
|
+
included: z.boolean(),
|
|
121
127
|
/** True while a `widens` item — or one whose fit is not computed yet — has no person-chosen use: approval is refused until none remain. */
|
|
122
128
|
treatmentUnresolved: z.boolean(),
|
|
123
129
|
/** Product-owned copy saying why this file was proposed. Never model-authored prose. */
|
|
@@ -128,6 +134,16 @@ export const SourceSyncCandidateItemSchema = z.object({
|
|
|
128
134
|
.nullable(),
|
|
129
135
|
});
|
|
130
136
|
|
|
137
|
+
/** Distinct-file totals over every line of a candidate set the caller may see. */
|
|
138
|
+
export const SourceSyncCandidateTotalsSchema = z.object({
|
|
139
|
+
/** Files in the review: at least one line, included or left out. */
|
|
140
|
+
files: z.number().int().min(0),
|
|
141
|
+
/** Files with at least one included line. */
|
|
142
|
+
filesIncluded: z.number().int().min(0),
|
|
143
|
+
/** Files with at least one included line whose treatment is unresolved. */
|
|
144
|
+
filesNeedingChoice: z.number().int().min(0),
|
|
145
|
+
});
|
|
146
|
+
|
|
131
147
|
/** The draft set under review. `revision` moves on every edit and is echoed on approve. */
|
|
132
148
|
export const SourceSyncCandidateSetResponseSchema = z.object({
|
|
133
149
|
setId: z.string().uuid(),
|
|
@@ -138,7 +154,12 @@ export const SourceSyncCandidateSetResponseSchema = z.object({
|
|
|
138
154
|
/** The low-confidence routing, class and treatment questions, as presented. */
|
|
139
155
|
questions: z.array(DecisionQuestionPresentationSchema).max(50),
|
|
140
156
|
withheldQuestionCount: z.number().int().min(0),
|
|
141
|
-
|
|
157
|
+
/**
|
|
158
|
+
* The review's top-level totals, counted by DISTINCT FILE (`sourceId`) — never
|
|
159
|
+
* by line. A file routed to two documents is two lines and one file. Every
|
|
160
|
+
* surface reads these rather than counting `items`, which may be capped.
|
|
161
|
+
*/
|
|
162
|
+
totals: SourceSyncCandidateTotalsSchema,
|
|
142
163
|
/** Every scope of the set the caller may see, and where its approval stands. */
|
|
143
164
|
scopes: z.array(SourceSyncScopeApprovalProjectionSchema).max(500),
|
|
144
165
|
/** A RANGE, and the cap that is the promise. Null until the estimator has run. */
|
|
@@ -378,6 +399,9 @@ export type SourceSyncCandidateItem = z.infer<
|
|
|
378
399
|
export type SourceSyncCandidateSetResponse = z.infer<
|
|
379
400
|
typeof SourceSyncCandidateSetResponseSchema
|
|
380
401
|
>;
|
|
402
|
+
export type SourceSyncCandidateTotals = z.infer<
|
|
403
|
+
typeof SourceSyncCandidateTotalsSchema
|
|
404
|
+
>;
|
|
381
405
|
export type SourceSyncCandidateItemPatch = z.infer<
|
|
382
406
|
typeof SourceSyncCandidateItemPatchSchema
|
|
383
407
|
>;
|