@company-semantics/contracts 93.0.0 → 93.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": "93.0.0",
3
+ "version": "93.1.0",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
@@ -168,7 +168,7 @@
168
168
  "pnpm": {
169
169
  "overrides": {
170
170
  "brace-expansion@<5.0.11": ">=5.0.11",
171
- "smol-toml@<1.7.1": ">=1.7.1",
171
+ "smol-toml@<1.9.0": ">=1.9.0",
172
172
  "minimatch@<10.2.3": ">=10.2.3",
173
173
  "nanoid@<3.3.18": ">=3.3.18",
174
174
  "js-yaml@>=4.0.0 <4.3.2": ">=4.3.2 <5.0.0",
@@ -181,7 +181,8 @@
181
181
  "postcss@<8.5.23": ">=8.5.23",
182
182
  "source-map-js@<1.2.2": ">=1.2.2",
183
183
  "markdown-it@<14.2.0": ">=14.2.0",
184
- "@humanfs/node@<0.16.8": ">=0.16.8 <0.17.0"
184
+ "@humanfs/node@<0.16.8": ">=0.16.8 <0.17.0",
185
+ "katex@<0.18.2": ">=0.18.2 <0.19.0"
185
186
  }
186
187
  },
187
188
  "lint-staged": {
@@ -189,5 +190,5 @@
189
190
  "*.md": "markdownlint-cli2",
190
191
  "package.json": "node -e \"JSON.parse(require('fs').readFileSync('package.json'))\""
191
192
  },
192
- "securityRequirementsVersion": "4b88755e9a43a82b2f5eb55b953581526f1982de362da77bc579888d1f6a1bb0"
193
+ "securityRequirementsVersion": "71a26f10642b9fc598f6da99c75200fd174ebd0e6a9e32437a3f1b245e906792"
193
194
  }
@@ -157,6 +157,7 @@ describe("resource-keys: system-scoped internalAdmin* types", () => {
157
157
  "factoryFloor",
158
158
  "factorySnapshot",
159
159
  "factoryKpis",
160
+ "factoryLineage",
160
161
  ] as const;
161
162
 
162
163
  for (const type of systemTypes) {
@@ -1,3 +1,3 @@
1
1
  // AUTO-GENERATED — do not edit. Run pnpm generate:spec-hash to regenerate.
2
- export const SPEC_HASH = '4eb1b17b3340' as const;
3
- export const SPEC_HASH_FULL = '4eb1b17b3340b7613c5f8189f7fef55164ea1d859c67b31790297ce5709b2db4' as const;
2
+ export const SPEC_HASH = 'aebd06a13983' as const;
3
+ export const SPEC_HASH_FULL = 'aebd06a139833549518e70adbcd3af333598cf06fa6669a838f605231395c8cf' as const;
@@ -3911,6 +3911,23 @@ export interface paths {
3911
3911
  patch?: never;
3912
3912
  trace?: never;
3913
3913
  };
3914
+ "/api/factory/lineage": {
3915
+ parameters: {
3916
+ query?: never;
3917
+ header?: never;
3918
+ path?: never;
3919
+ cookie?: never;
3920
+ };
3921
+ /** Read change lineage: each release with its commits, PRDs, workers, run and health */
3922
+ get: operations["factoryLineage"];
3923
+ put?: never;
3924
+ post?: never;
3925
+ delete?: never;
3926
+ options?: never;
3927
+ head?: never;
3928
+ patch?: never;
3929
+ trace?: never;
3930
+ };
3914
3931
  "/api/factory/quality/changes": {
3915
3932
  parameters: {
3916
3933
  query?: never;
@@ -6893,6 +6910,13 @@ export interface components {
6893
6910
  requiredScope?: string;
6894
6911
  };
6895
6912
  };
6913
+ workspace?: {
6914
+ manageSettings: {
6915
+ /** @enum {string} */
6916
+ state: "allowed" | "blocked";
6917
+ requiredScope?: string;
6918
+ };
6919
+ };
6896
6920
  };
6897
6921
  chatMentions: boolean;
6898
6922
  chatMultiParty: boolean;
@@ -9253,6 +9277,11 @@ export interface components {
9253
9277
  };
9254
9278
  eventTimestamp: string;
9255
9279
  }[];
9280
+ pausedAuth?: {
9281
+ since: string;
9282
+ lane: number;
9283
+ reason: string | null;
9284
+ } | null;
9256
9285
  }[];
9257
9286
  };
9258
9287
  FactorySnapshotResponse: {
@@ -9389,6 +9418,49 @@ export interface components {
9389
9418
  [key: string]: unknown;
9390
9419
  } | null;
9391
9420
  };
9421
+ FactoryLineageResponse: {
9422
+ releases: {
9423
+ key: string;
9424
+ manifestId: string | null;
9425
+ stationId: string;
9426
+ /** @enum {string} */
9427
+ status: "in_progress" | "applied" | "rolled_back";
9428
+ intendedAt: string | null;
9429
+ appliedAt: string | null;
9430
+ durationMs: number | null;
9431
+ surfaces: string[];
9432
+ shas: {
9433
+ [key: string]: string;
9434
+ } | null;
9435
+ run: {
9436
+ id: string;
9437
+ attempt: number;
9438
+ repository: string;
9439
+ url: string;
9440
+ } | null;
9441
+ health: {
9442
+ /** @enum {string} */
9443
+ releaseInvariant: "ok" | "failed" | "unproven" | "unknown";
9444
+ /** @enum {string} */
9445
+ windowMetric: "ok" | "failed" | "unproven" | "unknown";
9446
+ /** @enum {string} */
9447
+ pointProbe: "ok" | "failed" | "unproven" | "unknown";
9448
+ rolledBack: boolean;
9449
+ } | null;
9450
+ commitsRecorded: boolean;
9451
+ changesTruncated: boolean;
9452
+ changes: {
9453
+ repo: string;
9454
+ sha: string;
9455
+ prdId: string | null;
9456
+ pr: number | null;
9457
+ worker: {
9458
+ stationId: string;
9459
+ executorId: string;
9460
+ } | null;
9461
+ }[];
9462
+ }[];
9463
+ };
9392
9464
  CreateQualityChangeResponse: {
9393
9465
  /** Format: uuid */
9394
9466
  planId: string;
@@ -17897,6 +17969,43 @@ export interface operations {
17897
17969
  };
17898
17970
  };
17899
17971
  };
17972
+ factoryLineage: {
17973
+ parameters: {
17974
+ query?: {
17975
+ limit?: number;
17976
+ prdId?: string;
17977
+ };
17978
+ header?: never;
17979
+ path?: never;
17980
+ cookie?: never;
17981
+ };
17982
+ requestBody?: never;
17983
+ responses: {
17984
+ /** @description Lineage records, newest release first */
17985
+ 200: {
17986
+ headers: {
17987
+ [name: string]: unknown;
17988
+ };
17989
+ content: {
17990
+ "application/json": components["schemas"]["FactoryLineageResponse"];
17991
+ };
17992
+ };
17993
+ /** @description Not authenticated */
17994
+ 401: {
17995
+ headers: {
17996
+ [name: string]: unknown;
17997
+ };
17998
+ content?: never;
17999
+ };
18000
+ /** @description Not an internal admin */
18001
+ 403: {
18002
+ headers: {
18003
+ [name: string]: unknown;
18004
+ };
18005
+ content?: never;
18006
+ };
18007
+ };
18008
+ };
17900
18009
  createQualityChange: {
17901
18010
  parameters: {
17902
18011
  query?: never;
@@ -23,13 +23,21 @@
23
23
  * no-sibling-imports invariant intact (the same pattern as
24
24
  * runtime-profile.test.ts).
25
25
  *
26
- * It is skipped when the app is not checked out beside this repo — contracts
27
- * consumed standalone from npm, or contracts CI, which by design has no app
28
- * checkout because contracts is the root of the dependency tree. The inverted
29
- * marker test makes the reporter say so rather than showing a silent pass.
26
+ * Where the app is read from: `resolveSibling` (tests/workspace-sibling.ts), the
27
+ * workspace's sibling rule (ci ADR-CI-276): this session's app worktree when
28
+ * the session holds one, else app's committed origin/main; never a primary's
29
+ * working tree. It used to probe `<workspace>/company-semantics-app` (the
30
+ * PRIMARY) and `../company-semantics-app` from cwd for
31
+ * `src/platform/route-parser.ts`, a path app has since moved to
32
+ * `src/lib/nav/route-parser.ts`, so it skipped everywhere (ci ADR-CI-294
33
+ * follow-up). A moved file now fails the read.
34
+ *
35
+ * Inside the workspace a missing or unreadable app FAILS this file. The parity
36
+ * tests skip, and the inverted marker test says why, only in a standalone
37
+ * clone (no other company-semantics-* checkout beside it): contracts consumed
38
+ * from npm, or contracts CI, which by design has no app checkout because
39
+ * contracts is the root of the dependency tree.
30
40
  */
31
- import { existsSync, readFileSync } from "node:fs";
32
- import { resolve, sep } from "node:path";
33
41
  import { describe, it, expect } from "vitest";
34
42
  import {
35
43
  ChatPageContextSchema,
@@ -37,6 +45,7 @@ import {
37
45
  CHAT_PAGE_SCOPES,
38
46
  CHAT_PAGE_ENTITY_TYPES,
39
47
  } from "../schemas.js";
48
+ import { resolveSibling } from "../../../tests/workspace-sibling.js";
40
49
 
41
50
  // ---------------------------------------------------------------------------
42
51
  // Fixtures
@@ -56,52 +65,22 @@ const A_DOCUMENT_BODY = `# Q3 plan\n${"Revenue grew. ".repeat(200)}`;
56
65
  // Locating the app checkout that governs this run
57
66
  // ---------------------------------------------------------------------------
58
67
 
59
- /**
60
- * Probed in order:
61
- * 1. The app worktree mirroring this one. Ralph checks the same branch of
62
- * every repo out at the same relative path, so a contracts worktree has an
63
- * app worktree beside it carrying the branch's route grammar. The app MAIN
64
- * checkout sits on another branch entirely, and comparing against it would
65
- * report drift for a value this branch already corrected.
66
- * 2. The app main checkout in the same workspace.
67
- * 3. The plain sibling guess, for a non-worktree local dev layout.
68
- */
69
- function resolveAppRoot(): string | undefined {
70
- const candidates: string[] = [];
71
-
72
- const segments = process.cwd().split(sep);
73
- const contractsIdx = segments.lastIndexOf("company-semantics-contracts");
74
- if (contractsIdx !== -1) {
75
- const workspaceRoot = segments.slice(0, contractsIdx).join(sep);
76
- const worktreeSuffix = segments.slice(contractsIdx + 1);
77
- const appRoot = resolve(workspaceRoot, "company-semantics-app");
78
- if (worktreeSuffix.length > 0) {
79
- candidates.push(resolve(appRoot, ...worktreeSuffix));
80
- }
81
- candidates.push(appRoot);
82
- }
83
- candidates.push(resolve(process.cwd(), "..", "company-semantics-app"));
84
-
85
- return candidates.find((root) =>
86
- existsSync(resolve(root, "src", "platform", "route-parser.ts")),
87
- );
88
- }
68
+ const APP_ROUTE_PARSER = "src/lib/nav/route-parser.ts";
89
69
 
90
- const APP_ROOT = resolveAppRoot();
91
- const appAvailable = APP_ROOT !== undefined;
70
+ // Throws (failing this file loudly) inside the workspace when the app cannot
71
+ // be resolved; null only in a standalone clone.
72
+ const app = await resolveSibling("company-semantics-app");
73
+ const appAvailable = app !== null;
92
74
 
93
75
  /** The body of the app's `export type Route = ...;` union, as a string. */
94
76
  function appRouteUnionSource(): string {
95
- const source = readFileSync(
96
- resolve(APP_ROOT!, "src", "platform", "route-parser.ts"),
97
- "utf8",
98
- );
77
+ const source = app!.read(APP_ROUTE_PARSER);
99
78
  // Terminated by the blank line after the union, because `;` also ends every
100
79
  // member field inside it.
101
80
  const match = source.match(/export type Route =([\s\S]*?);\r?\n\r?\n/);
102
81
  if (!match?.[1]) {
103
82
  throw new Error(
104
- "Could not locate the `Route` union in app src/platform/route-parser.ts. " +
83
+ `Could not locate the \`Route\` union in app ${APP_ROUTE_PARSER}. ` +
105
84
  "If the declaration was renamed or restructured, update this test — do " +
106
85
  "NOT delete it, or the view vocabulary can drift out of step unseen.",
107
86
  );
@@ -18,59 +18,35 @@
18
18
  * imports, keeping the contracts no-sibling-imports invariant intact (the
19
19
  * same pattern as tests/org/reserved-slug-roundtrip.test.ts).
20
20
  *
21
- * They are skipped when the backend is not checked out beside this repo — e.g.
22
- * contracts consumed standalone from npm, or contracts CI, which by design has
23
- * no backend checkout because contracts is the root of the dependency tree.
24
- * Drift introduced on the backend side is therefore NOT gated by contracts CI;
25
- * it is caught here in a workspace checkout, and the inverted marker test below
26
- * makes the reporter say so rather than showing a silent pass.
21
+ * Where the backend is read from: `resolveSibling` (tests/workspace-sibling.ts),
22
+ * the workspace's sibling rule (ci ADR-CI-276): this session's backend worktree
23
+ * when the session holds one, else backend's committed origin/main; never a
24
+ * primary's working tree, which may hold another session's uncommitted work.
25
+ * It used to probe `<workspace>/company-semantics-backend` (the PRIMARY) and
26
+ * `../company-semantics-backend` from cwd (ci ADR-CI-294 follow-up).
27
+ *
28
+ * Inside the workspace a missing or unreadable backend FAILS this file. The
29
+ * parity tests skip, and the inverted marker test says why, only in a
30
+ * standalone clone (no other company-semantics-* checkout beside it): contracts
31
+ * consumed from npm, or contracts CI, which by design has no backend checkout
32
+ * because contracts is the root of the dependency tree. Drift introduced on the
33
+ * backend side is therefore NOT gated by contracts CI; it is caught here in a
34
+ * workspace checkout.
27
35
  */
28
- import { existsSync, readFileSync } from "node:fs";
29
- import { resolve, sep } from "node:path";
30
36
  import { describe, it, expect } from "vitest";
31
37
  import {
32
38
  CHAT_RUNTIME_PROFILES,
33
39
  DEFAULT_CHAT_RUNTIME_PROFILE,
34
40
  } from "../runtime-profile.js";
41
+ import { resolveSibling } from "../../../tests/workspace-sibling.js";
35
42
 
36
- /**
37
- * Locate the backend checkout that governs this run.
38
- *
39
- * Probed in order:
40
- * 1. The backend worktree mirroring this one. Ralph checks the same branch of
41
- * every repo out at the same relative path, so a contracts worktree has a
42
- * backend worktree beside it carrying the branch's constants. The backend
43
- * MAIN checkout sits on another branch entirely, and comparing against it
44
- * would report drift for a value this branch already corrected.
45
- * 2. The backend main checkout in the same workspace.
46
- * 3. The plain sibling guess, for a non-worktree local dev layout.
47
- */
48
- function resolveBackendRoot(): string | undefined {
49
- const candidates: string[] = [];
50
-
51
- const segments = process.cwd().split(sep);
52
- const contractsIdx = segments.lastIndexOf("company-semantics-contracts");
53
- if (contractsIdx !== -1) {
54
- const workspaceRoot = segments.slice(0, contractsIdx).join(sep);
55
- const worktreeSuffix = segments.slice(contractsIdx + 1);
56
- const backendRoot = resolve(workspaceRoot, "company-semantics-backend");
57
- if (worktreeSuffix.length > 0) {
58
- candidates.push(resolve(backendRoot, ...worktreeSuffix));
59
- }
60
- candidates.push(backendRoot);
61
- }
62
- candidates.push(resolve(process.cwd(), "..", "company-semantics-backend"));
63
-
64
- return candidates.find((root) =>
65
- existsSync(resolve(root, "src", "chat", "orchestrator", "factory.ts")),
66
- );
67
- }
68
-
69
- const BACKEND_ROOT = resolveBackendRoot();
70
- const backendAvailable = BACKEND_ROOT !== undefined;
43
+ // Throws (failing this file loudly) inside the workspace when the backend
44
+ // cannot be resolved; null only in a standalone clone.
45
+ const backend = await resolveSibling("company-semantics-backend");
46
+ const backendAvailable = backend !== null;
71
47
 
72
48
  function readBackendSource(...relative: string[]): string {
73
- return readFileSync(resolve(BACKEND_ROOT!, ...relative), "utf8");
49
+ return backend!.read(relative.join("/"));
74
50
  }
75
51
 
76
52
  /** Extract the single capture of `pattern`, or explain what moved. */
@@ -95,6 +95,7 @@ export const openApiRoutes = {
95
95
  '/api/executions/{executionId}/undo': ['POST'],
96
96
  '/api/factory/floor': ['GET'],
97
97
  '/api/factory/kpis': ['GET'],
98
+ '/api/factory/lineage': ['GET'],
98
99
  '/api/factory/quality/changes': ['POST'],
99
100
  '/api/factory/quality/corpus': ['GET'],
100
101
  '/api/factory/quality/deployments': ['POST'],
@@ -161,6 +161,7 @@ export const SYSTEM_SCOPED_TYPES = [
161
161
  "factoryFloor",
162
162
  "factorySnapshot",
163
163
  "factoryKpis",
164
+ "factoryLineage",
164
165
  ] as const satisfies readonly SystemScopedType[];
165
166
 
166
167
  /** Every literal `fromQueryKey` can route, across all five tables. */
@@ -157,6 +157,9 @@ export type ResourceKey =
157
157
  // `useResource` disables a query whose `toQueryKey` throws, the panel it backs
158
158
  // never fetched at all. An unregistered key is not a stale read, it is no read.
159
159
  | { type: "factoryKpis"; scope: "system" }
160
+ // Change lineage over the release ledger (ADR-CONTRACTS-222, backend
161
+ // ADR-BE-926): each release with its commits, PRDs, workers, run and health.
162
+ | { type: "factoryLineage"; scope: "system" }
160
163
  // Everything awaiting the viewer's decision, across every domain
161
164
  // (ADR-CONT-104). ORG-scoped, not user-scoped, even though the content is
162
165
  // per-viewer: the bucket differs per org, so a user-keyed entry would serve
@@ -137,6 +137,7 @@ export function toQueryKey(key: ResourceKey): readonly string[] {
137
137
  case "factoryFloor":
138
138
  case "factorySnapshot":
139
139
  case "factoryKpis":
140
+ case "factoryLineage":
140
141
  return [key.type, key.scope] as const;
141
142
 
142
143
  default: {