@company-semantics/contracts 91.0.0 → 91.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 +1 -1
- package/src/api/generated-spec-hash.ts +2 -2
- package/src/api/generated.ts +399 -1
- package/src/generated/openapi-routes.ts +3 -0
- package/src/workflows/README.md +7 -5
- package/src/workflows/__tests__/affordances-of-outcome.test.ts +2 -5
- package/src/workflows/__tests__/deferred-route.test.ts +2 -3
- package/src/workflows/__tests__/outcome.test.ts +2 -3
- package/src/workflows/affordances-of-outcome.ts +2 -3
- package/src/workflows/deferred-route.ts +5 -3
- package/src/workflows/index.ts +18 -12
- package/src/workflows/outcome-reasons.ts +244 -0
- package/src/workflows/outcome.ts +16 -227
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 = '2d074ecfa53c' as const;
|
|
3
|
+
export const SPEC_HASH_FULL = '2d074ecfa53c0f377dfda06d9a46167a9cfc77eb3878e2cd71b8a04149c700b7' as const;
|
package/src/api/generated.ts
CHANGED
|
@@ -1566,6 +1566,23 @@ export interface paths {
|
|
|
1566
1566
|
patch?: never;
|
|
1567
1567
|
trace?: never;
|
|
1568
1568
|
};
|
|
1569
|
+
"/api/integrations/bamboohr/sync": {
|
|
1570
|
+
parameters: {
|
|
1571
|
+
query?: never;
|
|
1572
|
+
header?: never;
|
|
1573
|
+
path?: never;
|
|
1574
|
+
cookie?: never;
|
|
1575
|
+
};
|
|
1576
|
+
get?: never;
|
|
1577
|
+
put?: never;
|
|
1578
|
+
/** Run a BambooHR sync now (returns the run summary) */
|
|
1579
|
+
post: operations["syncBambooHrNow"];
|
|
1580
|
+
delete?: never;
|
|
1581
|
+
options?: never;
|
|
1582
|
+
head?: never;
|
|
1583
|
+
patch?: never;
|
|
1584
|
+
trace?: never;
|
|
1585
|
+
};
|
|
1569
1586
|
"/api/org/reconciliation": {
|
|
1570
1587
|
parameters: {
|
|
1571
1588
|
query?: never;
|
|
@@ -1666,6 +1683,26 @@ export interface paths {
|
|
|
1666
1683
|
patch?: never;
|
|
1667
1684
|
trace?: never;
|
|
1668
1685
|
};
|
|
1686
|
+
"/api/org/structure-inference/runs": {
|
|
1687
|
+
parameters: {
|
|
1688
|
+
query?: never;
|
|
1689
|
+
header?: never;
|
|
1690
|
+
path?: never;
|
|
1691
|
+
cookie?: never;
|
|
1692
|
+
};
|
|
1693
|
+
get?: never;
|
|
1694
|
+
put?: never;
|
|
1695
|
+
/**
|
|
1696
|
+
* Launch one org-structure reanalyze workflow and its inference run
|
|
1697
|
+
* @description Mints an org-structure/reanalyze analysis workflow, opens its pending run and schedules the job, all in one transaction (ADR-BE-606, ADR-BE-703): the snapshot, the model calls and the deterministic gate execute on the worker, and the outcome is read back by polling GET /api/org/structure-inference/proposal, whose run field carries this run’s id and status, or GET /api/analysis-workflows/{workflowId} for the workflow. At most one inference is in flight per org — a second POST joins the run already under way. Explicitly operator-triggered: there is no schedule and no sync hook.
|
|
1698
|
+
*/
|
|
1699
|
+
post: operations["runOrgStructureInference"];
|
|
1700
|
+
delete?: never;
|
|
1701
|
+
options?: never;
|
|
1702
|
+
head?: never;
|
|
1703
|
+
patch?: never;
|
|
1704
|
+
trace?: never;
|
|
1705
|
+
};
|
|
1669
1706
|
"/api/analysis-workflows/{id}": {
|
|
1670
1707
|
parameters: {
|
|
1671
1708
|
query?: never;
|
|
@@ -1726,6 +1763,26 @@ export interface paths {
|
|
|
1726
1763
|
patch?: never;
|
|
1727
1764
|
trace?: never;
|
|
1728
1765
|
};
|
|
1766
|
+
"/api/affordances/state": {
|
|
1767
|
+
parameters: {
|
|
1768
|
+
query?: never;
|
|
1769
|
+
header?: never;
|
|
1770
|
+
path?: never;
|
|
1771
|
+
cookie?: never;
|
|
1772
|
+
};
|
|
1773
|
+
/**
|
|
1774
|
+
* Read the live policy and availability of offered affordances
|
|
1775
|
+
* @description For exactly the affordance ids named in `ids` (the ids a settled outcome offered — never the catalog), whether the viewer is shown each one (`policy`, from the same capability derivation as GET /api/capabilities) and whether the org’s current state permits it (`availability`). Entries come back in request order, deduped. NON-AUTHORITATIVE: this answer is advisory UX state; the route each affordance binds to stays the only enforcement and may still refuse. Org-scoped: requires active membership of the session org, because availability discloses org state.
|
|
1776
|
+
*/
|
|
1777
|
+
get: operations["getAffordanceState"];
|
|
1778
|
+
put?: never;
|
|
1779
|
+
post?: never;
|
|
1780
|
+
delete?: never;
|
|
1781
|
+
options?: never;
|
|
1782
|
+
head?: never;
|
|
1783
|
+
patch?: never;
|
|
1784
|
+
trace?: never;
|
|
1785
|
+
};
|
|
1729
1786
|
"/api/company-md/tree": {
|
|
1730
1787
|
parameters: {
|
|
1731
1788
|
query?: never;
|
|
@@ -6808,6 +6865,34 @@ export interface components {
|
|
|
6808
6865
|
requiredScope?: string;
|
|
6809
6866
|
};
|
|
6810
6867
|
};
|
|
6868
|
+
integrations?: {
|
|
6869
|
+
manage: {
|
|
6870
|
+
/** @enum {string} */
|
|
6871
|
+
state: "allowed" | "blocked";
|
|
6872
|
+
requiredScope?: string;
|
|
6873
|
+
};
|
|
6874
|
+
};
|
|
6875
|
+
sourceSync?: {
|
|
6876
|
+
manage: {
|
|
6877
|
+
/** @enum {string} */
|
|
6878
|
+
state: "allowed" | "blocked";
|
|
6879
|
+
requiredScope?: string;
|
|
6880
|
+
};
|
|
6881
|
+
};
|
|
6882
|
+
billing?: {
|
|
6883
|
+
view: {
|
|
6884
|
+
/** @enum {string} */
|
|
6885
|
+
state: "allowed" | "blocked";
|
|
6886
|
+
requiredScope?: string;
|
|
6887
|
+
};
|
|
6888
|
+
};
|
|
6889
|
+
orgStructure?: {
|
|
6890
|
+
analyze: {
|
|
6891
|
+
/** @enum {string} */
|
|
6892
|
+
state: "allowed" | "blocked";
|
|
6893
|
+
requiredScope?: string;
|
|
6894
|
+
};
|
|
6895
|
+
};
|
|
6811
6896
|
};
|
|
6812
6897
|
chatMentions: boolean;
|
|
6813
6898
|
chatMultiParty: boolean;
|
|
@@ -6816,6 +6901,17 @@ export interface components {
|
|
|
6816
6901
|
reason: ("BILLING_INACTIVE" | "SEAT_SUBSCRIPTION_PAST_DUE" | "AI_BALANCE_EXHAUSTED" | "AI_BUDGET_EXHAUSTED" | "BYO_KEY_INVALID") | null;
|
|
6817
6902
|
};
|
|
6818
6903
|
};
|
|
6904
|
+
BambooHrSyncRunResponse: {
|
|
6905
|
+
/** Format: uuid */
|
|
6906
|
+
runId: string;
|
|
6907
|
+
processed: number;
|
|
6908
|
+
changed: number;
|
|
6909
|
+
skipped: number;
|
|
6910
|
+
conflicts: number;
|
|
6911
|
+
failures: number;
|
|
6912
|
+
sinceCursor: string | null;
|
|
6913
|
+
status: string;
|
|
6914
|
+
};
|
|
6819
6915
|
ResolveOrgDivergenceRequest: {
|
|
6820
6916
|
/** @constant */
|
|
6821
6917
|
resolution: "acknowledged";
|
|
@@ -6993,6 +7089,23 @@ export interface components {
|
|
|
6993
7089
|
fingerprint: string;
|
|
6994
7090
|
note?: string;
|
|
6995
7091
|
};
|
|
7092
|
+
RunStructureInferenceRefusal: {
|
|
7093
|
+
/** @constant */
|
|
7094
|
+
ran: false;
|
|
7095
|
+
/** @enum {string} */
|
|
7096
|
+
reason: "no_sync_run" | "no_persons" | "reporting_not_keyed";
|
|
7097
|
+
message: string;
|
|
7098
|
+
};
|
|
7099
|
+
RunStructureInferenceAccepted: {
|
|
7100
|
+
/** @constant */
|
|
7101
|
+
ran: true;
|
|
7102
|
+
/** Format: uuid */
|
|
7103
|
+
runId: string;
|
|
7104
|
+
workflowId: string | null;
|
|
7105
|
+
/** @enum {string} */
|
|
7106
|
+
status: "pending" | "running";
|
|
7107
|
+
alreadyRunning: boolean;
|
|
7108
|
+
};
|
|
6996
7109
|
AnalysisWorkflowProjectionResponse: {
|
|
6997
7110
|
/** Format: uuid */
|
|
6998
7111
|
id: string;
|
|
@@ -7003,7 +7116,180 @@ export interface components {
|
|
|
7003
7116
|
completedAt: string | null;
|
|
7004
7117
|
progress: unknown | null;
|
|
7005
7118
|
result: unknown | null;
|
|
7006
|
-
outcome:
|
|
7119
|
+
outcome: ({
|
|
7120
|
+
/** @constant */
|
|
7121
|
+
workflowType: "source-sync/discover";
|
|
7122
|
+
executionEpoch: number;
|
|
7123
|
+
/** @enum {string} */
|
|
7124
|
+
kind: "produced" | "empty" | "partial" | "stopped" | "failed" | "abandoned" | "unknown";
|
|
7125
|
+
/** @enum {string} */
|
|
7126
|
+
reason: "candidates_found" | "nothing_found" | "nothing_relevant" | "budget_exhausted" | "file_ceiling" | "stopped_by_user" | "plan_coverage_refused" | "billing_refused" | "drive_auth" | "drive_unavailable" | "no_connection" | "source_sync_off" | "internal_error" | "abandoned" | "unrecognized_terminal_state";
|
|
7127
|
+
facts: {
|
|
7128
|
+
probesTotal: number;
|
|
7129
|
+
probesDone: number;
|
|
7130
|
+
filesSeen: number;
|
|
7131
|
+
filesShown: number;
|
|
7132
|
+
filesHidden: number;
|
|
7133
|
+
filesDropped: number;
|
|
7134
|
+
coveragePercent: number | null;
|
|
7135
|
+
} | null;
|
|
7136
|
+
disposition: {
|
|
7137
|
+
/** @constant */
|
|
7138
|
+
kind: "review";
|
|
7139
|
+
/** @enum {string} */
|
|
7140
|
+
requestType: "org-structure/review" | "source-sync/candidates" | "source-sync/synthesis";
|
|
7141
|
+
requestId: string;
|
|
7142
|
+
} | {
|
|
7143
|
+
/** @constant */
|
|
7144
|
+
kind: "narrate";
|
|
7145
|
+
};
|
|
7146
|
+
affordances: ({
|
|
7147
|
+
/** @constant */
|
|
7148
|
+
id: "sourceSync.findFiles";
|
|
7149
|
+
} | {
|
|
7150
|
+
/** @constant */
|
|
7151
|
+
id: "integrations.connectGoogleDrive";
|
|
7152
|
+
} | {
|
|
7153
|
+
/** @constant */
|
|
7154
|
+
id: "sourceSync.enable";
|
|
7155
|
+
} | {
|
|
7156
|
+
/** @constant */
|
|
7157
|
+
id: "billing.open";
|
|
7158
|
+
} | {
|
|
7159
|
+
/** @constant */
|
|
7160
|
+
id: "orgStructure.reanalyze";
|
|
7161
|
+
} | {
|
|
7162
|
+
/** @constant */
|
|
7163
|
+
id: "hris.resyncDirectory";
|
|
7164
|
+
})[];
|
|
7165
|
+
} | {
|
|
7166
|
+
/** @constant */
|
|
7167
|
+
workflowType: "source-sync/synthesize";
|
|
7168
|
+
executionEpoch: number;
|
|
7169
|
+
/** @enum {string} */
|
|
7170
|
+
kind: "produced" | "empty" | "partial" | "stopped" | "failed" | "abandoned" | "unknown";
|
|
7171
|
+
/** @enum {string} */
|
|
7172
|
+
reason: "updates_ready" | "updates_applied" | "stopped_by_user" | "paused_billing" | "synthesis_incomplete" | "approval_mismatch" | "landing_refused" | "standing_order_refused" | "no_connection" | "source_sync_off" | "internal_error" | "abandoned" | "unrecognized_terminal_state";
|
|
7173
|
+
facts: {
|
|
7174
|
+
scopeCount: number;
|
|
7175
|
+
violationCount: number;
|
|
7176
|
+
} | null;
|
|
7177
|
+
disposition: {
|
|
7178
|
+
/** @constant */
|
|
7179
|
+
kind: "review";
|
|
7180
|
+
/** @enum {string} */
|
|
7181
|
+
requestType: "org-structure/review" | "source-sync/candidates" | "source-sync/synthesis";
|
|
7182
|
+
requestId: string;
|
|
7183
|
+
} | {
|
|
7184
|
+
/** @constant */
|
|
7185
|
+
kind: "narrate";
|
|
7186
|
+
};
|
|
7187
|
+
affordances: ({
|
|
7188
|
+
/** @constant */
|
|
7189
|
+
id: "sourceSync.findFiles";
|
|
7190
|
+
} | {
|
|
7191
|
+
/** @constant */
|
|
7192
|
+
id: "integrations.connectGoogleDrive";
|
|
7193
|
+
} | {
|
|
7194
|
+
/** @constant */
|
|
7195
|
+
id: "sourceSync.enable";
|
|
7196
|
+
} | {
|
|
7197
|
+
/** @constant */
|
|
7198
|
+
id: "billing.open";
|
|
7199
|
+
} | {
|
|
7200
|
+
/** @constant */
|
|
7201
|
+
id: "orgStructure.reanalyze";
|
|
7202
|
+
} | {
|
|
7203
|
+
/** @constant */
|
|
7204
|
+
id: "hris.resyncDirectory";
|
|
7205
|
+
})[];
|
|
7206
|
+
} | {
|
|
7207
|
+
/** @constant */
|
|
7208
|
+
workflowType: "org-structure/hris-connect";
|
|
7209
|
+
executionEpoch: number;
|
|
7210
|
+
/** @enum {string} */
|
|
7211
|
+
kind: "produced" | "empty" | "partial" | "stopped" | "failed" | "abandoned" | "unknown";
|
|
7212
|
+
/** @enum {string} */
|
|
7213
|
+
reason: "proposal_ready" | "directory_synced" | "analysis_already_running" | "proposal_blocked" | "no_sync_run" | "no_persons" | "reporting_not_keyed" | "stopped_by_user" | "sync_failed" | "snapshot_too_large" | "model_failed" | "run_too_large" | "placement_failed" | "internal_error" | "abandoned" | "unrecognized_terminal_state";
|
|
7214
|
+
facts: {
|
|
7215
|
+
departmentCount: number;
|
|
7216
|
+
teamCount: number;
|
|
7217
|
+
placedCount: number;
|
|
7218
|
+
reviewItemCount: number;
|
|
7219
|
+
} | null;
|
|
7220
|
+
disposition: {
|
|
7221
|
+
/** @constant */
|
|
7222
|
+
kind: "review";
|
|
7223
|
+
/** @enum {string} */
|
|
7224
|
+
requestType: "org-structure/review" | "source-sync/candidates" | "source-sync/synthesis";
|
|
7225
|
+
requestId: string;
|
|
7226
|
+
} | {
|
|
7227
|
+
/** @constant */
|
|
7228
|
+
kind: "narrate";
|
|
7229
|
+
};
|
|
7230
|
+
affordances: ({
|
|
7231
|
+
/** @constant */
|
|
7232
|
+
id: "sourceSync.findFiles";
|
|
7233
|
+
} | {
|
|
7234
|
+
/** @constant */
|
|
7235
|
+
id: "integrations.connectGoogleDrive";
|
|
7236
|
+
} | {
|
|
7237
|
+
/** @constant */
|
|
7238
|
+
id: "sourceSync.enable";
|
|
7239
|
+
} | {
|
|
7240
|
+
/** @constant */
|
|
7241
|
+
id: "billing.open";
|
|
7242
|
+
} | {
|
|
7243
|
+
/** @constant */
|
|
7244
|
+
id: "orgStructure.reanalyze";
|
|
7245
|
+
} | {
|
|
7246
|
+
/** @constant */
|
|
7247
|
+
id: "hris.resyncDirectory";
|
|
7248
|
+
})[];
|
|
7249
|
+
} | {
|
|
7250
|
+
/** @constant */
|
|
7251
|
+
workflowType: "org-structure/reanalyze";
|
|
7252
|
+
executionEpoch: number;
|
|
7253
|
+
/** @enum {string} */
|
|
7254
|
+
kind: "produced" | "empty" | "partial" | "stopped" | "failed" | "abandoned" | "unknown";
|
|
7255
|
+
/** @enum {string} */
|
|
7256
|
+
reason: "proposal_ready" | "directory_synced" | "analysis_already_running" | "proposal_blocked" | "no_sync_run" | "no_persons" | "reporting_not_keyed" | "stopped_by_user" | "sync_failed" | "snapshot_too_large" | "model_failed" | "run_too_large" | "placement_failed" | "internal_error" | "abandoned" | "unrecognized_terminal_state";
|
|
7257
|
+
facts: {
|
|
7258
|
+
departmentCount: number;
|
|
7259
|
+
teamCount: number;
|
|
7260
|
+
placedCount: number;
|
|
7261
|
+
reviewItemCount: number;
|
|
7262
|
+
} | null;
|
|
7263
|
+
disposition: {
|
|
7264
|
+
/** @constant */
|
|
7265
|
+
kind: "review";
|
|
7266
|
+
/** @enum {string} */
|
|
7267
|
+
requestType: "org-structure/review" | "source-sync/candidates" | "source-sync/synthesis";
|
|
7268
|
+
requestId: string;
|
|
7269
|
+
} | {
|
|
7270
|
+
/** @constant */
|
|
7271
|
+
kind: "narrate";
|
|
7272
|
+
};
|
|
7273
|
+
affordances: ({
|
|
7274
|
+
/** @constant */
|
|
7275
|
+
id: "sourceSync.findFiles";
|
|
7276
|
+
} | {
|
|
7277
|
+
/** @constant */
|
|
7278
|
+
id: "integrations.connectGoogleDrive";
|
|
7279
|
+
} | {
|
|
7280
|
+
/** @constant */
|
|
7281
|
+
id: "sourceSync.enable";
|
|
7282
|
+
} | {
|
|
7283
|
+
/** @constant */
|
|
7284
|
+
id: "billing.open";
|
|
7285
|
+
} | {
|
|
7286
|
+
/** @constant */
|
|
7287
|
+
id: "orgStructure.reanalyze";
|
|
7288
|
+
} | {
|
|
7289
|
+
/** @constant */
|
|
7290
|
+
id: "hris.resyncDirectory";
|
|
7291
|
+
})[];
|
|
7292
|
+
}) | null;
|
|
7007
7293
|
error?: string;
|
|
7008
7294
|
capabilities: {
|
|
7009
7295
|
canStop: boolean;
|
|
@@ -7027,6 +7313,26 @@ export interface components {
|
|
|
7027
7313
|
/** @enum {string} */
|
|
7028
7314
|
result: "delivered" | "deferred" | "busy" | "skipped" | "not_settled";
|
|
7029
7315
|
};
|
|
7316
|
+
AffordanceStateResponse: {
|
|
7317
|
+
entries: {
|
|
7318
|
+
/** @enum {string} */
|
|
7319
|
+
id: "sourceSync.findFiles" | "integrations.connectGoogleDrive" | "sourceSync.enable" | "billing.open" | "orgStructure.reanalyze" | "hris.resyncDirectory" | "review.open";
|
|
7320
|
+
/** @enum {string} */
|
|
7321
|
+
policy: "allowed" | "blocked";
|
|
7322
|
+
availability: {
|
|
7323
|
+
/** @constant */
|
|
7324
|
+
state: "available";
|
|
7325
|
+
} | {
|
|
7326
|
+
/** @constant */
|
|
7327
|
+
state: "already_satisfied";
|
|
7328
|
+
} | {
|
|
7329
|
+
/** @constant */
|
|
7330
|
+
state: "unavailable";
|
|
7331
|
+
/** @enum {string} */
|
|
7332
|
+
reason: "conflicting_operation" | "missing_dependency" | "resource_gone" | "temporarily_disabled";
|
|
7333
|
+
};
|
|
7334
|
+
}[];
|
|
7335
|
+
};
|
|
7030
7336
|
CompanyMdListResponse: {
|
|
7031
7337
|
items: {
|
|
7032
7338
|
id: string;
|
|
@@ -12949,6 +13255,33 @@ export interface operations {
|
|
|
12949
13255
|
};
|
|
12950
13256
|
};
|
|
12951
13257
|
};
|
|
13258
|
+
syncBambooHrNow: {
|
|
13259
|
+
parameters: {
|
|
13260
|
+
query?: never;
|
|
13261
|
+
header?: never;
|
|
13262
|
+
path?: never;
|
|
13263
|
+
cookie?: never;
|
|
13264
|
+
};
|
|
13265
|
+
requestBody?: never;
|
|
13266
|
+
responses: {
|
|
13267
|
+
/** @description Sync run summary */
|
|
13268
|
+
200: {
|
|
13269
|
+
headers: {
|
|
13270
|
+
[name: string]: unknown;
|
|
13271
|
+
};
|
|
13272
|
+
content: {
|
|
13273
|
+
"application/json": components["schemas"]["BambooHrSyncRunResponse"];
|
|
13274
|
+
};
|
|
13275
|
+
};
|
|
13276
|
+
/** @description No active BambooHR connection, or BambooHR no longer recognizes the organization */
|
|
13277
|
+
400: {
|
|
13278
|
+
headers: {
|
|
13279
|
+
[name: string]: unknown;
|
|
13280
|
+
};
|
|
13281
|
+
content?: never;
|
|
13282
|
+
};
|
|
13283
|
+
};
|
|
13284
|
+
};
|
|
12952
13285
|
getOrgReconciliation: {
|
|
12953
13286
|
parameters: {
|
|
12954
13287
|
query?: never;
|
|
@@ -13096,6 +13429,35 @@ export interface operations {
|
|
|
13096
13429
|
};
|
|
13097
13430
|
};
|
|
13098
13431
|
};
|
|
13432
|
+
runOrgStructureInference: {
|
|
13433
|
+
parameters: {
|
|
13434
|
+
query?: never;
|
|
13435
|
+
header?: never;
|
|
13436
|
+
path?: never;
|
|
13437
|
+
cookie?: never;
|
|
13438
|
+
};
|
|
13439
|
+
requestBody?: never;
|
|
13440
|
+
responses: {
|
|
13441
|
+
/** @description A named refusal with its operator-facing next step: no directory imported yet, a sync that imported nobody, or a credential whose sync could not key reporting edges (reporting_not_keyed) */
|
|
13442
|
+
200: {
|
|
13443
|
+
headers: {
|
|
13444
|
+
[name: string]: unknown;
|
|
13445
|
+
};
|
|
13446
|
+
content: {
|
|
13447
|
+
"application/json": components["schemas"]["RunStructureInferenceRefusal"];
|
|
13448
|
+
};
|
|
13449
|
+
};
|
|
13450
|
+
/** @description A run is under way — freshly launched, or already in flight (alreadyRunning: true). Carries the runId the poll surface matches against and the workflowId of the org-structure/reanalyze workflow it executes (null only when the joined run predates the workflow launch) */
|
|
13451
|
+
202: {
|
|
13452
|
+
headers: {
|
|
13453
|
+
[name: string]: unknown;
|
|
13454
|
+
};
|
|
13455
|
+
content: {
|
|
13456
|
+
"application/json": components["schemas"]["RunStructureInferenceAccepted"];
|
|
13457
|
+
};
|
|
13458
|
+
};
|
|
13459
|
+
};
|
|
13460
|
+
};
|
|
13099
13461
|
getAnalysisWorkflow: {
|
|
13100
13462
|
parameters: {
|
|
13101
13463
|
query?: never;
|
|
@@ -13213,6 +13575,42 @@ export interface operations {
|
|
|
13213
13575
|
};
|
|
13214
13576
|
};
|
|
13215
13577
|
};
|
|
13578
|
+
getAffordanceState: {
|
|
13579
|
+
parameters: {
|
|
13580
|
+
query: {
|
|
13581
|
+
ids: string;
|
|
13582
|
+
};
|
|
13583
|
+
header?: never;
|
|
13584
|
+
path?: never;
|
|
13585
|
+
cookie?: never;
|
|
13586
|
+
};
|
|
13587
|
+
requestBody?: never;
|
|
13588
|
+
responses: {
|
|
13589
|
+
/** @description Policy and availability per requested affordance id, in request order */
|
|
13590
|
+
200: {
|
|
13591
|
+
headers: {
|
|
13592
|
+
[name: string]: unknown;
|
|
13593
|
+
};
|
|
13594
|
+
content: {
|
|
13595
|
+
"application/json": components["schemas"]["AffordanceStateResponse"];
|
|
13596
|
+
};
|
|
13597
|
+
};
|
|
13598
|
+
/** @description An id is not a known affordance, the list is empty, or it is too long */
|
|
13599
|
+
400: {
|
|
13600
|
+
headers: {
|
|
13601
|
+
[name: string]: unknown;
|
|
13602
|
+
};
|
|
13603
|
+
content?: never;
|
|
13604
|
+
};
|
|
13605
|
+
/** @description The viewer is not an active member of the session org */
|
|
13606
|
+
403: {
|
|
13607
|
+
headers: {
|
|
13608
|
+
[name: string]: unknown;
|
|
13609
|
+
};
|
|
13610
|
+
content?: never;
|
|
13611
|
+
};
|
|
13612
|
+
};
|
|
13613
|
+
};
|
|
13216
13614
|
getCompanyMdTree: {
|
|
13217
13615
|
parameters: {
|
|
13218
13616
|
query?: {
|
|
@@ -9,6 +9,7 @@ export const openApiRoutes = {
|
|
|
9
9
|
'/api/account/deletion-eligibility': ['GET'],
|
|
10
10
|
'/api/account/sessions': ['GET'],
|
|
11
11
|
'/api/account/sessions/{sessionId}': ['DELETE'],
|
|
12
|
+
'/api/affordances/state': ['GET'],
|
|
12
13
|
'/api/analysis-workflows/{id}': ['GET'],
|
|
13
14
|
'/api/analysis-workflows/{id}/settlement': ['POST'],
|
|
14
15
|
'/api/analysis-workflows/{id}/stop': ['POST'],
|
|
@@ -101,6 +102,7 @@ export const openApiRoutes = {
|
|
|
101
102
|
'/api/factory/quality/plans/{planId}/decision': ['GET'],
|
|
102
103
|
'/api/factory/snapshot': ['GET'],
|
|
103
104
|
'/api/ingestion/operations/{id}': ['GET'],
|
|
105
|
+
'/api/integrations/bamboohr/sync': ['POST'],
|
|
104
106
|
'/api/internal-admin/impersonate/end': ['POST'],
|
|
105
107
|
'/api/internal-admin/impersonate/session': ['GET'],
|
|
106
108
|
'/api/internal-admin/impersonate/start': ['POST'],
|
|
@@ -181,6 +183,7 @@ export const openApiRoutes = {
|
|
|
181
183
|
'/api/org/structure-findings': ['GET'],
|
|
182
184
|
'/api/org/structure-findings/{findingId}/dismiss': ['POST'],
|
|
183
185
|
'/api/org/structure-findings/{findingId}/reopen': ['POST'],
|
|
186
|
+
'/api/org/structure-inference/runs': ['POST'],
|
|
184
187
|
'/api/org/system-events': ['GET'],
|
|
185
188
|
'/api/org/system-events/{id}/acknowledge': ['POST'],
|
|
186
189
|
'/api/org/transfer-eligibility': ['GET'],
|
package/src/workflows/README.md
CHANGED
|
@@ -32,7 +32,8 @@ so every producer, validator and renderer agrees on it.
|
|
|
32
32
|
- **Source Sync registers two flows.** `source-sync/discover` (Stage 1)
|
|
33
33
|
retains nothing; `source-sync/synthesize` (Stage 4) runs only after a person
|
|
34
34
|
approved the exact set it reads.
|
|
35
|
-
- **Every type has a typed outcome** (`outcome.ts`,
|
|
35
|
+
- **Every type has a typed outcome** (`outcome.ts`, tables in
|
|
36
|
+
`outcome-reasons.ts`; control ADR-CTRL-540). A
|
|
36
37
|
terminal transition is classified once, by the backend, into a per-type
|
|
37
38
|
member of `WorkflowOutcome`: a closed `reason`, typed count-only `facts`, a
|
|
38
39
|
`kind` that is a function of the reason (`*_OUTCOME_KIND_OF_REASON`), and an
|
|
@@ -68,11 +69,12 @@ so every producer, validator and renderer agrees on it.
|
|
|
68
69
|
## Public API
|
|
69
70
|
|
|
70
71
|
- `ANALYSIS_WORKFLOW_TYPES`, `WorkflowType`, `isWorkflowType` (`types.ts`).
|
|
71
|
-
- `WorkflowOutcomeSchema` / `WorkflowOutcome
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
- `WorkflowOutcomeSchema` / `WorkflowOutcome`, the per-type member schemas and
|
|
73
|
+
`WorkflowOutcomeDispositionSchema` (`outcome.ts`).
|
|
74
|
+
- `WORKFLOW_OUTCOME_KINDS` and the per-type reason tables and fact schemas
|
|
75
|
+
(`outcome-reasons.ts`).
|
|
74
76
|
- `DISCOVER_AFFORDANCES_OF_REASON`, `SYNTHESIZE_AFFORDANCES_OF_REASON`,
|
|
75
|
-
`ORG_STRUCTURE_AFFORDANCES_OF_REASON` (`outcome.ts`).
|
|
77
|
+
`ORG_STRUCTURE_AFFORDANCES_OF_REASON` (`outcome-reasons.ts`).
|
|
76
78
|
- `WORKFLOW_AFFORDANCES_OF_REASON`, `affordancesOfReason`,
|
|
77
79
|
`affordancesOfOutcome` (`affordances-of-outcome.ts`).
|
|
78
80
|
- `SETTLEMENT_AUDIENCE_POLICIES`, `SETTLEMENT_COVERING_KINDS`,
|
|
@@ -6,11 +6,8 @@ import {
|
|
|
6
6
|
affordancesOfOutcome,
|
|
7
7
|
affordancesOfReason,
|
|
8
8
|
} from "../affordances-of-outcome";
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
WorkflowOutcomeSchema,
|
|
12
|
-
type WorkflowOutcome,
|
|
13
|
-
} from "../outcome";
|
|
9
|
+
import { WorkflowOutcomeSchema, type WorkflowOutcome } from "../outcome";
|
|
10
|
+
import { ORG_STRUCTURE_AFFORDANCES_OF_REASON } from "../outcome-reasons";
|
|
14
11
|
import { ANALYSIS_WORKFLOW_TYPES } from "../types";
|
|
15
12
|
|
|
16
13
|
const review = {
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
toExplainedOutcome,
|
|
17
17
|
type DeferredRoute,
|
|
18
18
|
} from "../deferred-route";
|
|
19
|
+
import { WorkflowOutcomeSchema, type WorkflowOutcome } from "../outcome";
|
|
19
20
|
import {
|
|
20
21
|
DISCOVER_AFFORDANCES_OF_REASON,
|
|
21
22
|
DISCOVER_OUTCOME_KIND_OF_REASON,
|
|
@@ -23,9 +24,7 @@ import {
|
|
|
23
24
|
ORG_STRUCTURE_OUTCOME_KIND_OF_REASON,
|
|
24
25
|
SYNTHESIZE_AFFORDANCES_OF_REASON,
|
|
25
26
|
SYNTHESIZE_OUTCOME_KIND_OF_REASON,
|
|
26
|
-
|
|
27
|
-
type WorkflowOutcome,
|
|
28
|
-
} from "../outcome";
|
|
27
|
+
} from "../outcome-reasons";
|
|
29
28
|
|
|
30
29
|
// (kind table, offer table, route table) per outcome family. Built here rather
|
|
31
30
|
// than exported so the rules stay pinned without widening the public surface.
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
OfferedAffordanceSchema,
|
|
6
6
|
} from "../../affordances/affordance";
|
|
7
7
|
import type { WorkflowType } from "../types";
|
|
8
|
+
import { WorkflowOutcomeSchema, type WorkflowOutcome } from "../outcome";
|
|
8
9
|
import {
|
|
9
10
|
DISCOVER_AFFORDANCES_OF_REASON,
|
|
10
11
|
DISCOVER_OUTCOME_KIND_OF_REASON,
|
|
@@ -13,9 +14,7 @@ import {
|
|
|
13
14
|
SYNTHESIZE_AFFORDANCES_OF_REASON,
|
|
14
15
|
SYNTHESIZE_OUTCOME_KIND_OF_REASON,
|
|
15
16
|
WORKFLOW_OUTCOME_KINDS,
|
|
16
|
-
|
|
17
|
-
type WorkflowOutcome,
|
|
18
|
-
} from "../outcome";
|
|
17
|
+
} from "../outcome-reasons";
|
|
19
18
|
|
|
20
19
|
// Compile-time: every registered workflow type has an outcome member, and the
|
|
21
20
|
// union names no type that is not registered.
|
|
@@ -9,13 +9,12 @@
|
|
|
9
9
|
* offered next steps are one list built one way.
|
|
10
10
|
*/
|
|
11
11
|
import type { Affordance, OfferedAffordance } from "../affordances/affordance";
|
|
12
|
+
import type { WorkflowOutcome, WorkflowOutcomeOf } from "./outcome";
|
|
12
13
|
import {
|
|
13
14
|
DISCOVER_AFFORDANCES_OF_REASON,
|
|
14
15
|
ORG_STRUCTURE_AFFORDANCES_OF_REASON,
|
|
15
16
|
SYNTHESIZE_AFFORDANCES_OF_REASON,
|
|
16
|
-
|
|
17
|
-
type WorkflowOutcomeOf,
|
|
18
|
-
} from "./outcome";
|
|
17
|
+
} from "./outcome-reasons";
|
|
19
18
|
import type { WorkflowType } from "./types";
|
|
20
19
|
|
|
21
20
|
/** Every workflow type's offer table, total over the type union. */
|
|
@@ -29,16 +29,18 @@
|
|
|
29
29
|
import { z } from "zod";
|
|
30
30
|
|
|
31
31
|
import type {
|
|
32
|
-
DiscoverOutcomeReason,
|
|
33
32
|
DiscoverWorkflowOutcome,
|
|
34
33
|
HrisConnectWorkflowOutcome,
|
|
35
|
-
OrgStructureOutcomeReason,
|
|
36
34
|
ReanalyzeWorkflowOutcome,
|
|
37
|
-
SynthesizeOutcomeReason,
|
|
38
35
|
SynthesizeWorkflowOutcome,
|
|
39
36
|
WorkflowOutcome,
|
|
40
37
|
WorkflowOutcomeOf,
|
|
41
38
|
} from "./outcome";
|
|
39
|
+
import type {
|
|
40
|
+
DiscoverOutcomeReason,
|
|
41
|
+
OrgStructureOutcomeReason,
|
|
42
|
+
SynthesizeOutcomeReason,
|
|
43
|
+
} from "./outcome-reasons";
|
|
42
44
|
import type { WorkflowType } from "./types";
|
|
43
45
|
|
|
44
46
|
/** Who a routed settlement is addressed to; resolved and frozen by the backend. */
|
package/src/workflows/index.ts
CHANGED
|
@@ -14,35 +14,41 @@ export { ANALYSIS_WORKFLOW_TYPES, isWorkflowType } from "./types";
|
|
|
14
14
|
export type {
|
|
15
15
|
DiscoverOutcomeFacts,
|
|
16
16
|
DiscoverOutcomeReason,
|
|
17
|
-
DiscoverWorkflowOutcome,
|
|
18
|
-
HrisConnectWorkflowOutcome,
|
|
19
17
|
OrgStructureOutcomeFacts,
|
|
20
18
|
OrgStructureOutcomeReason,
|
|
21
|
-
ReanalyzeWorkflowOutcome,
|
|
22
19
|
SynthesizeOutcomeFacts,
|
|
23
20
|
SynthesizeOutcomeReason,
|
|
24
|
-
SynthesizeWorkflowOutcome,
|
|
25
|
-
WorkflowOutcome,
|
|
26
|
-
WorkflowOutcomeDisposition,
|
|
27
21
|
WorkflowOutcomeKind,
|
|
28
|
-
|
|
29
|
-
} from "./outcome";
|
|
22
|
+
} from "./outcome-reasons";
|
|
30
23
|
|
|
31
24
|
export {
|
|
32
25
|
DISCOVER_AFFORDANCES_OF_REASON,
|
|
33
26
|
DISCOVER_OUTCOME_KIND_OF_REASON,
|
|
34
27
|
DiscoverOutcomeFactsSchema,
|
|
35
|
-
DiscoverWorkflowOutcomeSchema,
|
|
36
|
-
HrisConnectWorkflowOutcomeSchema,
|
|
37
28
|
ORG_STRUCTURE_AFFORDANCES_OF_REASON,
|
|
38
29
|
ORG_STRUCTURE_OUTCOME_KIND_OF_REASON,
|
|
39
30
|
OrgStructureOutcomeFactsSchema,
|
|
40
|
-
ReanalyzeWorkflowOutcomeSchema,
|
|
41
31
|
SYNTHESIZE_AFFORDANCES_OF_REASON,
|
|
42
32
|
SYNTHESIZE_OUTCOME_KIND_OF_REASON,
|
|
43
33
|
SynthesizeOutcomeFactsSchema,
|
|
44
|
-
SynthesizeWorkflowOutcomeSchema,
|
|
45
34
|
WORKFLOW_OUTCOME_KINDS,
|
|
35
|
+
} from "./outcome-reasons";
|
|
36
|
+
|
|
37
|
+
export type {
|
|
38
|
+
DiscoverWorkflowOutcome,
|
|
39
|
+
HrisConnectWorkflowOutcome,
|
|
40
|
+
ReanalyzeWorkflowOutcome,
|
|
41
|
+
SynthesizeWorkflowOutcome,
|
|
42
|
+
WorkflowOutcome,
|
|
43
|
+
WorkflowOutcomeDisposition,
|
|
44
|
+
WorkflowOutcomeOf,
|
|
45
|
+
} from "./outcome";
|
|
46
|
+
|
|
47
|
+
export {
|
|
48
|
+
DiscoverWorkflowOutcomeSchema,
|
|
49
|
+
HrisConnectWorkflowOutcomeSchema,
|
|
50
|
+
ReanalyzeWorkflowOutcomeSchema,
|
|
51
|
+
SynthesizeWorkflowOutcomeSchema,
|
|
46
52
|
WorkflowOutcomeDispositionSchema,
|
|
47
53
|
WorkflowOutcomeSchema,
|
|
48
54
|
} from "./outcome";
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The per-type vocabulary of a workflow outcome (control ADR-CTRL-540): the
|
|
3
|
+
* shared `kind` list and, for every workflow type, its closed `reason` union,
|
|
4
|
+
* the `kind` each reason fixes, the affordances each reason offers, and the
|
|
5
|
+
* typed `facts` it reports.
|
|
6
|
+
*
|
|
7
|
+
* Tables only. `./outcome.ts` builds the outcome schemas from them and states
|
|
8
|
+
* the invariants they uphold (per-type and closed, kind and offer as functions
|
|
9
|
+
* of reason, facts are counts).
|
|
10
|
+
*
|
|
11
|
+
* An ending is one row in a `*_OUTCOME_KIND_OF_REASON` table and one in the
|
|
12
|
+
* matching `*_AFFORDANCES_OF_REASON` table, whose `satisfies` refuses a
|
|
13
|
+
* missing row.
|
|
14
|
+
*/
|
|
15
|
+
import { z } from "zod";
|
|
16
|
+
|
|
17
|
+
import type { OfferedAffordance } from "../affordances/affordance";
|
|
18
|
+
|
|
19
|
+
/** The shape of an ending, shared by every workflow type. */
|
|
20
|
+
export const WORKFLOW_OUTCOME_KINDS = [
|
|
21
|
+
/** The run produced what it is for. */
|
|
22
|
+
"produced",
|
|
23
|
+
/** The run finished and produced nothing. */
|
|
24
|
+
"empty",
|
|
25
|
+
/** The run finished short of full coverage (a budget or ceiling). */
|
|
26
|
+
"partial",
|
|
27
|
+
/** A person stopped the run; Continue may begin a new execution epoch. */
|
|
28
|
+
"stopped",
|
|
29
|
+
/** The run failed. */
|
|
30
|
+
"failed",
|
|
31
|
+
/** The run went silent and the reconciler closed it. */
|
|
32
|
+
"abandoned",
|
|
33
|
+
/** A terminal transition the classifier did not recognize. */
|
|
34
|
+
"unknown",
|
|
35
|
+
] as const;
|
|
36
|
+
|
|
37
|
+
export type WorkflowOutcomeKind = (typeof WORKFLOW_OUTCOME_KINDS)[number];
|
|
38
|
+
|
|
39
|
+
const Count = z.number().int().nonnegative();
|
|
40
|
+
|
|
41
|
+
// The affordances an ending may offer, named once for the tables below.
|
|
42
|
+
const FIND_FILES = { id: "sourceSync.findFiles" } as const;
|
|
43
|
+
const CONNECT_GOOGLE_DRIVE = { id: "integrations.connectGoogleDrive" } as const;
|
|
44
|
+
const ENABLE_SOURCE_SYNC = { id: "sourceSync.enable" } as const;
|
|
45
|
+
const OPEN_BILLING = { id: "billing.open" } as const;
|
|
46
|
+
const REANALYZE_STRUCTURE = { id: "orgStructure.reanalyze" } as const;
|
|
47
|
+
const RESYNC_DIRECTORY = { id: "hris.resyncDirectory" } as const;
|
|
48
|
+
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
// source-sync/discover
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
|
|
53
|
+
/** Why a Drive discovery run ended the way it did. */
|
|
54
|
+
export const DISCOVER_OUTCOME_KIND_OF_REASON = {
|
|
55
|
+
candidates_found: "produced",
|
|
56
|
+
nothing_found: "empty",
|
|
57
|
+
nothing_relevant: "empty",
|
|
58
|
+
budget_exhausted: "partial",
|
|
59
|
+
file_ceiling: "partial",
|
|
60
|
+
stopped_by_user: "stopped",
|
|
61
|
+
plan_coverage_refused: "failed",
|
|
62
|
+
billing_refused: "failed",
|
|
63
|
+
drive_auth: "failed",
|
|
64
|
+
drive_unavailable: "failed",
|
|
65
|
+
no_connection: "failed",
|
|
66
|
+
source_sync_off: "failed",
|
|
67
|
+
internal_error: "failed",
|
|
68
|
+
abandoned: "abandoned",
|
|
69
|
+
unrecognized_terminal_state: "unknown",
|
|
70
|
+
} as const satisfies Record<string, WorkflowOutcomeKind>;
|
|
71
|
+
|
|
72
|
+
export type DiscoverOutcomeReason =
|
|
73
|
+
keyof typeof DISCOVER_OUTCOME_KIND_OF_REASON;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* What each discovery ending offers (control ADR affordance-system). TOTAL: an
|
|
77
|
+
* empty list is a decision that no grounded action changes that ending — a
|
|
78
|
+
* re-run of the same search is not "broadening" it, and nothing raises a budget.
|
|
79
|
+
*/
|
|
80
|
+
export const DISCOVER_AFFORDANCES_OF_REASON = {
|
|
81
|
+
candidates_found: [],
|
|
82
|
+
nothing_found: [],
|
|
83
|
+
nothing_relevant: [],
|
|
84
|
+
budget_exhausted: [],
|
|
85
|
+
file_ceiling: [],
|
|
86
|
+
stopped_by_user: [],
|
|
87
|
+
plan_coverage_refused: [],
|
|
88
|
+
billing_refused: [OPEN_BILLING],
|
|
89
|
+
drive_auth: [CONNECT_GOOGLE_DRIVE],
|
|
90
|
+
drive_unavailable: [FIND_FILES],
|
|
91
|
+
no_connection: [CONNECT_GOOGLE_DRIVE],
|
|
92
|
+
source_sync_off: [ENABLE_SOURCE_SYNC],
|
|
93
|
+
internal_error: [FIND_FILES],
|
|
94
|
+
abandoned: [FIND_FILES],
|
|
95
|
+
unrecognized_terminal_state: [],
|
|
96
|
+
} as const satisfies Record<
|
|
97
|
+
DiscoverOutcomeReason,
|
|
98
|
+
readonly OfferedAffordance[]
|
|
99
|
+
>;
|
|
100
|
+
|
|
101
|
+
/** The counts a discovery run reports at its end. */
|
|
102
|
+
export const DiscoverOutcomeFactsSchema = z
|
|
103
|
+
.object({
|
|
104
|
+
probesTotal: Count,
|
|
105
|
+
probesDone: Count,
|
|
106
|
+
filesSeen: Count,
|
|
107
|
+
filesShown: Count,
|
|
108
|
+
filesHidden: Count,
|
|
109
|
+
filesDropped: Count,
|
|
110
|
+
coveragePercent: z.number().min(0).max(100).nullable(),
|
|
111
|
+
})
|
|
112
|
+
.strict();
|
|
113
|
+
|
|
114
|
+
export type DiscoverOutcomeFacts = z.infer<typeof DiscoverOutcomeFactsSchema>;
|
|
115
|
+
|
|
116
|
+
// ---------------------------------------------------------------------------
|
|
117
|
+
// source-sync/synthesize
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
|
|
120
|
+
/** Why a synthesis (landing then drafting) run ended the way it did. */
|
|
121
|
+
export const SYNTHESIZE_OUTCOME_KIND_OF_REASON = {
|
|
122
|
+
updates_ready: "produced",
|
|
123
|
+
updates_applied: "produced",
|
|
124
|
+
stopped_by_user: "stopped",
|
|
125
|
+
paused_billing: "failed",
|
|
126
|
+
synthesis_incomplete: "failed",
|
|
127
|
+
approval_mismatch: "failed",
|
|
128
|
+
landing_refused: "failed",
|
|
129
|
+
standing_order_refused: "failed",
|
|
130
|
+
no_connection: "failed",
|
|
131
|
+
source_sync_off: "failed",
|
|
132
|
+
internal_error: "failed",
|
|
133
|
+
abandoned: "abandoned",
|
|
134
|
+
unrecognized_terminal_state: "unknown",
|
|
135
|
+
} as const satisfies Record<string, WorkflowOutcomeKind>;
|
|
136
|
+
|
|
137
|
+
export type SynthesizeOutcomeReason =
|
|
138
|
+
keyof typeof SYNTHESIZE_OUTCOME_KIND_OF_REASON;
|
|
139
|
+
|
|
140
|
+
/** What each synthesis ending offers. TOTAL; an empty list is explicit. */
|
|
141
|
+
export const SYNTHESIZE_AFFORDANCES_OF_REASON = {
|
|
142
|
+
updates_ready: [],
|
|
143
|
+
updates_applied: [],
|
|
144
|
+
stopped_by_user: [],
|
|
145
|
+
paused_billing: [OPEN_BILLING],
|
|
146
|
+
synthesis_incomplete: [],
|
|
147
|
+
approval_mismatch: [],
|
|
148
|
+
landing_refused: [],
|
|
149
|
+
standing_order_refused: [],
|
|
150
|
+
no_connection: [CONNECT_GOOGLE_DRIVE],
|
|
151
|
+
source_sync_off: [ENABLE_SOURCE_SYNC],
|
|
152
|
+
internal_error: [],
|
|
153
|
+
abandoned: [],
|
|
154
|
+
unrecognized_terminal_state: [],
|
|
155
|
+
} as const satisfies Record<
|
|
156
|
+
SynthesizeOutcomeReason,
|
|
157
|
+
readonly OfferedAffordance[]
|
|
158
|
+
>;
|
|
159
|
+
|
|
160
|
+
/** The counts a synthesis run reports at its end. */
|
|
161
|
+
export const SynthesizeOutcomeFactsSchema = z
|
|
162
|
+
.object({
|
|
163
|
+
/** Approved scopes the run read. */
|
|
164
|
+
scopeCount: Count,
|
|
165
|
+
/** Authority or size violations that left the batch incomplete. */
|
|
166
|
+
violationCount: Count,
|
|
167
|
+
})
|
|
168
|
+
.strict();
|
|
169
|
+
|
|
170
|
+
export type SynthesizeOutcomeFacts = z.infer<
|
|
171
|
+
typeof SynthesizeOutcomeFactsSchema
|
|
172
|
+
>;
|
|
173
|
+
|
|
174
|
+
// ---------------------------------------------------------------------------
|
|
175
|
+
// org-structure/hris-connect and org-structure/reanalyze
|
|
176
|
+
// ---------------------------------------------------------------------------
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Why an org-structure analysis ended the way it did. Shared by both
|
|
180
|
+
* org-structure workflow types: they run the same analysis. The directory-only
|
|
181
|
+
* endings (`directory_synced`, `analysis_already_running`, `sync_failed`) occur
|
|
182
|
+
* only on `org-structure/hris-connect`, which syncs the directory first.
|
|
183
|
+
*/
|
|
184
|
+
export const ORG_STRUCTURE_OUTCOME_KIND_OF_REASON = {
|
|
185
|
+
proposal_ready: "produced",
|
|
186
|
+
directory_synced: "produced",
|
|
187
|
+
analysis_already_running: "produced",
|
|
188
|
+
proposal_blocked: "failed",
|
|
189
|
+
no_sync_run: "empty",
|
|
190
|
+
no_persons: "empty",
|
|
191
|
+
reporting_not_keyed: "empty",
|
|
192
|
+
stopped_by_user: "stopped",
|
|
193
|
+
sync_failed: "failed",
|
|
194
|
+
snapshot_too_large: "failed",
|
|
195
|
+
model_failed: "failed",
|
|
196
|
+
run_too_large: "failed",
|
|
197
|
+
placement_failed: "failed",
|
|
198
|
+
internal_error: "failed",
|
|
199
|
+
abandoned: "abandoned",
|
|
200
|
+
unrecognized_terminal_state: "unknown",
|
|
201
|
+
} as const satisfies Record<string, WorkflowOutcomeKind>;
|
|
202
|
+
|
|
203
|
+
export type OrgStructureOutcomeReason =
|
|
204
|
+
keyof typeof ORG_STRUCTURE_OUTCOME_KIND_OF_REASON;
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* What each org-structure ending offers; shared by both org-structure workflow
|
|
208
|
+
* types, like the kind table. TOTAL; an empty list is explicit.
|
|
209
|
+
*/
|
|
210
|
+
export const ORG_STRUCTURE_AFFORDANCES_OF_REASON = {
|
|
211
|
+
proposal_ready: [],
|
|
212
|
+
directory_synced: [],
|
|
213
|
+
analysis_already_running: [],
|
|
214
|
+
proposal_blocked: [],
|
|
215
|
+
no_sync_run: [RESYNC_DIRECTORY],
|
|
216
|
+
no_persons: [],
|
|
217
|
+
reporting_not_keyed: [],
|
|
218
|
+
stopped_by_user: [],
|
|
219
|
+
sync_failed: [RESYNC_DIRECTORY],
|
|
220
|
+
snapshot_too_large: [],
|
|
221
|
+
model_failed: [REANALYZE_STRUCTURE],
|
|
222
|
+
run_too_large: [],
|
|
223
|
+
placement_failed: [REANALYZE_STRUCTURE],
|
|
224
|
+
internal_error: [REANALYZE_STRUCTURE],
|
|
225
|
+
abandoned: [REANALYZE_STRUCTURE],
|
|
226
|
+
unrecognized_terminal_state: [],
|
|
227
|
+
} as const satisfies Record<
|
|
228
|
+
OrgStructureOutcomeReason,
|
|
229
|
+
readonly OfferedAffordance[]
|
|
230
|
+
>;
|
|
231
|
+
|
|
232
|
+
/** The counts a finished org-structure proposal carries. */
|
|
233
|
+
export const OrgStructureOutcomeFactsSchema = z
|
|
234
|
+
.object({
|
|
235
|
+
departmentCount: Count,
|
|
236
|
+
teamCount: Count,
|
|
237
|
+
placedCount: Count,
|
|
238
|
+
reviewItemCount: Count,
|
|
239
|
+
})
|
|
240
|
+
.strict();
|
|
241
|
+
|
|
242
|
+
export type OrgStructureOutcomeFacts = z.infer<
|
|
243
|
+
typeof OrgStructureOutcomeFactsSchema
|
|
244
|
+
>;
|
package/src/workflows/outcome.ts
CHANGED
|
@@ -16,8 +16,9 @@
|
|
|
16
16
|
* record: a renderer that switches on `reason` is exhaustive, and a new fact is
|
|
17
17
|
* a schema change, not a new spelling.
|
|
18
18
|
* - KIND IS A FUNCTION OF REASON. `kind` is carried for consumers that only care
|
|
19
|
-
* about the shape of the ending, but it is fixed by the per-type table
|
|
20
|
-
* (`*_OUTCOME_KIND_OF_REASON`) and the schema
|
|
19
|
+
* about the shape of the ending, but it is fixed by the per-type table
|
|
20
|
+
* (`*_OUTCOME_KIND_OF_REASON` in `./outcome-reasons.ts`) and the schema
|
|
21
|
+
* refuses any other pairing.
|
|
21
22
|
* - DISPOSITION IS EXPLICIT. `review` names the input request a person decides
|
|
22
23
|
* on; `narrate` means the ending is told, not reviewed. `produced` does not
|
|
23
24
|
* imply a review surface, and only a `produced` or `partial` outcome may carry
|
|
@@ -44,26 +45,19 @@ import {
|
|
|
44
45
|
type OfferedAffordance,
|
|
45
46
|
} from "../affordances/affordance";
|
|
46
47
|
import { INPUT_REQUEST_TYPES } from "../input-requests/types";
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
/** The run went silent and the reconciler closed it. */
|
|
61
|
-
"abandoned",
|
|
62
|
-
/** A terminal transition the classifier did not recognize. */
|
|
63
|
-
"unknown",
|
|
64
|
-
] as const;
|
|
65
|
-
|
|
66
|
-
export type WorkflowOutcomeKind = (typeof WORKFLOW_OUTCOME_KINDS)[number];
|
|
48
|
+
import {
|
|
49
|
+
DISCOVER_AFFORDANCES_OF_REASON,
|
|
50
|
+
DISCOVER_OUTCOME_KIND_OF_REASON,
|
|
51
|
+
DiscoverOutcomeFactsSchema,
|
|
52
|
+
ORG_STRUCTURE_AFFORDANCES_OF_REASON,
|
|
53
|
+
ORG_STRUCTURE_OUTCOME_KIND_OF_REASON,
|
|
54
|
+
OrgStructureOutcomeFactsSchema,
|
|
55
|
+
SYNTHESIZE_AFFORDANCES_OF_REASON,
|
|
56
|
+
SYNTHESIZE_OUTCOME_KIND_OF_REASON,
|
|
57
|
+
SynthesizeOutcomeFactsSchema,
|
|
58
|
+
WORKFLOW_OUTCOME_KINDS,
|
|
59
|
+
type WorkflowOutcomeKind,
|
|
60
|
+
} from "./outcome-reasons";
|
|
67
61
|
|
|
68
62
|
const KindSchema = z.enum(WORKFLOW_OUTCOME_KINDS);
|
|
69
63
|
|
|
@@ -85,211 +79,6 @@ export type WorkflowOutcomeDisposition = z.infer<
|
|
|
85
79
|
|
|
86
80
|
const Count = z.number().int().nonnegative();
|
|
87
81
|
|
|
88
|
-
// The affordances an ending may offer, named once for the tables below.
|
|
89
|
-
const FIND_FILES = { id: "sourceSync.findFiles" } as const;
|
|
90
|
-
const CONNECT_GOOGLE_DRIVE = { id: "integrations.connectGoogleDrive" } as const;
|
|
91
|
-
const ENABLE_SOURCE_SYNC = { id: "sourceSync.enable" } as const;
|
|
92
|
-
const OPEN_BILLING = { id: "billing.open" } as const;
|
|
93
|
-
const REANALYZE_STRUCTURE = { id: "orgStructure.reanalyze" } as const;
|
|
94
|
-
const RESYNC_DIRECTORY = { id: "hris.resyncDirectory" } as const;
|
|
95
|
-
|
|
96
|
-
// ---------------------------------------------------------------------------
|
|
97
|
-
// source-sync/discover
|
|
98
|
-
// ---------------------------------------------------------------------------
|
|
99
|
-
|
|
100
|
-
/** Why a Drive discovery run ended the way it did. */
|
|
101
|
-
export const DISCOVER_OUTCOME_KIND_OF_REASON = {
|
|
102
|
-
candidates_found: "produced",
|
|
103
|
-
nothing_found: "empty",
|
|
104
|
-
nothing_relevant: "empty",
|
|
105
|
-
budget_exhausted: "partial",
|
|
106
|
-
file_ceiling: "partial",
|
|
107
|
-
stopped_by_user: "stopped",
|
|
108
|
-
plan_coverage_refused: "failed",
|
|
109
|
-
billing_refused: "failed",
|
|
110
|
-
drive_auth: "failed",
|
|
111
|
-
drive_unavailable: "failed",
|
|
112
|
-
no_connection: "failed",
|
|
113
|
-
source_sync_off: "failed",
|
|
114
|
-
internal_error: "failed",
|
|
115
|
-
abandoned: "abandoned",
|
|
116
|
-
unrecognized_terminal_state: "unknown",
|
|
117
|
-
} as const satisfies Record<string, WorkflowOutcomeKind>;
|
|
118
|
-
|
|
119
|
-
export type DiscoverOutcomeReason =
|
|
120
|
-
keyof typeof DISCOVER_OUTCOME_KIND_OF_REASON;
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* What each discovery ending offers (control ADR affordance-system). TOTAL: an
|
|
124
|
-
* empty list is a decision that no grounded action changes that ending — a
|
|
125
|
-
* re-run of the same search is not "broadening" it, and nothing raises a budget.
|
|
126
|
-
*/
|
|
127
|
-
export const DISCOVER_AFFORDANCES_OF_REASON = {
|
|
128
|
-
candidates_found: [],
|
|
129
|
-
nothing_found: [],
|
|
130
|
-
nothing_relevant: [],
|
|
131
|
-
budget_exhausted: [],
|
|
132
|
-
file_ceiling: [],
|
|
133
|
-
stopped_by_user: [],
|
|
134
|
-
plan_coverage_refused: [],
|
|
135
|
-
billing_refused: [OPEN_BILLING],
|
|
136
|
-
drive_auth: [CONNECT_GOOGLE_DRIVE],
|
|
137
|
-
drive_unavailable: [FIND_FILES],
|
|
138
|
-
no_connection: [CONNECT_GOOGLE_DRIVE],
|
|
139
|
-
source_sync_off: [ENABLE_SOURCE_SYNC],
|
|
140
|
-
internal_error: [FIND_FILES],
|
|
141
|
-
abandoned: [FIND_FILES],
|
|
142
|
-
unrecognized_terminal_state: [],
|
|
143
|
-
} as const satisfies Record<
|
|
144
|
-
DiscoverOutcomeReason,
|
|
145
|
-
readonly OfferedAffordance[]
|
|
146
|
-
>;
|
|
147
|
-
|
|
148
|
-
/** The counts a discovery run reports at its end. */
|
|
149
|
-
export const DiscoverOutcomeFactsSchema = z
|
|
150
|
-
.object({
|
|
151
|
-
probesTotal: Count,
|
|
152
|
-
probesDone: Count,
|
|
153
|
-
filesSeen: Count,
|
|
154
|
-
filesShown: Count,
|
|
155
|
-
filesHidden: Count,
|
|
156
|
-
filesDropped: Count,
|
|
157
|
-
coveragePercent: z.number().min(0).max(100).nullable(),
|
|
158
|
-
})
|
|
159
|
-
.strict();
|
|
160
|
-
|
|
161
|
-
export type DiscoverOutcomeFacts = z.infer<typeof DiscoverOutcomeFactsSchema>;
|
|
162
|
-
|
|
163
|
-
// ---------------------------------------------------------------------------
|
|
164
|
-
// source-sync/synthesize
|
|
165
|
-
// ---------------------------------------------------------------------------
|
|
166
|
-
|
|
167
|
-
/** Why a synthesis (landing then drafting) run ended the way it did. */
|
|
168
|
-
export const SYNTHESIZE_OUTCOME_KIND_OF_REASON = {
|
|
169
|
-
updates_ready: "produced",
|
|
170
|
-
updates_applied: "produced",
|
|
171
|
-
stopped_by_user: "stopped",
|
|
172
|
-
paused_billing: "failed",
|
|
173
|
-
synthesis_incomplete: "failed",
|
|
174
|
-
approval_mismatch: "failed",
|
|
175
|
-
landing_refused: "failed",
|
|
176
|
-
standing_order_refused: "failed",
|
|
177
|
-
no_connection: "failed",
|
|
178
|
-
source_sync_off: "failed",
|
|
179
|
-
internal_error: "failed",
|
|
180
|
-
abandoned: "abandoned",
|
|
181
|
-
unrecognized_terminal_state: "unknown",
|
|
182
|
-
} as const satisfies Record<string, WorkflowOutcomeKind>;
|
|
183
|
-
|
|
184
|
-
export type SynthesizeOutcomeReason =
|
|
185
|
-
keyof typeof SYNTHESIZE_OUTCOME_KIND_OF_REASON;
|
|
186
|
-
|
|
187
|
-
/** What each synthesis ending offers. TOTAL; an empty list is explicit. */
|
|
188
|
-
export const SYNTHESIZE_AFFORDANCES_OF_REASON = {
|
|
189
|
-
updates_ready: [],
|
|
190
|
-
updates_applied: [],
|
|
191
|
-
stopped_by_user: [],
|
|
192
|
-
paused_billing: [OPEN_BILLING],
|
|
193
|
-
synthesis_incomplete: [],
|
|
194
|
-
approval_mismatch: [],
|
|
195
|
-
landing_refused: [],
|
|
196
|
-
standing_order_refused: [],
|
|
197
|
-
no_connection: [CONNECT_GOOGLE_DRIVE],
|
|
198
|
-
source_sync_off: [ENABLE_SOURCE_SYNC],
|
|
199
|
-
internal_error: [],
|
|
200
|
-
abandoned: [],
|
|
201
|
-
unrecognized_terminal_state: [],
|
|
202
|
-
} as const satisfies Record<
|
|
203
|
-
SynthesizeOutcomeReason,
|
|
204
|
-
readonly OfferedAffordance[]
|
|
205
|
-
>;
|
|
206
|
-
|
|
207
|
-
/** The counts a synthesis run reports at its end. */
|
|
208
|
-
export const SynthesizeOutcomeFactsSchema = z
|
|
209
|
-
.object({
|
|
210
|
-
/** Approved scopes the run read. */
|
|
211
|
-
scopeCount: Count,
|
|
212
|
-
/** Authority or size violations that left the batch incomplete. */
|
|
213
|
-
violationCount: Count,
|
|
214
|
-
})
|
|
215
|
-
.strict();
|
|
216
|
-
|
|
217
|
-
export type SynthesizeOutcomeFacts = z.infer<
|
|
218
|
-
typeof SynthesizeOutcomeFactsSchema
|
|
219
|
-
>;
|
|
220
|
-
|
|
221
|
-
// ---------------------------------------------------------------------------
|
|
222
|
-
// org-structure/hris-connect and org-structure/reanalyze
|
|
223
|
-
// ---------------------------------------------------------------------------
|
|
224
|
-
|
|
225
|
-
/**
|
|
226
|
-
* Why an org-structure analysis ended the way it did. Shared by both
|
|
227
|
-
* org-structure workflow types: they run the same analysis. The directory-only
|
|
228
|
-
* endings (`directory_synced`, `analysis_already_running`, `sync_failed`) occur
|
|
229
|
-
* only on `org-structure/hris-connect`, which syncs the directory first.
|
|
230
|
-
*/
|
|
231
|
-
export const ORG_STRUCTURE_OUTCOME_KIND_OF_REASON = {
|
|
232
|
-
proposal_ready: "produced",
|
|
233
|
-
directory_synced: "produced",
|
|
234
|
-
analysis_already_running: "produced",
|
|
235
|
-
proposal_blocked: "failed",
|
|
236
|
-
no_sync_run: "empty",
|
|
237
|
-
no_persons: "empty",
|
|
238
|
-
reporting_not_keyed: "empty",
|
|
239
|
-
stopped_by_user: "stopped",
|
|
240
|
-
sync_failed: "failed",
|
|
241
|
-
snapshot_too_large: "failed",
|
|
242
|
-
model_failed: "failed",
|
|
243
|
-
run_too_large: "failed",
|
|
244
|
-
placement_failed: "failed",
|
|
245
|
-
internal_error: "failed",
|
|
246
|
-
abandoned: "abandoned",
|
|
247
|
-
unrecognized_terminal_state: "unknown",
|
|
248
|
-
} as const satisfies Record<string, WorkflowOutcomeKind>;
|
|
249
|
-
|
|
250
|
-
export type OrgStructureOutcomeReason =
|
|
251
|
-
keyof typeof ORG_STRUCTURE_OUTCOME_KIND_OF_REASON;
|
|
252
|
-
|
|
253
|
-
/**
|
|
254
|
-
* What each org-structure ending offers; shared by both org-structure workflow
|
|
255
|
-
* types, like the kind table. TOTAL; an empty list is explicit.
|
|
256
|
-
*/
|
|
257
|
-
export const ORG_STRUCTURE_AFFORDANCES_OF_REASON = {
|
|
258
|
-
proposal_ready: [],
|
|
259
|
-
directory_synced: [],
|
|
260
|
-
analysis_already_running: [],
|
|
261
|
-
proposal_blocked: [],
|
|
262
|
-
no_sync_run: [RESYNC_DIRECTORY],
|
|
263
|
-
no_persons: [],
|
|
264
|
-
reporting_not_keyed: [],
|
|
265
|
-
stopped_by_user: [],
|
|
266
|
-
sync_failed: [RESYNC_DIRECTORY],
|
|
267
|
-
snapshot_too_large: [],
|
|
268
|
-
model_failed: [REANALYZE_STRUCTURE],
|
|
269
|
-
run_too_large: [],
|
|
270
|
-
placement_failed: [REANALYZE_STRUCTURE],
|
|
271
|
-
internal_error: [REANALYZE_STRUCTURE],
|
|
272
|
-
abandoned: [REANALYZE_STRUCTURE],
|
|
273
|
-
unrecognized_terminal_state: [],
|
|
274
|
-
} as const satisfies Record<
|
|
275
|
-
OrgStructureOutcomeReason,
|
|
276
|
-
readonly OfferedAffordance[]
|
|
277
|
-
>;
|
|
278
|
-
|
|
279
|
-
/** The counts a finished org-structure proposal carries. */
|
|
280
|
-
export const OrgStructureOutcomeFactsSchema = z
|
|
281
|
-
.object({
|
|
282
|
-
departmentCount: Count,
|
|
283
|
-
teamCount: Count,
|
|
284
|
-
placedCount: Count,
|
|
285
|
-
reviewItemCount: Count,
|
|
286
|
-
})
|
|
287
|
-
.strict();
|
|
288
|
-
|
|
289
|
-
export type OrgStructureOutcomeFacts = z.infer<
|
|
290
|
-
typeof OrgStructureOutcomeFactsSchema
|
|
291
|
-
>;
|
|
292
|
-
|
|
293
82
|
// ---------------------------------------------------------------------------
|
|
294
83
|
// The union
|
|
295
84
|
// ---------------------------------------------------------------------------
|