@company-semantics/contracts 99.3.0 → 100.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@company-semantics/contracts",
3
- "version": "99.3.0",
3
+ "version": "100.0.0",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,3 +1,3 @@
1
1
  // AUTO-GENERATED — do not edit. Run pnpm generate:spec-hash to regenerate.
2
- export const SPEC_HASH = 'c7651db1db74' as const;
3
- export const SPEC_HASH_FULL = 'c7651db1db74df7ba1f8d6ef92caef3024498071b187aa818640d98f2d90c037' as const;
2
+ export const SPEC_HASH = '7e0143b235a3' as const;
3
+ export const SPEC_HASH_FULL = '7e0143b235a3cc79cc020305bc8e4cf82c7784774cff280504fe70c0e9ee9a81' as const;
@@ -7469,10 +7469,11 @@ export interface components {
7469
7469
  /** @enum {string} */
7470
7470
  kind: "produced" | "empty" | "partial" | "stopped" | "failed" | "abandoned" | "unknown";
7471
7471
  /** @enum {string} */
7472
- reason: "updates_ready" | "updates_applied" | "stopped_by_user" | "paused_billing" | "run_ceiling_reached" | "pricing_unconfigured" | "synthesis_incomplete" | "approval_mismatch" | "landing_refused" | "standing_order_refused" | "no_connection" | "source_sync_off" | "internal_error" | "abandoned" | "unrecognized_terminal_state";
7472
+ reason: "updates_ready" | "updates_ready_partial" | "updates_applied" | "stopped_by_user" | "paused_billing" | "run_ceiling_reached" | "pricing_unconfigured" | "synthesis_incomplete" | "approval_mismatch" | "landing_refused" | "standing_order_refused" | "no_connection" | "source_sync_off" | "internal_error" | "abandoned" | "unrecognized_terminal_state";
7473
7473
  facts: {
7474
7474
  scopeCount: number;
7475
7475
  violationCount: number;
7476
+ notLandedCount: number;
7476
7477
  } | null;
7477
7478
  disposition: {
7478
7479
  /** @constant */
@@ -10848,6 +10849,8 @@ export interface components {
10848
10849
  label: string;
10849
10850
  } | null;
10850
10851
  approvedAt: string | null;
10852
+ approvable: boolean;
10853
+ blockedReason: "needs_doc_access" | null;
10851
10854
  }[];
10852
10855
  discovery: {
10853
10856
  foundThisRun: number;
@@ -10912,6 +10915,8 @@ export interface components {
10912
10915
  label: string;
10913
10916
  } | null;
10914
10917
  approvedAt: string | null;
10918
+ approvable: boolean;
10919
+ blockedReason: "needs_doc_access" | null;
10915
10920
  }[];
10916
10921
  /** Format: uuid */
10917
10922
  workflowId: string;
@@ -11039,6 +11044,8 @@ export interface components {
11039
11044
  label: string;
11040
11045
  } | null;
11041
11046
  approvedAt: string | null;
11047
+ approvable: boolean;
11048
+ blockedReason: "needs_doc_access" | null;
11042
11049
  }[];
11043
11050
  };
11044
11051
  SourceSyncApplyResponse: {
@@ -11098,6 +11105,8 @@ export interface components {
11098
11105
  label: string;
11099
11106
  } | null;
11100
11107
  approvedAt: string | null;
11108
+ approvable: boolean;
11109
+ blockedReason: "needs_doc_access" | null;
11101
11110
  }[];
11102
11111
  };
11103
11112
  SourceSyncRulesResponse: {
@@ -34,6 +34,8 @@ function scope(overrides: Record<string, unknown> = {}) {
34
34
  vacantHead: false,
35
35
  approvedBy: null,
36
36
  approvedAt: null,
37
+ approvable: true,
38
+ blockedReason: null,
37
39
  ...overrides,
38
40
  };
39
41
  }
@@ -100,6 +102,28 @@ describe("SourceSyncScopeApprovalProjectionSchema", () => {
100
102
  });
101
103
  });
102
104
 
105
+ describe("approvable and blockedReason", () => {
106
+ it("accepts a visible scope the caller may not approve, with its reason", () => {
107
+ const parsed = SourceSyncScopeApprovalProjectionSchema.safeParse(
108
+ scope({ approvable: false, blockedReason: "needs_doc_access" }),
109
+ );
110
+ expect(parsed.success).toBe(true);
111
+ });
112
+
113
+ it("refuses a reason outside the vocabulary and a missing approvable", () => {
114
+ expect(
115
+ SourceSyncScopeApprovalProjectionSchema.safeParse(
116
+ scope({ approvable: false, blockedReason: "not_admin" }),
117
+ ).success,
118
+ ).toBe(false);
119
+ const { approvable: _omit, ...withoutApprovable } = scope();
120
+ expect(
121
+ SourceSyncScopeApprovalProjectionSchema.safeParse(withoutApprovable)
122
+ .success,
123
+ ).toBe(false);
124
+ });
125
+ });
126
+
103
127
  describe("scopes is required on every checkpoint response", () => {
104
128
  const schemas = [
105
129
  ["candidate set", SourceSyncCandidateSetResponseSchema],
@@ -31,6 +31,7 @@ export type {
31
31
  SourceSyncDocDisposition,
32
32
  SourceSyncScopeApprovalState,
33
33
  SourceSyncScopeApproverKind,
34
+ SourceSyncScopeBlockedReason,
34
35
  DocumentType,
35
36
  KnownDocumentType,
36
37
  OperatingKnowledgeFamily,
@@ -47,6 +48,7 @@ export {
47
48
  SOURCE_SYNC_DOC_DISPOSITIONS,
48
49
  SOURCE_SYNC_SCOPE_APPROVAL_STATES,
49
50
  SOURCE_SYNC_SCOPE_APPROVER_KINDS,
51
+ SOURCE_SYNC_SCOPE_BLOCKED_REASONS,
50
52
  DOCUMENT_TYPES,
51
53
  OPERATING_KNOWLEDGE_FAMILIES,
52
54
  } from "./vocabulary";
@@ -26,6 +26,7 @@ import {
26
26
  SOURCE_SYNC_DOC_RISKS,
27
27
  SOURCE_SYNC_SCOPE_APPROVAL_STATES,
28
28
  SOURCE_SYNC_SCOPE_APPROVER_KINDS,
29
+ SOURCE_SYNC_SCOPE_BLOCKED_REASONS,
29
30
  } from "./vocabulary";
30
31
  import { CandidateDiscoverySummarySchema } from "./relevance";
31
32
  import { SourceSyncCandidateItemSchema } from "./candidate-item";
@@ -45,6 +46,13 @@ const PersonLabel = z.string().min(1).max(255);
45
46
  * still a `unit_head` scope, `assignedTo` is null, and the org's admins approve it.
46
47
  * - An approved scope reports the routing its approval RECORDED; a later head
47
48
  * change does not rewrite it. A pending scope reports its routing as of now.
49
+ * - `approvable` is whether THE CALLER may approve this pending scope now. A scope
50
+ * can be visible but not approvable: approving needs the caller's own upload and
51
+ * edit access on the scope's document, because landing and apply act as the
52
+ * approver. `blockedReason` is non-null exactly when a pending scope is not
53
+ * approvable; an approved scope is never approvable and carries null. At the
54
+ * synthesis checkpoint a pending scope is approvable: apply is decided per
55
+ * document by the edit policy, which approving the candidate set required.
48
56
  */
49
57
  export const SourceSyncScopeApprovalProjectionSchema = z.object({
50
58
  /** 'company' or 'unit:<uuid>'. */
@@ -62,6 +70,8 @@ export const SourceSyncScopeApprovalProjectionSchema = z.object({
62
70
  /** Non-null exactly when a person's approval is recorded. */
63
71
  approvedBy: z.object({ label: PersonLabel }).nullable(),
64
72
  approvedAt: IsoDateTime.nullable(),
73
+ approvable: z.boolean(),
74
+ blockedReason: z.enum(SOURCE_SYNC_SCOPE_BLOCKED_REASONS).nullable(),
65
75
  });
66
76
 
67
77
  /** The discovery run a person started, or that upkeep started on a schedule. */
@@ -111,6 +111,16 @@ export const SOURCE_SYNC_SCOPE_APPROVER_KINDS = [
111
111
  export type SourceSyncScopeApproverKind =
112
112
  (typeof SOURCE_SYNC_SCOPE_APPROVER_KINDS)[number];
113
113
 
114
+ /**
115
+ * Why the CALLER may not approve a scope they can see. `needs_doc_access`: the
116
+ * landing and the apply act as the approver, so approving needs the caller's own
117
+ * upload and edit access on the scope's document (an admin holds only metadata
118
+ * access to company.md content).
119
+ */
120
+ export const SOURCE_SYNC_SCOPE_BLOCKED_REASONS = ["needs_doc_access"] as const;
121
+ export type SourceSyncScopeBlockedReason =
122
+ (typeof SOURCE_SYNC_SCOPE_BLOCKED_REASONS)[number];
123
+
114
124
  /**
115
125
  * What a source IS — a STRUCTURAL name the model observes, never a relevance verdict
116
126
  * (control ADR source-discovery-observation-vs-policy). The set names operating
@@ -147,6 +147,8 @@ export const SYNTHESIZE_DEFERRED_ROUTE_OF_REASON = {
147
147
  // prettier-ignore
148
148
  updates_ready: { route: "covered", by: "sourceSync.review_ready", fallback: "notice", audience: "creator" },
149
149
  // prettier-ignore
150
+ updates_ready_partial: { route: "covered", by: "sourceSync.review_ready", fallback: "notice", audience: "creator" },
151
+ // prettier-ignore
150
152
  updates_applied: { route: "covered", by: "sourceSync.docs_updated", fallback: "notice", audience: "creator" },
151
153
  stopped_by_user: STOPPED,
152
154
  paused_billing: EXPLAINED,
@@ -120,6 +120,8 @@ export type DiscoverOutcomeFacts = z.infer<typeof DiscoverOutcomeFactsSchema>;
120
120
  /** Why a synthesis (landing then drafting) run ended the way it did. */
121
121
  export const SYNTHESIZE_OUTCOME_KIND_OF_REASON = {
122
122
  updates_ready: "produced",
123
+ /** Drafted from what landed; some approved files could not be brought in. */
124
+ updates_ready_partial: "partial",
123
125
  updates_applied: "produced",
124
126
  stopped_by_user: "stopped",
125
127
  paused_billing: "failed",
@@ -142,6 +144,7 @@ export type SynthesizeOutcomeReason =
142
144
  /** What each synthesis ending offers. TOTAL; an empty list is explicit. */
143
145
  export const SYNTHESIZE_AFFORDANCES_OF_REASON = {
144
146
  updates_ready: [],
147
+ updates_ready_partial: [],
145
148
  updates_applied: [],
146
149
  stopped_by_user: [],
147
150
  paused_billing: [OPEN_BILLING],
@@ -168,6 +171,8 @@ export const SynthesizeOutcomeFactsSchema = z
168
171
  scopeCount: Count,
169
172
  /** Authority or size violations that left the batch incomplete. */
170
173
  violationCount: Count,
174
+ /** Approved files to attach that did not land (refused, unreadable, gone). */
175
+ notLandedCount: Count,
171
176
  })
172
177
  .strict();
173
178