wicked-crew 0.7.49 → 0.8.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/dist/api/discovery-source.d.ts +51 -0
- package/dist/api/discovery-source.d.ts.map +1 -0
- package/dist/api/discovery-source.js +176 -0
- package/dist/api/discovery-source.js.map +1 -0
- package/dist/api/governance-steering.d.ts +4 -5
- package/dist/api/governance-steering.d.ts.map +1 -1
- package/dist/api/governance-steering.js +11 -16
- package/dist/api/governance-steering.js.map +1 -1
- package/dist/api/recording.d.ts +23 -0
- package/dist/api/recording.d.ts.map +1 -1
- package/dist/api/recording.js +151 -4
- package/dist/api/recording.js.map +1 -1
- package/dist/api/routes.d.ts.map +1 -1
- package/dist/api/routes.js +28 -4
- package/dist/api/routes.js.map +1 -1
- package/dist/api/run-files.d.ts +13 -1
- package/dist/api/run-files.d.ts.map +1 -1
- package/dist/api/run-files.js +30 -6
- package/dist/api/run-files.js.map +1 -1
- package/dist/api/seat-standing.d.ts +16 -0
- package/dist/api/seat-standing.d.ts.map +1 -1
- package/dist/api/seat-standing.js +54 -4
- package/dist/api/seat-standing.js.map +1 -1
- package/dist/api/server.d.ts.map +1 -1
- package/dist/api/server.js +12 -0
- package/dist/api/server.js.map +1 -1
- package/dist/api/steering-landing.d.ts +7 -7
- package/dist/api/steering-landing.js +7 -7
- package/dist/core/adapter.d.ts +16 -1
- package/dist/core/adapter.d.ts.map +1 -1
- package/dist/core/adapter.js +35 -10
- package/dist/core/adapter.js.map +1 -1
- package/dist/interactive/doc-run-index.d.ts +10 -2
- package/dist/interactive/doc-run-index.d.ts.map +1 -1
- package/dist/interactive/doc-run-index.js +16 -3
- package/dist/interactive/doc-run-index.js.map +1 -1
- package/dist/projects/graph.d.ts.map +1 -1
- package/dist/projects/graph.js +10 -0
- package/dist/projects/graph.js.map +1 -1
- package/dist/projects/membership-index.d.ts +2 -0
- package/dist/projects/membership-index.d.ts.map +1 -1
- package/dist/projects/membership-index.js +8 -0
- package/dist/projects/membership-index.js.map +1 -1
- package/dist/qe/acceptance.d.ts +6 -1
- package/dist/qe/acceptance.d.ts.map +1 -1
- package/dist/qe/acceptance.js +11 -9
- package/dist/qe/acceptance.js.map +1 -1
- package/dist/qe/walkthrough-acceptance.d.ts +6 -0
- package/dist/qe/walkthrough-acceptance.d.ts.map +1 -1
- package/dist/qe/walkthrough-acceptance.js +12 -4
- package/dist/qe/walkthrough-acceptance.js.map +1 -1
- package/dist/studio/assets/archivo-latin-ext-wght-normal-C4zznr8T.woff2 +0 -0
- package/dist/studio/assets/archivo-latin-wght-normal-E0tuGl4L.woff2 +0 -0
- package/dist/studio/assets/index-BnJlrMxp.css +32 -0
- package/dist/studio/assets/index-DG0nwF7c.js +582 -0
- package/dist/studio/assets/inter-latin-ext-opsz-italic-BLMf5All.woff2 +0 -0
- package/dist/studio/assets/inter-latin-ext-opsz-normal-DpK-iCPk.woff2 +0 -0
- package/dist/studio/assets/inter-latin-opsz-italic-BbqH_2Ar.woff2 +0 -0
- package/dist/studio/assets/inter-latin-opsz-normal-BwkfbSeq.woff2 +0 -0
- package/dist/studio/assets/jetbrains-mono-latin-ext-wght-italic-BrDczivE.woff2 +0 -0
- package/dist/studio/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
- package/dist/studio/assets/jetbrains-mono-latin-wght-italic-B2M6KQje.woff2 +0 -0
- package/dist/studio/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
- package/dist/studio/editors/wicked-page/editor.json +35 -0
- package/dist/studio/editors/wicked-page/index.html +144 -0
- package/dist/studio/fonts/LICENSE-Archivo.txt +93 -0
- package/dist/studio/fonts/LICENSE-Inter.txt +93 -0
- package/dist/studio/fonts/LICENSE-JetBrainsMono.txt +93 -0
- package/dist/studio/index.html +3 -8
- package/dist/studio/testid-inventory.json +5801 -2440
- package/dist/watch/bounded-read.d.ts +26 -0
- package/dist/watch/bounded-read.d.ts.map +1 -0
- package/dist/watch/bounded-read.js +59 -0
- package/dist/watch/bounded-read.js.map +1 -0
- package/dist/watch/checks/discovery.d.ts +65 -0
- package/dist/watch/checks/discovery.d.ts.map +1 -0
- package/dist/watch/checks/discovery.js +168 -0
- package/dist/watch/checks/discovery.js.map +1 -0
- package/dist/watch/checks/index.d.ts.map +1 -1
- package/dist/watch/checks/index.js +7 -0
- package/dist/watch/checks/index.js.map +1 -1
- package/dist/watch/checks/scope-drift.d.ts +47 -0
- package/dist/watch/checks/scope-drift.d.ts.map +1 -0
- package/dist/watch/checks/scope-drift.js +212 -0
- package/dist/watch/checks/scope-drift.js.map +1 -0
- package/dist/watch/emit.d.ts +19 -0
- package/dist/watch/emit.d.ts.map +1 -1
- package/dist/watch/emit.js +144 -18
- package/dist/watch/emit.js.map +1 -1
- package/dist/watch/registry.d.ts +20 -11
- package/dist/watch/registry.d.ts.map +1 -1
- package/dist/watch/registry.js +50 -42
- package/dist/watch/registry.js.map +1 -1
- package/dist/watch/sources.d.ts +2 -1
- package/dist/watch/sources.d.ts.map +1 -1
- package/dist/watch/sources.js +2 -1
- package/dist/watch/sources.js.map +1 -1
- package/dist/watch/types.d.ts +42 -0
- package/dist/watch/types.d.ts.map +1 -1
- package/endpoint-manifest.json +14 -1
- package/package.json +3 -3
- package/watch/entries/added-by-hand.json +16 -0
- package/watch/entries/scope-drift.json +13 -0
- package/watch/entries/what-catches.json +16 -0
- package/dist/studio/assets/index-CvV5qITf.css +0 -32
- package/dist/studio/assets/index-jCOy6Ns7.js +0 -568
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One bounded, cached read (TR-W6's rules-snapshot rule, shared by WT-W4's discovery view): a TTL'd
|
|
3
|
+
* value, at most one read in flight, and a per-ask DEADLINE below the deterministic lane's timeout —
|
|
4
|
+
* a slow read must never get a check's evaluation abandoned mid-way (its dedupe state would move
|
|
5
|
+
* while its output is dropped). Past the deadline the ask is refused — or, with `staleOk`, answered
|
|
6
|
+
* from the last value — while the read itself goes on and fills the snapshot when it lands. A read
|
|
7
|
+
* that has not settled within one TTL is abandoned: the next ask starts a new one (a hung source
|
|
8
|
+
* never pins the slot), and a late answer from an abandoned read never overwrites a newer snapshot.
|
|
9
|
+
*/
|
|
10
|
+
export declare class BoundedRead<T> {
|
|
11
|
+
private readonly opts;
|
|
12
|
+
private snapshot;
|
|
13
|
+
private inFlight;
|
|
14
|
+
constructor(opts: {
|
|
15
|
+
/** Names the read in the timeout's message ("the rules read timed out after 400 ms"). */
|
|
16
|
+
name: string;
|
|
17
|
+
source: () => Promise<T>;
|
|
18
|
+
ttlMs: number;
|
|
19
|
+
deadlineMs: number;
|
|
20
|
+
now: () => number;
|
|
21
|
+
/** Answer an ask past its deadline from the last value when there is one (advisory data). */
|
|
22
|
+
staleOk?: boolean;
|
|
23
|
+
});
|
|
24
|
+
read(): Promise<T>;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=bounded-read.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bounded-read.d.ts","sourceRoot":"","sources":["../../src/watch/bounded-read.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,qBAAa,WAAW,CAAC,CAAC;IAKtB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAJvB,OAAO,CAAC,QAAQ,CAAyC;IACzD,OAAO,CAAC,QAAQ,CAA2D;gBAGxD,IAAI,EAAE;QACrB,yFAAyF;QACzF,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC;QACzB,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,CAAC;QACnB,GAAG,EAAE,MAAM,MAAM,CAAC;QAClB,6FAA6F;QAC7F,OAAO,CAAC,EAAE,OAAO,CAAC;KACnB;IAGH,IAAI,IAAI,OAAO,CAAC,CAAC,CAAC;CAuCnB"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One bounded, cached read (TR-W6's rules-snapshot rule, shared by WT-W4's discovery view): a TTL'd
|
|
3
|
+
* value, at most one read in flight, and a per-ask DEADLINE below the deterministic lane's timeout —
|
|
4
|
+
* a slow read must never get a check's evaluation abandoned mid-way (its dedupe state would move
|
|
5
|
+
* while its output is dropped). Past the deadline the ask is refused — or, with `staleOk`, answered
|
|
6
|
+
* from the last value — while the read itself goes on and fills the snapshot when it lands. A read
|
|
7
|
+
* that has not settled within one TTL is abandoned: the next ask starts a new one (a hung source
|
|
8
|
+
* never pins the slot), and a late answer from an abandoned read never overwrites a newer snapshot.
|
|
9
|
+
*/
|
|
10
|
+
export class BoundedRead {
|
|
11
|
+
opts;
|
|
12
|
+
snapshot = null;
|
|
13
|
+
inFlight = null;
|
|
14
|
+
constructor(opts) {
|
|
15
|
+
this.opts = opts;
|
|
16
|
+
}
|
|
17
|
+
read() {
|
|
18
|
+
const { name, ttlMs, deadlineMs, now } = this.opts;
|
|
19
|
+
const t = now();
|
|
20
|
+
if (this.snapshot !== null && t - this.snapshot.at < ttlMs)
|
|
21
|
+
return Promise.resolve(this.snapshot.value);
|
|
22
|
+
if (this.inFlight === null || t - this.inFlight.startedAt >= ttlMs) {
|
|
23
|
+
const flight = { startedAt: t, promise: Promise.resolve(undefined) };
|
|
24
|
+
flight.promise = Promise.resolve()
|
|
25
|
+
.then(this.opts.source)
|
|
26
|
+
.then((value) => {
|
|
27
|
+
// Only the read that still owns the slot may publish (an abandoned one is stale by definition).
|
|
28
|
+
if (this.inFlight === flight)
|
|
29
|
+
this.snapshot = { at: now(), value };
|
|
30
|
+
return value;
|
|
31
|
+
})
|
|
32
|
+
.finally(() => {
|
|
33
|
+
if (this.inFlight === flight)
|
|
34
|
+
this.inFlight = null;
|
|
35
|
+
});
|
|
36
|
+
flight.promise.catch(() => undefined); // an ask past its deadline no longer listens
|
|
37
|
+
this.inFlight = flight;
|
|
38
|
+
}
|
|
39
|
+
const read = this.inFlight.promise;
|
|
40
|
+
const stale = this.snapshot;
|
|
41
|
+
return new Promise((resolve, reject) => {
|
|
42
|
+
const timer = setTimeout(() => {
|
|
43
|
+
if (this.opts.staleOk === true && stale !== null)
|
|
44
|
+
resolve(stale.value);
|
|
45
|
+
else
|
|
46
|
+
reject(new Error(`${name} timed out after ${deadlineMs} ms`));
|
|
47
|
+
}, deadlineMs);
|
|
48
|
+
timer.unref();
|
|
49
|
+
read.then((value) => {
|
|
50
|
+
clearTimeout(timer);
|
|
51
|
+
resolve(value);
|
|
52
|
+
}, (err) => {
|
|
53
|
+
clearTimeout(timer);
|
|
54
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=bounded-read.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bounded-read.js","sourceRoot":"","sources":["../../src/watch/bounded-read.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,OAAO,WAAW;IAKH;IAJX,QAAQ,GAAoC,IAAI,CAAC;IACjD,QAAQ,GAAsD,IAAI,CAAC;IAE3E,YACmB,IAShB;QATgB,SAAI,GAAJ,IAAI,CASpB;IACA,CAAC;IAEJ,IAAI;QACF,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC;QACnD,MAAM,CAAC,GAAG,GAAG,EAAE,CAAC;QAChB,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,EAAE,GAAG,KAAK;YAAE,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACxG,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,IAAI,KAAK,EAAE,CAAC;YACnE,MAAM,MAAM,GAA+C,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,SAAyB,CAAC,EAAE,CAAC;YACjI,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,EAAE;iBAC/B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;iBACtB,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;gBACd,gGAAgG;gBAChG,IAAI,IAAI,CAAC,QAAQ,KAAK,MAAM;oBAAE,IAAI,CAAC,QAAQ,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC;gBACnE,OAAO,KAAK,CAAC;YACf,CAAC,CAAC;iBACD,OAAO,CAAC,GAAG,EAAE;gBACZ,IAAI,IAAI,CAAC,QAAQ,KAAK,MAAM;oBAAE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;YACrD,CAAC,CAAC,CAAC;YACL,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,6CAA6C;YACpF,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC;QACzB,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;QACnC,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC5B,OAAO,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACxC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC5B,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,KAAK,IAAI,IAAI,KAAK,KAAK,IAAI;oBAAE,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;;oBAClE,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,IAAI,oBAAoB,UAAU,KAAK,CAAC,CAAC,CAAC;YACrE,CAAC,EAAE,UAAU,CAAC,CAAC;YACf,KAAK,CAAC,KAAK,EAAE,CAAC;YACd,IAAI,CAAC,IAAI,CACP,CAAC,KAAK,EAAE,EAAE;gBACR,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,OAAO,CAAC,KAAK,CAAC,CAAC;YACjB,CAAC,EACD,CAAC,GAAY,EAAE,EAAE;gBACf,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,MAAM,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAC9D,CAAC,CACF,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;CACF"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow discovery (DES-walkthrough-proof §4.13; WT-W4): two deterministic, propose-only queries,
|
|
3
|
+
* registered as trigger-registry entries and fired on a run's terminal frames.
|
|
4
|
+
*
|
|
5
|
+
* added_by_hand per project, a catalog id a PERSON added to N consecutive launched chains (the
|
|
6
|
+
* steps of `plan.proposed{by:"human"}` the PA's proposal did not have; floor-added
|
|
7
|
+
* never; PA additions — `pa_added`, `member_request` — never) and never overrode
|
|
8
|
+
* → a testing-rule draft that makes the step the default for the observed kinds.
|
|
9
|
+
* what_catches per project per 30 days, a walkthrough FAIL while the same run's `test` verdict
|
|
10
|
+
* was PASS, K times → hold TST-1002 (Test plus a walkthrough review).
|
|
11
|
+
*
|
|
12
|
+
* Both count over ONE project-level view the daemon builds and the registry hands over as
|
|
13
|
+
* `ctx.discovery` (bounded, cached; `src/api/discovery-source.ts`). The checks stay pure over that
|
|
14
|
+
* view: no bus read, no ledger read, no engine call here.
|
|
15
|
+
*
|
|
16
|
+
* A hit is one `proposal` row per (project, query, draft hash) — RUN-LESS and project-scoped
|
|
17
|
+
* (`project` on the output; the emitter keys it to the project, so a second run of the project
|
|
18
|
+
* re-deriving the same draft resolves to the row already there, across restarts too). The emitter
|
|
19
|
+
* hands the row to the existing review queue (`facts.proposal` = the estate `proposal.submit` item,
|
|
20
|
+
* `kind_type: "policy:testing"`, payload `{rule, severity, evidence: {count, window, run_ids}}`).
|
|
21
|
+
* Nothing here lands a rule: approval is the operator's, in the queue (§4.13 "Approving"). The draft
|
|
22
|
+
* is a proposal, not the operator's words, so it never auto-remembers.
|
|
23
|
+
*
|
|
24
|
+
* The draft hash is over the RULE text, not the count: a sixth consecutive run re-derives the same
|
|
25
|
+
* draft and raises nothing new. A changed set of observed kinds is a new draft.
|
|
26
|
+
*
|
|
27
|
+
* A run whose records could not be read stays in the view as `unknown` (nothing added, no verdicts):
|
|
28
|
+
* it breaks a streak it sits inside and never counts as a hit — unknown is never "yes".
|
|
29
|
+
*/
|
|
30
|
+
import type { DiscoverySnapshot, WatchCheck } from '../types.js';
|
|
31
|
+
export type DiscoveryQuery = 'added_by_hand' | 'what_catches';
|
|
32
|
+
export interface AddedByHandParams {
|
|
33
|
+
/** The catalog ids a testing rule may oblige — only a step of this kind becomes a proposal. */
|
|
34
|
+
catalog: string[];
|
|
35
|
+
}
|
|
36
|
+
export interface AddedByHandThreshold {
|
|
37
|
+
/** Consecutive launched chains the step must have been added to, counted from the newest back. */
|
|
38
|
+
consecutive: number;
|
|
39
|
+
}
|
|
40
|
+
export interface WhatCatchesThreshold {
|
|
41
|
+
times: number;
|
|
42
|
+
window_days: number;
|
|
43
|
+
}
|
|
44
|
+
export interface DiscoveryProposal {
|
|
45
|
+
query: DiscoveryQuery;
|
|
46
|
+
/** `added_by_hand`: the step. */
|
|
47
|
+
catalog?: string;
|
|
48
|
+
/** The rule statement the proposal carries (the operator's review queue shows it verbatim). */
|
|
49
|
+
rule: string;
|
|
50
|
+
/** The watch row's sentence (the Watchtower's question). */
|
|
51
|
+
sentence: string;
|
|
52
|
+
evidence: {
|
|
53
|
+
count: number;
|
|
54
|
+
window: string;
|
|
55
|
+
run_ids: string[];
|
|
56
|
+
kinds: string[];
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/** The dedupe key's draft part: 12 hex of sha256 over (query, rule). */
|
|
60
|
+
export declare function draftHash(query: DiscoveryQuery, rule: string): string;
|
|
61
|
+
export declare function addedByHandProposals(snap: DiscoverySnapshot, params: AddedByHandParams, threshold: AddedByHandThreshold): DiscoveryProposal[];
|
|
62
|
+
export declare function whatCatchesProposals(snap: DiscoverySnapshot, threshold: WhatCatchesThreshold, now: number): DiscoveryProposal[];
|
|
63
|
+
export declare const addedByHandCheck: WatchCheck<AddedByHandParams, AddedByHandThreshold>;
|
|
64
|
+
export declare const whatCatchesCheck: WatchCheck<Record<string, never>, WhatCatchesThreshold>;
|
|
65
|
+
//# sourceMappingURL=discovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../../src/watch/checks/discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAIH,OAAO,KAAK,EAAuC,iBAAiB,EAAgC,UAAU,EAAE,MAAM,aAAa,CAAC;AAEpI,MAAM,MAAM,cAAc,GAAG,eAAe,GAAG,cAAc,CAAC;AAE9D,MAAM,WAAW,iBAAiB;IAChC,+FAA+F;IAC/F,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AACD,MAAM,WAAW,oBAAoB;IACnC,kGAAkG;IAClG,WAAW,EAAE,MAAM,CAAC;CACrB;AACD,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,cAAc,CAAC;IACtB,iCAAiC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+FAA+F;IAC/F,IAAI,EAAE,MAAM,CAAC;IACb,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CACjF;AAMD,wEAAwE;AACxE,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAErE;AAQD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,iBAAiB,EAAE,MAAM,EAAE,iBAAiB,EAAE,SAAS,EAAE,oBAAoB,GAAG,iBAAiB,EAAE,CAkB7I;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,iBAAiB,EAAE,SAAS,EAAE,oBAAoB,EAAE,GAAG,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAa/H;AAmFD,eAAO,MAAM,gBAAgB,EAAE,UAAU,CAAC,iBAAiB,EAAE,oBAAoB,CAQhF,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,oBAAoB,CAUpF,CAAC"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow discovery (DES-walkthrough-proof §4.13; WT-W4): two deterministic, propose-only queries,
|
|
3
|
+
* registered as trigger-registry entries and fired on a run's terminal frames.
|
|
4
|
+
*
|
|
5
|
+
* added_by_hand per project, a catalog id a PERSON added to N consecutive launched chains (the
|
|
6
|
+
* steps of `plan.proposed{by:"human"}` the PA's proposal did not have; floor-added
|
|
7
|
+
* never; PA additions — `pa_added`, `member_request` — never) and never overrode
|
|
8
|
+
* → a testing-rule draft that makes the step the default for the observed kinds.
|
|
9
|
+
* what_catches per project per 30 days, a walkthrough FAIL while the same run's `test` verdict
|
|
10
|
+
* was PASS, K times → hold TST-1002 (Test plus a walkthrough review).
|
|
11
|
+
*
|
|
12
|
+
* Both count over ONE project-level view the daemon builds and the registry hands over as
|
|
13
|
+
* `ctx.discovery` (bounded, cached; `src/api/discovery-source.ts`). The checks stay pure over that
|
|
14
|
+
* view: no bus read, no ledger read, no engine call here.
|
|
15
|
+
*
|
|
16
|
+
* A hit is one `proposal` row per (project, query, draft hash) — RUN-LESS and project-scoped
|
|
17
|
+
* (`project` on the output; the emitter keys it to the project, so a second run of the project
|
|
18
|
+
* re-deriving the same draft resolves to the row already there, across restarts too). The emitter
|
|
19
|
+
* hands the row to the existing review queue (`facts.proposal` = the estate `proposal.submit` item,
|
|
20
|
+
* `kind_type: "policy:testing"`, payload `{rule, severity, evidence: {count, window, run_ids}}`).
|
|
21
|
+
* Nothing here lands a rule: approval is the operator's, in the queue (§4.13 "Approving"). The draft
|
|
22
|
+
* is a proposal, not the operator's words, so it never auto-remembers.
|
|
23
|
+
*
|
|
24
|
+
* The draft hash is over the RULE text, not the count: a sixth consecutive run re-derives the same
|
|
25
|
+
* draft and raises nothing new. A changed set of observed kinds is a new draft.
|
|
26
|
+
*
|
|
27
|
+
* A run whose records could not be read stays in the view as `unknown` (nothing added, no verdicts):
|
|
28
|
+
* it breaks a streak it sits inside and never counts as a hit — unknown is never "yes".
|
|
29
|
+
*/
|
|
30
|
+
import { createHash } from 'node:crypto';
|
|
31
|
+
import { z } from 'zod';
|
|
32
|
+
const DAY_MS = 86_400_000;
|
|
33
|
+
const TST_1002 = 'TST-1002';
|
|
34
|
+
const BAG_KEY = 'discovery';
|
|
35
|
+
/** The dedupe key's draft part: 12 hex of sha256 over (query, rule). */
|
|
36
|
+
export function draftHash(query, rule) {
|
|
37
|
+
return createHash('sha256').update(`${query}\u0000${rule}`).digest('hex').slice(0, 12);
|
|
38
|
+
}
|
|
39
|
+
const kindsOf = (runs) => [...new Set(runs.map((r) => r.kind))].sort();
|
|
40
|
+
const kindsText = (kinds) => kinds.join(' or ');
|
|
41
|
+
/** Oldest launch first, whatever order the view lists them in. */
|
|
42
|
+
const byLaunch = (snap) => [...snap.runs].sort((a, b) => a.launched_at - b.launched_at || a.run_id.localeCompare(b.run_id));
|
|
43
|
+
export function addedByHandProposals(snap, params, threshold) {
|
|
44
|
+
const runs = byLaunch(snap);
|
|
45
|
+
const out = [];
|
|
46
|
+
for (const catalog of params.catalog) {
|
|
47
|
+
let streak = 0;
|
|
48
|
+
for (let i = runs.length - 1; i >= 0 && runs[i].human_added.includes(catalog); i -= 1)
|
|
49
|
+
streak += 1;
|
|
50
|
+
if (streak === 0 || streak < threshold.consecutive)
|
|
51
|
+
continue;
|
|
52
|
+
const hits = runs.slice(runs.length - streak);
|
|
53
|
+
const kinds = kindsOf(hits);
|
|
54
|
+
out.push({
|
|
55
|
+
query: 'added_by_hand',
|
|
56
|
+
catalog,
|
|
57
|
+
rule: `A ${kindsText(kinds)} run includes the \`${catalog}\` step.`,
|
|
58
|
+
sentence: `You've added \`${catalog}\` by hand to ${streak} consecutive ${kindsText(kinds)} runs — make it the default?`,
|
|
59
|
+
evidence: { count: streak, window: `${streak} consecutive runs`, run_ids: hits.map((r) => r.run_id), kinds },
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
64
|
+
export function whatCatchesProposals(snap, threshold, now) {
|
|
65
|
+
const since = now - threshold.window_days * DAY_MS;
|
|
66
|
+
const hits = byLaunch(snap).filter((r) => r.launched_at >= since && r.walkthrough === 'FAIL' && r.test === 'PASS');
|
|
67
|
+
if (hits.length < threshold.times)
|
|
68
|
+
return [];
|
|
69
|
+
const kinds = kindsOf(hits);
|
|
70
|
+
return [
|
|
71
|
+
{
|
|
72
|
+
query: 'what_catches',
|
|
73
|
+
rule: `A change to code or config gets Test plus a walkthrough review by a different helper (${TST_1002}, held).`,
|
|
74
|
+
sentence: `A walkthrough caught what the tests passed ${hits.length} times in the last ${threshold.window_days} days — hold ${TST_1002} (Test plus a walkthrough review) for ${kindsText(kinds)} runs?`,
|
|
75
|
+
evidence: { count: hits.length, window: `${threshold.window_days}d`, run_ids: hits.map((r) => r.run_id), kinds },
|
|
76
|
+
},
|
|
77
|
+
];
|
|
78
|
+
}
|
|
79
|
+
function bagOf(state) {
|
|
80
|
+
let bag = state.bag.get(BAG_KEY);
|
|
81
|
+
if (bag === undefined) {
|
|
82
|
+
bag = { frames: 0, noSource: false, noProject: false, unreadable: null, judged: false };
|
|
83
|
+
state.bag.set(BAG_KEY, bag);
|
|
84
|
+
}
|
|
85
|
+
return bag;
|
|
86
|
+
}
|
|
87
|
+
/** The review-queue item the emitter files (`facts.proposal`), beside the plain facts studio shows. */
|
|
88
|
+
function proposalFacts(p, project) {
|
|
89
|
+
return {
|
|
90
|
+
proposal: {
|
|
91
|
+
kind_type: 'policy:testing',
|
|
92
|
+
payload: { rule: p.rule, severity: 'warn', evidence: p.evidence },
|
|
93
|
+
facets: { project },
|
|
94
|
+
},
|
|
95
|
+
query: p.query,
|
|
96
|
+
...(p.catalog !== undefined ? { catalog: p.catalog } : {}),
|
|
97
|
+
count: p.evidence.count,
|
|
98
|
+
kinds: p.evidence.kinds,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
async function discover(input, state, ctx, compute) {
|
|
102
|
+
const bag = bagOf(state);
|
|
103
|
+
bag.frames += 1;
|
|
104
|
+
if (ctx.discovery === undefined) {
|
|
105
|
+
bag.noSource = true;
|
|
106
|
+
return [];
|
|
107
|
+
}
|
|
108
|
+
if (input.runId === null)
|
|
109
|
+
return [];
|
|
110
|
+
let snap;
|
|
111
|
+
try {
|
|
112
|
+
snap = await ctx.discovery(input.runId);
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
bag.unreadable = err instanceof Error ? err.message : String(err);
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
if (snap === null) {
|
|
119
|
+
bag.noProject = true;
|
|
120
|
+
return [];
|
|
121
|
+
}
|
|
122
|
+
const project = snap.project_id;
|
|
123
|
+
bag.noProject = false;
|
|
124
|
+
bag.unreadable = null;
|
|
125
|
+
bag.judged = true;
|
|
126
|
+
return compute(snap).map((p) => ({
|
|
127
|
+
op: 'raise',
|
|
128
|
+
subject: `${project}:${p.query}:${draftHash(p.query, p.rule)}`,
|
|
129
|
+
project,
|
|
130
|
+
sentence: p.sentence,
|
|
131
|
+
facts: proposalFacts(p, project),
|
|
132
|
+
re: `${input.type}#${input.runId}`,
|
|
133
|
+
}));
|
|
134
|
+
}
|
|
135
|
+
function coverageOf(state) {
|
|
136
|
+
const bag = state.bag.get(BAG_KEY);
|
|
137
|
+
if (bag === undefined || bag.frames === 0)
|
|
138
|
+
return { state: 'not_checked', reason: 'the run has not ended yet' };
|
|
139
|
+
if (bag.noSource)
|
|
140
|
+
return { state: 'not_checked', reason: 'no discovery source (the daemon gave the registry no project view to count over)' };
|
|
141
|
+
if (bag.noProject)
|
|
142
|
+
return { state: 'not_checked', reason: 'the run belongs to no project, so there is nothing to count over' };
|
|
143
|
+
if (bag.unreadable !== null) {
|
|
144
|
+
return { state: 'not_checked', reason: `the project's run records could not be read in time (${bag.unreadable}); counted again when the next run ends` };
|
|
145
|
+
}
|
|
146
|
+
return bag.judged ? { state: 'checked' } : { state: 'not_checked', reason: 'the run has not ended yet' };
|
|
147
|
+
}
|
|
148
|
+
export const addedByHandCheck = {
|
|
149
|
+
name: 'deterministic:added_by_hand',
|
|
150
|
+
lane: 'deterministic',
|
|
151
|
+
paramsSchema: z.object({ catalog: z.array(z.string().min(1).max(64)).min(1).max(32) }).strict(),
|
|
152
|
+
thresholdSchema: z.object({ consecutive: z.number().int().min(2).max(100).default(5) }).strict(),
|
|
153
|
+
evaluate: (input, state, params, threshold, ctx) => discover(input, state, ctx, (snap) => addedByHandProposals(snap, params, threshold)),
|
|
154
|
+
coverage: coverageOf,
|
|
155
|
+
describe: (t) => `When a step you added by hand appears in ${t.consecutive} consecutive runs of a project (a testing rule to make it the default)`,
|
|
156
|
+
};
|
|
157
|
+
export const whatCatchesCheck = {
|
|
158
|
+
name: 'deterministic:what_catches',
|
|
159
|
+
lane: 'deterministic',
|
|
160
|
+
paramsSchema: z.object({}).strict(),
|
|
161
|
+
thresholdSchema: z
|
|
162
|
+
.object({ times: z.number().int().min(1).max(100).default(3), window_days: z.number().int().min(1).max(365).default(30) })
|
|
163
|
+
.strict(),
|
|
164
|
+
evaluate: (input, state, _params, threshold, ctx) => discover(input, state, ctx, (snap) => whatCatchesProposals(snap, threshold, ctx.now())),
|
|
165
|
+
coverage: coverageOf,
|
|
166
|
+
describe: (t) => `When a walkthrough fails while the same run's tests passed ${t.times} times in ${t.window_days} days (hold ${TST_1002})`,
|
|
167
|
+
};
|
|
168
|
+
//# sourceMappingURL=discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../../src/watch/checks/discovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/watch/checks/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/watch/checks/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAW9C,eAAO,MAAM,cAAc,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAezD,CAAC"}
|
|
@@ -6,8 +6,10 @@
|
|
|
6
6
|
import { checkFailedCheck } from './check-failed.js';
|
|
7
7
|
import { claimVsEvidenceCheck } from './claim-vs-evidence.js';
|
|
8
8
|
import { deliverAuditCheck } from './deliver-audit.js';
|
|
9
|
+
import { addedByHandCheck, whatCatchesCheck } from './discovery.js';
|
|
9
10
|
import { lagCheck } from './lag.js';
|
|
10
11
|
import { quietAfterClaimCheck } from './quiet-after-claim.js';
|
|
12
|
+
import { scopeDriftCheck } from './scope-drift.js';
|
|
11
13
|
import { ungatedCheck } from './ungated.js';
|
|
12
14
|
import { warnedRuleCheck } from './warned-rule.js';
|
|
13
15
|
export const SHIPPED_CHECKS = new Map([
|
|
@@ -20,5 +22,10 @@ export const SHIPPED_CHECKS = new Map([
|
|
|
20
22
|
// TR-W6
|
|
21
23
|
[claimVsEvidenceCheck.name, claimVsEvidenceCheck],
|
|
22
24
|
[warnedRuleCheck.name, warnedRuleCheck],
|
|
25
|
+
// TR-W7
|
|
26
|
+
[scopeDriftCheck.name, scopeDriftCheck],
|
|
27
|
+
// WT-W4 (DES-walkthrough-proof §4.13: discovery, propose-only)
|
|
28
|
+
[addedByHandCheck.name, addedByHandCheck],
|
|
29
|
+
[whatCatchesCheck.name, whatCatchesCheck],
|
|
23
30
|
]);
|
|
24
31
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/watch/checks/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,MAAM,CAAC,MAAM,cAAc,GAAoC,IAAI,GAAG,CAAqB;IACzF,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAiC,CAAC;IAClD,CAAC,gBAAgB,CAAC,IAAI,EAAE,gBAAyC,CAAC;IAClE,SAAS;IACT,CAAC,iBAAiB,CAAC,IAAI,EAAE,iBAA0C,CAAC;IACpE,CAAC,YAAY,CAAC,IAAI,EAAE,YAAqC,CAAC;IAC1D,CAAC,oBAAoB,CAAC,IAAI,EAAE,oBAA6C,CAAC;IAC1E,QAAQ;IACR,CAAC,oBAAoB,CAAC,IAAI,EAAE,oBAA6C,CAAC;IAC1E,CAAC,eAAe,CAAC,IAAI,EAAE,eAAwC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/watch/checks/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACpE,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,MAAM,CAAC,MAAM,cAAc,GAAoC,IAAI,GAAG,CAAqB;IACzF,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAiC,CAAC;IAClD,CAAC,gBAAgB,CAAC,IAAI,EAAE,gBAAyC,CAAC;IAClE,SAAS;IACT,CAAC,iBAAiB,CAAC,IAAI,EAAE,iBAA0C,CAAC;IACpE,CAAC,YAAY,CAAC,IAAI,EAAE,YAAqC,CAAC;IAC1D,CAAC,oBAAoB,CAAC,IAAI,EAAE,oBAA6C,CAAC;IAC1E,QAAQ;IACR,CAAC,oBAAoB,CAAC,IAAI,EAAE,oBAA6C,CAAC;IAC1E,CAAC,eAAe,CAAC,IAAI,EAAE,eAAwC,CAAC;IAChE,QAAQ;IACR,CAAC,eAAe,CAAC,IAAI,EAAE,eAAwC,CAAC;IAChE,+DAA+D;IAC/D,CAAC,gBAAgB,CAAC,IAAI,EAAE,gBAAyC,CAAC;IAClE,CAAC,gBAAgB,CAAC,IAAI,EAAE,gBAAyC,CAAC;CACnE,CAAC,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `deterministic:scope_drift` (DES-trigger-registry §4.3 row 4 "scope-drift", §4.4; TR-W7).
|
|
3
|
+
*
|
|
4
|
+
* Set logic over two facts the engine computed, nothing parsed: the creator floor's
|
|
5
|
+
* `repoChecksEvaluated.changed` (TR-W1b — every path the unit changed, its dispatch baseline tree
|
|
6
|
+
* against the tree the checks ran on; any carrier, any way of editing) against the run's declared
|
|
7
|
+
* scope, `plan.accepted.touch` (TR-W1a — the accepted proposal's touch unioned with every earlier
|
|
8
|
+
* accepted rev's; a BUS row the registry PULLS, the first entry that listens on the bus). A path the
|
|
9
|
+
* floor names that no touch entry covers is one flag per (attempt, path); the emitter rolls them up
|
|
10
|
+
* per attempt past the entry's rate (§4.7). Drift flags clear only by dismissal.
|
|
11
|
+
*
|
|
12
|
+
* Touch entries are files or directory prefixes ending `/` (§4.4). Nothing else is inferred: an entry
|
|
13
|
+
* without a trailing slash names ONE file, never a prefix (a declared `src` does not cover `src/x.ts`;
|
|
14
|
+
* a declared `src/` does). Both sides are normalised (`./`, doubled slashes) before the comparison so
|
|
15
|
+
* a spelling difference is never drift.
|
|
16
|
+
*
|
|
17
|
+
* Order is not assumed. A plan is accepted minutes before its creator floors run, but the plan row is
|
|
18
|
+
* polled off the bus while the floor arrives on the fan-in, so a floor that lands first is KEPT
|
|
19
|
+
* (bounded) and judged when the plan row arrives — anchored to the floor's own time and replay
|
|
20
|
+
* provenance (TR-W6's kept-frame rule). The newest accepted rev is the scope (core already unions the
|
|
21
|
+
* revs); a lower rev replayed late never narrows it.
|
|
22
|
+
*
|
|
23
|
+
* Coverage (§4.7, G7):
|
|
24
|
+
* - "no declared scope" when `touch_source` is `none`, or absent — an old row reads as none, and an
|
|
25
|
+
* engine before TR-W1a cannot be told apart from a plan that declared nothing, so the reason
|
|
26
|
+
* names both. A DECLARED empty set (a source with no paths) is not none: it covers nothing, so
|
|
27
|
+
* every change is outside it and the run is checked;
|
|
28
|
+
* - not checked when the TOUCH set itself was cut at 64: what lies outside the listed paths cannot
|
|
29
|
+
* be known, so nothing is flagged rather than flagging what may be in scope;
|
|
30
|
+
* - a truncated CHANGE list is still judged on the paths it names, and the fact says it was cut
|
|
31
|
+
* (§4.4: "a truncated list still names its first 200 paths and says so").
|
|
32
|
+
*/
|
|
33
|
+
import type { WatchCheck } from '../types.js';
|
|
34
|
+
/** The bus row the check joins to (TR-W1a). The entry's `join` names it; the loader checks the grammar. */
|
|
35
|
+
export declare const PLAN_ACCEPTED_TYPE = "wicked.team.plan.accepted";
|
|
36
|
+
/** `plan.accepted.touch` is cut at this many paths by the engine (`ACCEPTED_TOUCH_CAP`). */
|
|
37
|
+
export declare const TOUCH_CAP = 64;
|
|
38
|
+
export interface ScopeDriftThreshold {
|
|
39
|
+
/** An attempt raises only when at least this many of its changed paths lie outside the scope. */
|
|
40
|
+
min_paths: number;
|
|
41
|
+
}
|
|
42
|
+
/** Repo-relative, forward slashes: no leading `./` or `/`, no doubled slashes. */
|
|
43
|
+
export declare function normalisePath(p: string): string;
|
|
44
|
+
/** True when some touch entry covers `path`: an equal file, or a directory prefix ending `/` (§4.4). */
|
|
45
|
+
export declare function inScope(path: string, touch: readonly string[]): boolean;
|
|
46
|
+
export declare const scopeDriftCheck: WatchCheck<Record<string, never>, ScopeDriftThreshold>;
|
|
47
|
+
//# sourceMappingURL=scope-drift.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope-drift.d.ts","sourceRoot":"","sources":["../../../src/watch/checks/scope-drift.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAGH,OAAO,KAAK,EAA8B,UAAU,EAAE,MAAM,aAAa,CAAC;AAE1E,2GAA2G;AAC3G,eAAO,MAAM,kBAAkB,8BAA8B,CAAC;AAC9D,4FAA4F;AAC5F,eAAO,MAAM,SAAS,KAAK,CAAC;AAE5B,MAAM,WAAW,mBAAmB;IAClC,iGAAiG;IACjG,SAAS,EAAE,MAAM,CAAC;CACnB;AA8CD,kFAAkF;AAClF,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAK/C;AAED,wGAAwG;AACxG,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAYvE;AA2DD,eAAO,MAAM,eAAe,EAAE,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,mBAAmB,CA2ElF,CAAC"}
|