@melite/estate-drafts 0.0.0-stage → 0.1.5-pre-alpha

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/lib/spec.d.ts ADDED
@@ -0,0 +1,88 @@
1
+ import { z } from "zod";
2
+ /** One drafts-domain record: the doc plus the recency column the
3
+ * list arm orders by (the file-mtime equivalent — seconds). */
4
+ declare const DraftRecordSchema: z.ZodObject<{
5
+ updated_at: z.ZodNumber;
6
+ doc: z.ZodObject<{
7
+ draft_id: z.ZodString;
8
+ status: z.ZodString;
9
+ createdAt: z.ZodNumber;
10
+ completedAt: z.ZodUnion<readonly [z.ZodNumber, z.ZodNull]>;
11
+ intent: z.ZodString;
12
+ stages: z.ZodArray<z.ZodObject<{
13
+ id: z.ZodString;
14
+ }, z.core.$loose>>;
15
+ }, z.core.$loose>;
16
+ }, z.core.$strip>;
17
+ export type DraftRecord = z.infer<typeof DraftRecordSchema>;
18
+ /** One character record (audit 004/C2): the reusable identity
19
+ * bundle. `references` is the ORDERED reference-image list — path
20
+ * strings of exactly the class the submit walk stages (data URLs,
21
+ * http(s), estate asset URLs, runs-relative and cwd-relative
22
+ * paths; `uploadReferenced` walks the whole graph and stages any
23
+ * of them, audit 004 §3), order preserved — sheet views are
24
+ * position-coded. `description` is the LOCKED identity prompt (a
25
+ * character-sheet ten-section block, audit 004/C7's skill); the
26
+ * run-time seam (how it reaches a prompt) is C3's decision, not
27
+ * this table's. */
28
+ declare const CharacterRecordSchema: z.ZodObject<{
29
+ name: z.ZodString;
30
+ references: z.ZodArray<z.ZodString>;
31
+ description: z.ZodString;
32
+ updated_at: z.ZodNumber;
33
+ }, z.core.$strip>;
34
+ export type CharacterRecord = z.infer<typeof CharacterRecordSchema>;
35
+ /** The draft-id law (editor_runs.818-822 heritage): 1..96 chars,
36
+ * [A-Za-z0-9_-] ASCII only, path-safe. THE SSOT — the queue's
37
+ * submit gate and the drafts remote both test this one address
38
+ * (the queue re-exports it; gateway-core's copy is dead). */
39
+ export declare const DRAFT_ID_RE: RegExp;
40
+ /** The id's PATTERN and its bound, published so every gate that
41
+ * admits a draft id enforces the SAME rule (the census's H13: the
42
+ * queue's copy had no cap, so a long id passed one door and was
43
+ * refused by the next with a different voice). */
44
+ export declare const DRAFT_ID_PATTERN: RegExp;
45
+ export declare const DRAFT_ID_MAX_LEN = 96;
46
+ /** draft_id_ok (the doors' hand-loop drop-in): the law, one voice. */
47
+ export declare function draftIdOk(draftId: string): boolean;
48
+ /** The drafts domain (unit dir `drafts/`, version 2 — the
49
+ * characters table join; version-1 record documents stay
50
+ * readable through compatibleVersions, the per-record
51
+ * contract's accepted-stamp set). */
52
+ export declare const draftsDomainSpec: {
53
+ name: string;
54
+ version: number;
55
+ compatibleVersions: number[];
56
+ layout: "per-record";
57
+ invalidRecords: "backup-and-skip";
58
+ global: {
59
+ schema: z.ZodNumber;
60
+ initial: number;
61
+ };
62
+ tables: {
63
+ docs: import("@deepseek-ai/dsh-storage-domain").DomainTableSpec<string, {
64
+ updated_at: number;
65
+ doc: {
66
+ [x: string]: unknown;
67
+ draft_id: string;
68
+ status: string;
69
+ createdAt: number;
70
+ completedAt: number | null;
71
+ intent: string;
72
+ stages: {
73
+ [x: string]: unknown;
74
+ id: string;
75
+ }[];
76
+ };
77
+ }>;
78
+ characters: import("@deepseek-ai/dsh-storage-domain").DomainTableSpec<string, {
79
+ name: string;
80
+ references: string[];
81
+ description: string;
82
+ updated_at: number;
83
+ }>;
84
+ };
85
+ };
86
+ export type DraftsDomainSpec = typeof draftsDomainSpec;
87
+ export {};
88
+ //# sourceMappingURL=spec.d.ts.map
package/lib/spec.js ADDED
@@ -0,0 +1,87 @@
1
+
2
+ //
3
+ // The domain truth for draft docs: table `docs` keyed by draft id
4
+ // (DRAFT_ID_RE admits path-safe chars only, so the identity codec
5
+ // holds — no b64u here), one record per draft (large, sparse,
6
+ // individually disposable), schema-failing records backed up and
7
+ // skipped by the facility (`invalidRecords: 'backup-and-skip'`).
8
+ // The global slot is the one-time legacy-import marker: 0 until the
9
+ // legacy drafts tree has been imported, the import epoch (ms) after.
10
+ //
11
+
12
+ // character bundle (ordered reference paths + a locked description),
13
+ // same id grammar as drafts (one address class, one law — the
14
+ // per-record layout's SAFE_KEY_RE is exactly DRAFT_ID_RE's set), the
15
+ // storage root itself is the tenant boundary. Version 2 with
16
+ // compatibleVersions [1]: existing v1-stamped record documents keep
17
+ // reading green (the per-record contract accepts the declared set),
18
+ // new writes stamp 2.
19
+ import { defineDomain, domainTable } from "@deepseek-ai/dsh-storage-domain";
20
+ import { z } from "zod";
21
+ /** One draft doc — the composer's shape: six contract keys plus
22
+ * caller extras verbatim. THE SERVE READ IS DELIBERATELY LOOSE
23
+ * (the write doors are strict; this read hands the composer's own
24
+ * extras back, pinned by bench-coverage's "extras ride the loose
25
+ * schema" row) — a looseObject needs no .passthrough() on top. */
26
+ const DraftDocSchema = z.looseObject({
27
+ draft_id: z.string(),
28
+ status: z.string(),
29
+ createdAt: z.number(),
30
+ completedAt: z.union([z.number(), z.null()]),
31
+ intent: z.string(),
32
+ stages: z.array(z.looseObject({ id: z.string() })),
33
+ });
34
+ /** One drafts-domain record: the doc plus the recency column the
35
+ * list arm orders by (the file-mtime equivalent — seconds). */
36
+ const DraftRecordSchema = z.object({
37
+ updated_at: z.number().int(),
38
+ doc: DraftDocSchema,
39
+ });
40
+ /** One character record (audit 004/C2): the reusable identity
41
+ * bundle. `references` is the ORDERED reference-image list — path
42
+ * strings of exactly the class the submit walk stages (data URLs,
43
+ * http(s), estate asset URLs, runs-relative and cwd-relative
44
+ * paths; `uploadReferenced` walks the whole graph and stages any
45
+ * of them, audit 004 §3), order preserved — sheet views are
46
+ * position-coded. `description` is the LOCKED identity prompt (a
47
+ * character-sheet ten-section block, audit 004/C7's skill); the
48
+ * run-time seam (how it reaches a prompt) is C3's decision, not
49
+ * this table's. */
50
+ const CharacterRecordSchema = z.object({
51
+ name: z.string().min(1),
52
+ references: z.array(z.string()),
53
+ description: z.string(),
54
+ updated_at: z.number().int(),
55
+ });
56
+ /** The draft-id law (editor_runs.818-822 heritage): 1..96 chars,
57
+ * [A-Za-z0-9_-] ASCII only, path-safe. THE SSOT — the queue's
58
+ * submit gate and the drafts remote both test this one address
59
+ * (the queue re-exports it; gateway-core's copy is dead). */
60
+ export const DRAFT_ID_RE = /^[A-Za-z0-9_-]{1,96}$/;
61
+ /** The id's PATTERN and its bound, published so every gate that
62
+ * admits a draft id enforces the SAME rule (the census's H13: the
63
+ * queue's copy had no cap, so a long id passed one door and was
64
+ * refused by the next with a different voice). */
65
+ export const DRAFT_ID_PATTERN = DRAFT_ID_RE;
66
+ export const DRAFT_ID_MAX_LEN = 96;
67
+ /** draft_id_ok (the doors' hand-loop drop-in): the law, one voice. */
68
+ export function draftIdOk(draftId) {
69
+ return DRAFT_ID_RE.test(draftId);
70
+ }
71
+ /** The drafts domain (unit dir `drafts/`, version 2 — the
72
+ * characters table join; version-1 record documents stay
73
+ * readable through compatibleVersions, the per-record
74
+ * contract's accepted-stamp set). */
75
+ export const draftsDomainSpec = defineDomain({
76
+ name: "drafts",
77
+ version: 2,
78
+ compatibleVersions: [1],
79
+ layout: "per-record",
80
+ invalidRecords: "backup-and-skip",
81
+ global: { schema: z.number().int(), initial: 0 },
82
+ tables: {
83
+ docs: domainTable(DraftRecordSchema),
84
+ characters: domainTable(CharacterRecordSchema),
85
+ },
86
+ });
87
+ //# sourceMappingURL=spec.js.map
package/lib/store.d.ts ADDED
@@ -0,0 +1,46 @@
1
+ import { Service, type Context } from "@deepseek-ai/cordis";
2
+ import type { Domain } from "@deepseek-ai/dsh-storage-domain";
3
+ import type { DraftsDomainSpec } from "./spec.js";
4
+ /** The drafts plugin's config (J12: the retired
5
+ * MELITE_STORAGE_ROOT / MELITE_STATE_ROOT env seams' config
6
+ * twin — the unit-file root the json backend hangs under,
7
+ * named at the composition site, never read from the env). */
8
+ export interface DraftsConfig {
9
+ /** The storage unit-file root (`<stateRoot>/storage` at the
10
+ * composition site); default `data/runs/storage`. */
11
+ storageRoot?: string;
12
+ }
13
+ /** The json backend's unit-file root. */
14
+ export declare function resolveStorageRoot(config?: Readonly<DraftsConfig>): string;
15
+ /** The fiber-scoped seat owning the drafts domain handles (id
16
+ * `meliteDraftsDomain` — the estate-seat prefix law, cf.
17
+ * skillRegistry.ts:20-28): one instance per mounting fiber, so the
18
+ * cached opens die with the fiber instead of living at module
19
+ * scope. Fields are TS-`private`, never `#private` — cordis
20
+ * `ctx.get` returns a proxy and private class fields die through
21
+ * it ("Cannot read private member ... whose class did not declare
22
+ * it"; the flows seat, flowsData.ts, is the measured precedent). */
23
+ export declare class DraftsDomainSeatService extends Service {
24
+ static readonly inject: {
25
+ readonly optional: readonly [];
26
+ };
27
+ /** Per-facility open handles, keyed by the facility object (one
28
+ * slot per provider; GC-bounded, fiber-lifetime). */
29
+ private cached;
30
+ constructor(ctx: Context, config?: Readonly<DraftsConfig>);
31
+ /** The composition site's named storage root (J12: config —
32
+ * the retired env seam's twin). */
33
+ readonly config: Readonly<DraftsConfig>;
34
+
35
+
36
+
37
+
38
+ open(): Promise<Domain<DraftsDomainSpec>>;
39
+ }
40
+ /** Open (or reuse) the drafts domain through the mounted seat. The
41
+ * apply mounts `DraftsDomainSeatService` before the remote
42
+ * services; tests mount it on their own Context.
43
+ * @param ctx - the Context whose fiber carries the seat.
44
+ * @returns the ready domain handle. */
45
+ export declare function openDraftsDomain(ctx: Context): Promise<Domain<DraftsDomainSpec>>;
46
+ //# sourceMappingURL=store.d.ts.map
package/lib/store.js ADDED
@@ -0,0 +1,194 @@
1
+ // store.ts — open the drafts domain through the host's facility.
2
+ //
3
+ // The facility seat (`ctx.storageDomain`) is provided by the HOST's
4
+ // storage rows (json backend + domain facility); this package never
5
+ // bundles them. The open is lazy and process-scoped (one open per
6
+ // storage root — the domain write chain serializes concurrent puts,
7
+ // so sharing the handle is correct), cached on first use.
8
+ //
9
+ // First open runs the one-time legacy import (the pre-domain
10
+ // STATE_ROOT/drafts tree → the domain), guarded by the global slot:
11
+ // runs only while it serves the initial 0, then stamps the epoch —
12
+ // a wiped unit never re-imports frozen ghosts. The legacy files stay
13
+ // untouched on disk — evidence, never truth.
14
+ import { Service } from "@deepseek-ai/cordis";
15
+ import { readFileSync, readdirSync, statSync } from "node:fs";
16
+ import { join } from "node:path";
17
+ import { isPurelyUnstatedRequiredVoice } from "@melite/contracts/laneRelations";
18
+ import { draftsDomainSpec } from "./spec.js";
19
+ /** The json backend's unit-file root. */
20
+ export function resolveStorageRoot(config = {}) {
21
+ return config.storageRoot ?? join("data", "runs", "storage");
22
+ }
23
+ /** The one-time legacy-drafts import (the pre-domain drafts tree →
24
+ * the drafts domain). Unparseable/non-object legacy files skip;
25
+ * schema-failing rows skip individually; the rest import. */
26
+ async function importLegacyDrafts(drafts, storageRoot) {
27
+ const marker = drafts.global;
28
+ if (marker.get() !== 0)
29
+ return;
30
+ const docs = drafts.table("docs");
31
+ const legacyDir = join(storageRoot, "..", "drafts");
32
+ let names;
33
+ try {
34
+ names = readdirSync(legacyDir);
35
+ }
36
+ catch {
37
+ names = [];
38
+ }
39
+ for (const name of names) {
40
+ if (!name.endsWith(".json"))
41
+ continue;
42
+ const did = name.slice(0, -5);
43
+ if (docs.get(did) !== undefined)
44
+ continue;
45
+ let doc;
46
+ try {
47
+ doc = JSON.parse(readFileSync(join(legacyDir, name), "utf8"));
48
+ }
49
+ catch {
50
+ continue;
51
+ }
52
+ if (typeof doc !== "object" || doc === null || Array.isArray(doc))
53
+ continue;
54
+ const rec = doc;
55
+ if (typeof rec["draft_id"] !== "string")
56
+ rec["draft_id"] = did;
57
+ let updated = Math.floor(Date.now() / 1000);
58
+ try {
59
+ updated = Math.floor(statSync(join(legacyDir, name)).mtimeMs / 1000);
60
+ }
61
+ catch {
62
+ /* unstatable imports as now — ordering stays total */
63
+ }
64
+ try {
65
+ await docs.put(did, {
66
+ updated_at: updated,
67
+ doc: rec,
68
+ });
69
+ }
70
+ catch {
71
+ /* a schema-failing legacy row skips; the rest import */
72
+ }
73
+ }
74
+ await marker.set(Date.now());
75
+ }
76
+
77
+
78
+
79
+
80
+
81
+
82
+
83
+
84
+
85
+
86
+
87
+
88
+ async function healReplayedRefusals(drafts) {
89
+ const docs = drafts.table("docs");
90
+ for (const [did, rec] of docs.entries()) {
91
+ // persisted rows are a durable boundary: a record without a doc
92
+ // object (or without stages) carries no bench row to heal
93
+ const doc = typeof rec === "object" && rec !== null ? rec.doc : undefined;
94
+ if (typeof doc !== "object" || doc === null)
95
+ continue;
96
+ const stages = Array.isArray(doc.stages) ? doc.stages : [];
97
+ let changed = false;
98
+ for (const stage of stages) {
99
+ if (typeof stage !== "object" || stage === null)
100
+ continue;
101
+ const row = stage;
102
+ const runStatus = row["runStatus"];
103
+ if (runStatus !== "failed" && runStatus !== "error")
104
+ continue;
105
+ const result = row["result"];
106
+ const error = typeof result === "object" && result !== null
107
+ ? result["error"]
108
+ : undefined;
109
+ // PURELY the class (the mixed-carry guard): a composite
110
+ // refusal can join the stem with a stated-wrong half — that
111
+ // row keeps its failed face, only whole-stem texts heal
112
+ if (typeof error !== "string" || !isPurelyUnstatedRequiredVoice(error)) {
113
+ continue;
114
+ }
115
+ row["runStatus"] = "";
116
+ row["result"] = {};
117
+ changed = true;
118
+ }
119
+ if (changed)
120
+ await docs.put(did, rec);
121
+ }
122
+ }
123
+ /** The fiber-scoped seat owning the drafts domain handles (id
124
+ * `meliteDraftsDomain` — the estate-seat prefix law, cf.
125
+ * skillRegistry.ts:20-28): one instance per mounting fiber, so the
126
+ * cached opens die with the fiber instead of living at module
127
+ * scope. Fields are TS-`private`, never `#private` — cordis
128
+ * `ctx.get` returns a proxy and private class fields die through
129
+ * it ("Cannot read private member ... whose class did not declare
130
+ * it"; the flows seat, flowsData.ts, is the measured precedent). */
131
+ export class DraftsDomainSeatService extends Service {
132
+ static inject = { optional: [] };
133
+ /** Per-facility open handles, keyed by the facility object (one
134
+ * slot per provider; GC-bounded, fiber-lifetime). */
135
+ cached = new WeakMap();
136
+ constructor(ctx, config = {}) {
137
+ // the estate-seat id: dsh core may own the bare name
138
+ super(ctx, "meliteDraftsDomain");
139
+ this.config = config;
140
+ }
141
+ /** The composition site's named storage root (J12: config —
142
+ * the retired env seam's twin). */
143
+ config;
144
+
145
+
146
+
147
+
148
+ async open() {
149
+ const root = resolveStorageRoot(this.config);
150
+ // OPTIONAL-dependency probe per the tutorial's documented pattern
151
+ // (cordis-tutorial/03-services.md: "skip inject and probe at the
152
+ // use site" — property reads demand inject on loader-mounted
153
+ // fibers; ctx.get returns the active provider or undefined).
154
+ const facility = this.ctx.get("storageDomain");
155
+ if (facility === undefined || facility === null) {
156
+ throw new Error("[estate-drafts] storage domain facility not mounted (ctx.storageDomain)");
157
+ }
158
+ const hit = this.cached.get(facility);
159
+ // (J12) the config root is immutable per boot, so a cached hit is
160
+ // always this root — the drifting-mid-process root the retired
161
+
162
+ if (hit !== undefined)
163
+ return hit.ready;
164
+ const ready = (async () => {
165
+ const drafts = await facility.open(draftsDomainSpec);
166
+ await importLegacyDrafts(drafts, root);
167
+ await healReplayedRefusals(drafts);
168
+ return drafts;
169
+ })();
170
+ this.cached.set(facility, { root, ready });
171
+ try {
172
+ return await ready;
173
+ }
174
+ catch (error) {
175
+ // Unconditional: one slot per facility exists at a time (a
176
+ // foreign root refuses above), so this rejection owns the slot.
177
+ this.cached.delete(facility);
178
+ throw error;
179
+ }
180
+ }
181
+ }
182
+ /** Open (or reuse) the drafts domain through the mounted seat. The
183
+ * apply mounts `DraftsDomainSeatService` before the remote
184
+ * services; tests mount it on their own Context.
185
+ * @param ctx - the Context whose fiber carries the seat.
186
+ * @returns the ready domain handle. */
187
+ export async function openDraftsDomain(ctx) {
188
+ const seat = ctx.get("meliteDraftsDomain");
189
+ if (seat === undefined || seat === null) {
190
+ throw new Error("[estate-drafts] drafts domain seat not mounted (new DraftsDomainSeatService(ctx))");
191
+ }
192
+ return seat.open();
193
+ }
194
+ //# sourceMappingURL=store.js.map
package/lib/trail.d.ts ADDED
@@ -0,0 +1,16 @@
1
+ export declare function canonicalOutputUrl(url: string): string;
2
+ /** A result's OUTPUT urls, one spelling: the artifacts name→url map
3
+ * first, the flat assetUrls list second, the lone url third (the
4
+ * same harvest order the client's preview reads). */
5
+ export declare function resultOutputUrls(result: unknown): string[];
6
+ /** The draft row's terminal words (see remote.ts's trail laws). */
7
+ export declare function isTerminalTrailWord(v: unknown): boolean;
8
+ /** Same run identity: two non-empty equal run_id strings. */
9
+ export declare function sameTrailRunIdentity(a: unknown, b: unknown): boolean;
10
+ /** THE ONE-ROW-PER-RUN TRAIL (bench-trail W2's law, applied to any
11
+ * carried history): identity is the run_id first — the media route
12
+ * and the gallery proxy spell the same file differently — with the
13
+ * canonical-url set as the no-id fallback. Order preserved, newest
14
+ * first in, newest first out. */
15
+ export declare function trailDedupe(history: unknown[]): unknown[];
16
+ //# sourceMappingURL=trail.d.ts.map
package/lib/trail.js ADDED
@@ -0,0 +1,91 @@
1
+
2
+ // trail's dedup/canonical laws live here so EVERY carrier obeys them
3
+ // — the patch door's archive (remote.ts), the load/undo memory carry
4
+ // (bench.ts), and any future writer. remote.ts imports bench.ts, so
5
+ // bench-facing carriers can never import remote.ts back; this module
6
+ // is the cycle-free home both sides share.
7
+ import { RUN_MEDIA_PREFIX } from "@melite/contracts/benchStage";
8
+ /** One url, canonical: the run-relative path. The media route and
9
+ * the gallery proxy spell the SAME file two ways
10
+ * (/melite-media/runs/<rest>, /infer-gallery/artifact?path=<enc>) —
11
+ * every dedup compares canonical forms, never wire spellings. The
12
+ * run-media prefix rides the contract's constant — the closure
13
+ * gate's no-second-copy law. */
14
+ const MEDIA_RUNS = RUN_MEDIA_PREFIX + "/";
15
+ export function canonicalOutputUrl(url) {
16
+ if (url.startsWith(MEDIA_RUNS))
17
+ return url.slice(MEDIA_RUNS.length);
18
+ if (url.startsWith("/infer-gallery/artifact?path=")) {
19
+ try {
20
+ return decodeURIComponent(url.slice("/infer-gallery/artifact?path=".length));
21
+ }
22
+ catch {
23
+ // a malformed escape is not a spelling of another file — keep it
24
+ return url;
25
+ }
26
+ }
27
+ return url;
28
+ }
29
+ /** A result's OUTPUT urls, one spelling: the artifacts name→url map
30
+ * first, the flat assetUrls list second, the lone url third (the
31
+ * same harvest order the client's preview reads). */
32
+ export function resultOutputUrls(result) {
33
+ if (typeof result !== "object" || result === null || Array.isArray(result))
34
+ return [];
35
+ const row = result;
36
+ const urls = [];
37
+ if (row["artifacts"] !== null && typeof row["artifacts"] === "object" && !Array.isArray(row["artifacts"])) {
38
+ for (const v of Object.values(row["artifacts"])) {
39
+ if (typeof v === "string" && v !== "")
40
+ urls.push(v);
41
+ }
42
+ }
43
+ if (urls.length === 0 && Array.isArray(row["assetUrls"])) {
44
+ for (const v of row["assetUrls"]) {
45
+ if (typeof v === "string" && v !== "")
46
+ urls.push(v);
47
+ }
48
+ }
49
+ if (urls.length === 0 && typeof row["url"] === "string" && row["url"] !== "")
50
+ urls.push(row["url"]);
51
+ return urls;
52
+ }
53
+ const TRAIL_TERMINAL = new Set(["done", "completed", "failed", "stopped"]);
54
+ /** The draft row's terminal words (see remote.ts's trail laws). */
55
+ export function isTerminalTrailWord(v) {
56
+ return typeof v === "string" && TRAIL_TERMINAL.has(v);
57
+ }
58
+ /** Same run identity: two non-empty equal run_id strings. */
59
+ export function sameTrailRunIdentity(a, b) {
60
+ return typeof a === "string" && a !== "" && a === b;
61
+ }
62
+ /** THE ONE-ROW-PER-RUN TRAIL (bench-trail W2's law, applied to any
63
+ * carried history): identity is the run_id first — the media route
64
+ * and the gallery proxy spell the same file differently — with the
65
+ * canonical-url set as the no-id fallback. Order preserved, newest
66
+ * first in, newest first out. */
67
+ export function trailDedupe(history) {
68
+ const out = [];
69
+ const runIds = new Set();
70
+ const sets = [];
71
+ for (const entry of history) {
72
+ if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
73
+ out.push(entry);
74
+ continue;
75
+ }
76
+ const row = entry;
77
+ const rid = row["run_id"];
78
+ if (typeof rid === "string" && rid !== "") {
79
+ if (runIds.has(rid))
80
+ continue;
81
+ runIds.add(rid);
82
+ }
83
+ const canon = new Set(resultOutputUrls(row).map(canonicalOutputUrl));
84
+ if (sets.some((s) => s.size === canon.size && [...s].every((u) => canon.has(u))))
85
+ continue;
86
+ sets.push(canon);
87
+ out.push(entry);
88
+ }
89
+ return out;
90
+ }
91
+ //# sourceMappingURL=trail.js.map
@@ -0,0 +1,3 @@
1
+ /* Generated by @deepseek-ai/dsh-typert-generator from FaceModel — do not edit. */
2
+
3
+ export declare const TYPERT: unknown