@company-semantics/contracts 89.2.0 → 90.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 +3 -2
- package/src/api/generated-spec-hash.ts +2 -2
- package/src/api/generated.ts +83 -1
- package/src/source-sync/README.md +95 -5
- package/src/source-sync/__tests__/attention-evidence.test.ts +96 -0
- package/src/source-sync/__tests__/barrel.test.ts +39 -0
- package/src/source-sync/__tests__/enumeration.test.ts +160 -0
- package/src/source-sync/__tests__/schemas.test.ts +223 -0
- package/src/source-sync/__tests__/vocabulary.test.ts +104 -5
- package/src/source-sync/attention-evidence.ts +93 -0
- package/src/source-sync/candidate-item.ts +25 -0
- package/src/source-sync/enumeration.ts +152 -0
- package/src/source-sync/index.ts +35 -1
- package/src/source-sync/relevance.ts +85 -11
- package/src/source-sync/vocabulary.ts +37 -1
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Index-first discovery's ENUMERATION vocabulary (control ADR
|
|
3
|
+
* index-first-operating-knowledge-discovery; INV-SOURCESYNC-PARTIAL-ENUMERATION-IS-UNKNOWN).
|
|
4
|
+
*
|
|
5
|
+
* A discovery run first enumerates every source reachable through the connection,
|
|
6
|
+
* root by root (the person's own corpus, each shared drive, the domain corpus).
|
|
7
|
+
* How completely it did so is a closed answer that separates OUR ceiling from the
|
|
8
|
+
* PROVIDER's incompleteness, so a partial enumeration can never read as an index of
|
|
9
|
+
* the corpus: only `complete` lets a surface say "full index". Anything else means
|
|
10
|
+
* absence is UNKNOWN, never negative evidence.
|
|
11
|
+
*
|
|
12
|
+
* Stage counters name what each count did: enumerated / metadata-eligible / T0-scored
|
|
13
|
+
* are metadata only; attended / peeked / classified involve a model; shown / retained
|
|
14
|
+
* are outcomes. `filesEnumerated = 100000` with `local_budget_truncated` never reads as
|
|
15
|
+
* "indexed every file".
|
|
16
|
+
*/
|
|
17
|
+
import { z } from "zod";
|
|
18
|
+
import { IsoDateTime } from "../api/primitives";
|
|
19
|
+
|
|
20
|
+
/** How completely a run (or one root) was enumerated. */
|
|
21
|
+
export const ENUMERATION_COMPLETENESS = [
|
|
22
|
+
"complete",
|
|
23
|
+
"local_budget_truncated",
|
|
24
|
+
"provider_incomplete",
|
|
25
|
+
"both",
|
|
26
|
+
] as const;
|
|
27
|
+
export type EnumerationCompleteness = (typeof ENUMERATION_COMPLETENESS)[number];
|
|
28
|
+
|
|
29
|
+
/** Which corpus a root is: the connected person's, one shared drive, or the domain. */
|
|
30
|
+
export const ENUMERATION_ROOT_KINDS = [
|
|
31
|
+
"user",
|
|
32
|
+
"shared_drive",
|
|
33
|
+
"domain",
|
|
34
|
+
] as const;
|
|
35
|
+
export type EnumerationRootKind = (typeof ENUMERATION_ROOT_KINDS)[number];
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* PURE: one completeness for many roots. Our ceiling anywhere and the provider's
|
|
39
|
+
* incompleteness anywhere combine to `both`; only every root complete is `complete`.
|
|
40
|
+
*/
|
|
41
|
+
export function combineEnumerationCompleteness(
|
|
42
|
+
statuses: readonly EnumerationCompleteness[],
|
|
43
|
+
): EnumerationCompleteness {
|
|
44
|
+
const local = statuses.some(
|
|
45
|
+
(s) => s === "local_budget_truncated" || s === "both",
|
|
46
|
+
);
|
|
47
|
+
const provider = statuses.some(
|
|
48
|
+
(s) => s === "provider_incomplete" || s === "both",
|
|
49
|
+
);
|
|
50
|
+
if (local && provider) return "both";
|
|
51
|
+
if (local) return "local_budget_truncated";
|
|
52
|
+
if (provider) return "provider_incomplete";
|
|
53
|
+
return "complete";
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const MS = (iso: string): number => Date.parse(iso);
|
|
57
|
+
|
|
58
|
+
/** A modified-time range the sampler did not enumerate. */
|
|
59
|
+
export const EnumerationSkippedRangeSchema = z
|
|
60
|
+
.object({ from: IsoDateTime, to: IsoDateTime })
|
|
61
|
+
.refine((r) => MS(r.from) <= MS(r.to), {
|
|
62
|
+
message: "a skipped range ends no earlier than it starts",
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
/** How far one root's enumeration got. Counts, times and provider ids only — never a name. */
|
|
66
|
+
export const RootCoverageSchema = z
|
|
67
|
+
.object({
|
|
68
|
+
rootKind: z.enum(ENUMERATION_ROOT_KINDS),
|
|
69
|
+
/** The shared drive's provider id; null for the user and domain corpora. */
|
|
70
|
+
rootId: z.string().min(1).max(128).nullable(),
|
|
71
|
+
status: z.enum(ENUMERATION_COMPLETENESS),
|
|
72
|
+
enumeratedCount: z.number().int().min(0),
|
|
73
|
+
/** Null exactly when nothing was enumerated under the root. */
|
|
74
|
+
observedOldestModifiedTime: IsoDateTime.nullable(),
|
|
75
|
+
observedNewestModifiedTime: IsoDateTime.nullable(),
|
|
76
|
+
skippedRanges: z.array(EnumerationSkippedRangeSchema).max(16),
|
|
77
|
+
})
|
|
78
|
+
.superRefine((root, ctx) => {
|
|
79
|
+
if ((root.rootId !== null) !== (root.rootKind === "shared_drive")) {
|
|
80
|
+
ctx.addIssue({
|
|
81
|
+
code: "custom",
|
|
82
|
+
message: "a root id names exactly a shared drive",
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
if (root.status === "complete" && root.skippedRanges.length > 0) {
|
|
86
|
+
ctx.addIssue({
|
|
87
|
+
code: "custom",
|
|
88
|
+
message: "a complete root skips nothing",
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
const empty = root.enumeratedCount === 0;
|
|
92
|
+
const timesAbsent =
|
|
93
|
+
root.observedOldestModifiedTime === null &&
|
|
94
|
+
root.observedNewestModifiedTime === null;
|
|
95
|
+
const timesPresent =
|
|
96
|
+
root.observedOldestModifiedTime !== null &&
|
|
97
|
+
root.observedNewestModifiedTime !== null;
|
|
98
|
+
if (empty ? !timesAbsent : !timesPresent) {
|
|
99
|
+
ctx.addIssue({
|
|
100
|
+
code: "custom",
|
|
101
|
+
message:
|
|
102
|
+
"observed modified times are present exactly when the root enumerated a file",
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
if (
|
|
106
|
+
timesPresent &&
|
|
107
|
+
MS(root.observedOldestModifiedTime as string) >
|
|
108
|
+
MS(root.observedNewestModifiedTime as string)
|
|
109
|
+
) {
|
|
110
|
+
ctx.addIssue({
|
|
111
|
+
code: "custom",
|
|
112
|
+
message: "the oldest observed time is not after the newest",
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
export type RootCoverage = z.infer<typeof RootCoverageSchema>;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* A run's stage counters. Each narrows the one before it:
|
|
120
|
+
* enumerated >= metadata-eligible >= T0-scored >= T1-attended >= peeked;
|
|
121
|
+
* T0-scored >= classified; T0-scored >= retained >= shown.
|
|
122
|
+
*/
|
|
123
|
+
export const DiscoveryStageCountersSchema = z
|
|
124
|
+
.object({
|
|
125
|
+
filesEnumerated: z.number().int().min(0),
|
|
126
|
+
filesMetadataEligible: z.number().int().min(0),
|
|
127
|
+
filesT0Scored: z.number().int().min(0),
|
|
128
|
+
filesT1Attended: z.number().int().min(0),
|
|
129
|
+
filesPeeked: z.number().int().min(0),
|
|
130
|
+
filesClassified: z.number().int().min(0),
|
|
131
|
+
filesShown: z.number().int().min(0),
|
|
132
|
+
filesRetained: z.number().int().min(0),
|
|
133
|
+
})
|
|
134
|
+
.superRefine((c, ctx) => {
|
|
135
|
+
const narrows =
|
|
136
|
+
c.filesMetadataEligible <= c.filesEnumerated &&
|
|
137
|
+
c.filesT0Scored <= c.filesMetadataEligible &&
|
|
138
|
+
c.filesT1Attended <= c.filesT0Scored &&
|
|
139
|
+
c.filesPeeked <= c.filesT1Attended &&
|
|
140
|
+
c.filesClassified <= c.filesT0Scored &&
|
|
141
|
+
c.filesRetained <= c.filesT0Scored &&
|
|
142
|
+
c.filesShown <= c.filesRetained;
|
|
143
|
+
if (!narrows) {
|
|
144
|
+
ctx.addIssue({
|
|
145
|
+
code: "custom",
|
|
146
|
+
message: "stage counters narrow from enumerated to shown",
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
export type DiscoveryStageCounters = z.infer<
|
|
151
|
+
typeof DiscoveryStageCountersSchema
|
|
152
|
+
>;
|
package/src/source-sync/index.ts
CHANGED
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Re-exports the closed Source Sync vocabularies (the sets the backend persists
|
|
5
5
|
* and mirrors as database CHECK constraints, and the app handles exhaustively)
|
|
6
|
-
* including the discovery relevance vocabulary, the
|
|
6
|
+
* including the discovery relevance vocabulary, the index-first enumeration
|
|
7
|
+
* vocabulary (completeness, root coverage, stage counters), the attention
|
|
8
|
+
* evidence schemas, the discovery and candidate-set response schemas, the candidate-edit and
|
|
7
9
|
* per-scope approval request and response schemas, the per-document change
|
|
8
10
|
* plan and apply schemas, the source-resolution rule schemas, the staleness
|
|
9
11
|
* finding and standing-order schemas, and the Drive-reach status and upgrade
|
|
@@ -31,6 +33,7 @@ export type {
|
|
|
31
33
|
SourceSyncScopeApproverKind,
|
|
32
34
|
DocumentType,
|
|
33
35
|
KnownDocumentType,
|
|
36
|
+
OperatingKnowledgeFamily,
|
|
34
37
|
} from "./vocabulary";
|
|
35
38
|
|
|
36
39
|
export {
|
|
@@ -45,6 +48,7 @@ export {
|
|
|
45
48
|
SOURCE_SYNC_SCOPE_APPROVAL_STATES,
|
|
46
49
|
SOURCE_SYNC_SCOPE_APPROVER_KINDS,
|
|
47
50
|
DOCUMENT_TYPES,
|
|
51
|
+
OPERATING_KNOWLEDGE_FAMILIES,
|
|
48
52
|
} from "./vocabulary";
|
|
49
53
|
|
|
50
54
|
export type {
|
|
@@ -86,6 +90,36 @@ export {
|
|
|
86
90
|
refineCandidateRelevance,
|
|
87
91
|
} from "./relevance";
|
|
88
92
|
|
|
93
|
+
export type {
|
|
94
|
+
EnumerationCompleteness,
|
|
95
|
+
EnumerationRootKind,
|
|
96
|
+
RootCoverage,
|
|
97
|
+
DiscoveryStageCounters,
|
|
98
|
+
} from "./enumeration";
|
|
99
|
+
|
|
100
|
+
export {
|
|
101
|
+
ENUMERATION_COMPLETENESS,
|
|
102
|
+
ENUMERATION_ROOT_KINDS,
|
|
103
|
+
combineEnumerationCompleteness,
|
|
104
|
+
EnumerationSkippedRangeSchema,
|
|
105
|
+
RootCoverageSchema,
|
|
106
|
+
DiscoveryStageCountersSchema,
|
|
107
|
+
} from "./enumeration";
|
|
108
|
+
|
|
109
|
+
export type {
|
|
110
|
+
AttentionSignalKind,
|
|
111
|
+
AttentionSignalSource,
|
|
112
|
+
AttentionSignal,
|
|
113
|
+
AttentionEvidence,
|
|
114
|
+
} from "./attention-evidence";
|
|
115
|
+
|
|
116
|
+
export {
|
|
117
|
+
ATTENTION_SIGNAL_KINDS,
|
|
118
|
+
AttentionSignalSourceSchema,
|
|
119
|
+
AttentionSignalSchema,
|
|
120
|
+
AttentionEvidenceSchema,
|
|
121
|
+
} from "./attention-evidence";
|
|
122
|
+
|
|
89
123
|
export type {
|
|
90
124
|
SourceSyncCandidateItem,
|
|
91
125
|
SourceSyncCandidateItemPatch,
|
|
@@ -7,6 +7,12 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { z } from "zod";
|
|
10
|
+
import {
|
|
11
|
+
combineEnumerationCompleteness,
|
|
12
|
+
DiscoveryStageCountersSchema,
|
|
13
|
+
ENUMERATION_COMPLETENESS,
|
|
14
|
+
RootCoverageSchema,
|
|
15
|
+
} from "./enumeration";
|
|
10
16
|
|
|
11
17
|
/** The funnel's verdict. `dropped` is persisted (drop ledger / re-scored observation) and never reaches the wire item. */
|
|
12
18
|
export const SOURCE_RELEVANCE_TIERS = ["dropped", "hidden", "shown"] as const;
|
|
@@ -165,17 +171,50 @@ export type CandidateAttention = z.infer<typeof CandidateAttentionSchema>;
|
|
|
165
171
|
|
|
166
172
|
/**
|
|
167
173
|
* The last completed discovery run's counts, so no surface shows one ambiguous total.
|
|
168
|
-
* The set response carries it NULL before any run has completed.
|
|
174
|
+
* The set response carries it NULL before any run has completed. The three enumeration
|
|
175
|
+
* fields are all present or all absent: NULL on all three = the run predates index-first
|
|
176
|
+
* discovery (control ADR index-first-operating-knowledge-discovery).
|
|
169
177
|
*/
|
|
170
|
-
export const CandidateDiscoverySummarySchema = z
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
178
|
+
export const CandidateDiscoverySummarySchema = z
|
|
179
|
+
.object({
|
|
180
|
+
foundThisRun: z.number().int().min(0),
|
|
181
|
+
retainedDecisions: z.number().int().min(0),
|
|
182
|
+
notRediscovered: z.number().int().min(0),
|
|
183
|
+
pendingClassification: z.number().int().min(0),
|
|
184
|
+
filesDropped: z.number().int().min(0),
|
|
185
|
+
coveragePercent: z.number().int().min(0).max(100),
|
|
186
|
+
scanOutcome: z.enum(SCAN_OUTCOMES),
|
|
187
|
+
/** How completely the run enumerated; only `complete` may be called a full index. */
|
|
188
|
+
enumerationCompleteness: z.enum(ENUMERATION_COMPLETENESS).nullable(),
|
|
189
|
+
/** One entry per enumerated root. */
|
|
190
|
+
rootCoverage: z.array(RootCoverageSchema).min(1).max(64).nullable(),
|
|
191
|
+
/** What each stage did, by count (filesEnumerated is metadata only — never "indexed"). */
|
|
192
|
+
stageCounters: DiscoveryStageCountersSchema.nullable(),
|
|
193
|
+
})
|
|
194
|
+
.superRefine((s, ctx) => {
|
|
195
|
+
const present = [
|
|
196
|
+
s.enumerationCompleteness,
|
|
197
|
+
s.rootCoverage,
|
|
198
|
+
s.stageCounters,
|
|
199
|
+
].filter((v) => v !== null).length;
|
|
200
|
+
if (present !== 0 && present !== 3) {
|
|
201
|
+
ctx.addIssue({
|
|
202
|
+
code: "custom",
|
|
203
|
+
message: "enumeration fields are all present or all absent",
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
if (
|
|
207
|
+
s.rootCoverage !== null &&
|
|
208
|
+
s.enumerationCompleteness !== null &&
|
|
209
|
+
combineEnumerationCompleteness(s.rootCoverage.map((r) => r.status)) !==
|
|
210
|
+
s.enumerationCompleteness
|
|
211
|
+
) {
|
|
212
|
+
ctx.addIssue({
|
|
213
|
+
code: "custom",
|
|
214
|
+
message: "enumeration completeness is the combination of its roots",
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
});
|
|
179
218
|
export type CandidateDiscoverySummary = z.infer<
|
|
180
219
|
typeof CandidateDiscoverySummarySchema
|
|
181
220
|
>;
|
|
@@ -191,6 +230,11 @@ type CandidateRelevanceFacts = {
|
|
|
191
230
|
selectionSource: SelectionSource | null;
|
|
192
231
|
documentType: string | null;
|
|
193
232
|
documentTypeConfidence: number | null;
|
|
233
|
+
withheld: boolean;
|
|
234
|
+
attention: { t1: AttentionLane | null; t2: AttentionLane | null };
|
|
235
|
+
operatingKnowledgeFamily: string | null;
|
|
236
|
+
canonicalPath: string | null;
|
|
237
|
+
attentionEvidence: readonly unknown[] | null;
|
|
194
238
|
};
|
|
195
239
|
|
|
196
240
|
/**
|
|
@@ -198,7 +242,10 @@ type CandidateRelevanceFacts = {
|
|
|
198
242
|
* a hidden line is never included; classification decides whether a recommendation and a
|
|
199
243
|
* class exist; `selectionSource` is present exactly when a treatment is committed. A
|
|
200
244
|
* document type exists only on a classified line, and carries a confidence exactly when
|
|
201
|
-
* it is a known type (control ADR source-discovery-observation-vs-policy).
|
|
245
|
+
* it is a known type (control ADR source-discovery-observation-vs-policy). An
|
|
246
|
+
* operating-knowledge family needs a known type; attention evidence and a canonical path
|
|
247
|
+
* exist only on a line T1 attended and never on a withheld one (control ADR
|
|
248
|
+
* index-first-operating-knowledge-discovery).
|
|
202
249
|
*/
|
|
203
250
|
export function refineCandidateRelevance(
|
|
204
251
|
item: CandidateRelevanceFacts,
|
|
@@ -248,4 +295,31 @@ export function refineCandidateRelevance(
|
|
|
248
295
|
"a known document type carries a confidence; unknown and absent carry none",
|
|
249
296
|
});
|
|
250
297
|
}
|
|
298
|
+
if (item.operatingKnowledgeFamily !== null && !knownType) {
|
|
299
|
+
ctx.addIssue({
|
|
300
|
+
code: "custom",
|
|
301
|
+
message: "an operating-knowledge family needs a known document type",
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
if (
|
|
305
|
+
item.withheld &&
|
|
306
|
+
(item.attentionEvidence !== null || item.canonicalPath !== null)
|
|
307
|
+
) {
|
|
308
|
+
ctx.addIssue({
|
|
309
|
+
code: "custom",
|
|
310
|
+
message: "a withheld line carries no attention evidence and no path",
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
if (item.attentionEvidence !== null && item.attention.t1 === null) {
|
|
314
|
+
ctx.addIssue({
|
|
315
|
+
code: "custom",
|
|
316
|
+
message: "attention evidence exists only on a line T1 attended",
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
if (item.canonicalPath !== null && item.attention.t1 === null) {
|
|
320
|
+
ctx.addIssue({
|
|
321
|
+
code: "custom",
|
|
322
|
+
message: "a canonical path exists only on a line T1 attended",
|
|
323
|
+
});
|
|
324
|
+
}
|
|
251
325
|
}
|
|
@@ -113,7 +113,9 @@ export type SourceSyncScopeApproverKind =
|
|
|
113
113
|
|
|
114
114
|
/**
|
|
115
115
|
* What a source IS — a STRUCTURAL name the model observes, never a relevance verdict
|
|
116
|
-
* (control ADR source-discovery-observation-vs-policy).
|
|
116
|
+
* (control ADR source-discovery-observation-vs-policy). The set names operating
|
|
117
|
+
* knowledge — charters, playbooks, policies, decision logs, postmortems and the like —
|
|
118
|
+
* beside strategy (control ADR index-first-operating-knowledge-discovery). Product policy in the backend maps a
|
|
117
119
|
* resolved type to a family, a source class, a sensitivity and a relevance policy; none of
|
|
118
120
|
* that travels on the wire. A medium is not a meaning: `image_or_screenshot` is graded on
|
|
119
121
|
* content. `unknown` is a real answer (the model could not tell, or two reads disagreed).
|
|
@@ -151,7 +153,41 @@ export const DOCUMENT_TYPES = [
|
|
|
151
153
|
"coursework",
|
|
152
154
|
"empty_template",
|
|
153
155
|
"image_or_screenshot",
|
|
156
|
+
// Operating knowledge (control ADR index-first-operating-knowledge-discovery):
|
|
157
|
+
"team_charter",
|
|
158
|
+
"process_playbook",
|
|
159
|
+
"policy_handbook",
|
|
160
|
+
"onboarding_guide",
|
|
161
|
+
"values_culture",
|
|
162
|
+
"positioning_messaging",
|
|
163
|
+
"decision_log",
|
|
164
|
+
"postmortem",
|
|
165
|
+
"metrics_definition",
|
|
166
|
+
"operating_cadence",
|
|
154
167
|
"unknown",
|
|
155
168
|
] as const;
|
|
156
169
|
export type DocumentType = (typeof DOCUMENT_TYPES)[number];
|
|
157
170
|
export type KnownDocumentType = Exclude<DocumentType, "unknown">;
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* WHAT KIND of operating knowledge a source is: what the company is trying to do
|
|
174
|
+
* (direction), how it is organized to do it (operating_model), how it runs
|
|
175
|
+
* (practices), who it is and for whom (identity_market), and what it decided and
|
|
176
|
+
* learned (decisions_learning). Control ADR index-first-operating-knowledge-discovery.
|
|
177
|
+
*
|
|
178
|
+
* A NAME the product derives from the resolved document type — the backend's
|
|
179
|
+
* versioned policy table owns the type -> family mapping, exactly as it owns
|
|
180
|
+
* sourceClass. It is NOT the backend's relevance-policy family (strategy,
|
|
181
|
+
* reference, corporate_record, …), which never travels on the wire. Board and
|
|
182
|
+
* financial material are ordinary members of `direction`; no family is required
|
|
183
|
+
* to exist for a discovery to be valid.
|
|
184
|
+
*/
|
|
185
|
+
export const OPERATING_KNOWLEDGE_FAMILIES = [
|
|
186
|
+
"direction",
|
|
187
|
+
"operating_model",
|
|
188
|
+
"practices",
|
|
189
|
+
"identity_market",
|
|
190
|
+
"decisions_learning",
|
|
191
|
+
] as const;
|
|
192
|
+
export type OperatingKnowledgeFamily =
|
|
193
|
+
(typeof OPERATING_KNOWLEDGE_FAMILIES)[number];
|