heyspex 0.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/README.md +157 -0
- package/bin/hs.mjs +1028 -0
- package/bin/postinstall.mjs +88 -0
- package/dev-factory/lib/fleet-readiness.mjs +274 -0
- package/dev-factory/lib/fleet-state.mjs +250 -0
- package/dev-factory/lib/sufficiency-score.mjs +441 -0
- package/dist/cli/hs-check.mjs +747 -0
- package/dist/cli/hs-claim.mjs +541 -0
- package/dist/cli/hs-connect.mjs +3436 -0
- package/dist/cli/hs-defer.mjs +8455 -0
- package/dist/cli/hs-env.mjs +36845 -0
- package/dist/cli/hs-init.mjs +1145 -0
- package/dist/cli/hs-install.mjs +1390 -0
- package/dist/cli/hs-join.mjs +38553 -0
- package/dist/cli/hs-vault-pull.mjs +7782 -0
- package/dist/cli/hs-vault.mjs +4166 -0
- package/dist/cli/hs-workspace.mjs +2898 -0
- package/dist/cli-templates/customer-vault/specs/entity-model.md +1735 -0
- package/dist/cli-templates/customer-vault/specs/protocols/canonical-frontmatter-templates.md +531 -0
- package/dist/cli-templates/customer-vault/specs/protocols/memory-protocol.md +48 -0
- package/dist/cli-templates/customer-vault/specs/protocols/spec-hierarchy.md +548 -0
- package/docs/mcp-client-config.md +200 -0
- package/package.json +124 -0
- package/scripts/check-mcp-freshness.mjs +379 -0
- package/scripts/dev-server-status.mjs +722 -0
- package/scripts/gateway-skills-lib.mjs +421 -0
- package/scripts/lib/console-url-resolver.mjs +152 -0
- package/scripts/lib/dev-mode.mjs +369 -0
- package/scripts/lib/hs-link.mjs +154 -0
- package/scripts/lib/hs-source-commit.mjs +207 -0
- package/scripts/lib/hs-source-log.mjs +366 -0
- package/scripts/lib/hs-source-preflight.mjs +402 -0
- package/scripts/lib/hs-source-push.mjs +307 -0
- package/scripts/lib/hs-source-secret-scan.mjs +263 -0
- package/scripts/lib/standalone-doctor.mjs +89 -0
- package/scripts/vault-id-lib.mjs +173 -0
- package/vendor/heyspex-mcp/alignment-gate.mjs +1347 -0
- package/vendor/heyspex-mcp/blocker-resolver.mjs +891 -0
- package/vendor/heyspex-mcp/breakdown-ladder.mjs +309 -0
- package/vendor/heyspex-mcp/breakdown-source.mjs +236 -0
- package/vendor/heyspex-mcp/breakdown-writer.mjs +524 -0
- package/vendor/heyspex-mcp/brief-observability.mjs +67 -0
- package/vendor/heyspex-mcp/canvas-inbox.mjs +130 -0
- package/vendor/heyspex-mcp/capture-active-rehydrate.mjs +76 -0
- package/vendor/heyspex-mcp/capture-buffer-patches.mjs +147 -0
- package/vendor/heyspex-mcp/capture-channel.mjs +577 -0
- package/vendor/heyspex-mcp/capture-console-client.mjs +290 -0
- package/vendor/heyspex-mcp/capture-focus.mjs +1366 -0
- package/vendor/heyspex-mcp/capture-kind-suggest.mjs +121 -0
- package/vendor/heyspex-mcp/capture-outbox.mjs +239 -0
- package/vendor/heyspex-mcp/capture-stage-gate.mjs +160 -0
- package/vendor/heyspex-mcp/cli.mjs +15754 -0
- package/vendor/heyspex-mcp/config-settings.mjs +419 -0
- package/vendor/heyspex-mcp/console-fetch.mjs +342 -0
- package/vendor/heyspex-mcp/defer-spec.mjs +527 -0
- package/vendor/heyspex-mcp/deferred-reclaim.mjs +284 -0
- package/vendor/heyspex-mcp/design-tools.mjs +449 -0
- package/vendor/heyspex-mcp/dev-factory-bridge.mjs +66 -0
- package/vendor/heyspex-mcp/diagnose-skeleton.mjs +114 -0
- package/vendor/heyspex-mcp/fleet-queue-tools.mjs +241 -0
- package/vendor/heyspex-mcp/hooks-engine.mjs +399 -0
- package/vendor/heyspex-mcp/login-handoff.mjs +438 -0
- package/vendor/heyspex-mcp/mcp-subprocess.mjs +136 -0
- package/vendor/heyspex-mcp/mvp-mode.mjs +101 -0
- package/vendor/heyspex-mcp/next-resolution.mjs +240 -0
- package/vendor/heyspex-mcp/next-review.mjs +548 -0
- package/vendor/heyspex-mcp/peer-presence.mjs +430 -0
- package/vendor/heyspex-mcp/plan-ground-conflicts.mjs +321 -0
- package/vendor/heyspex-mcp/plan-ground.mjs +2001 -0
- package/vendor/heyspex-mcp/plan-ingest.mjs +476 -0
- package/vendor/heyspex-mcp/plan-push.mjs +1826 -0
- package/vendor/heyspex-mcp/plan-review.mjs +1419 -0
- package/vendor/heyspex-mcp/preflight-gate.mjs +0 -0
- package/vendor/heyspex-mcp/procedure-tools.mjs +970 -0
- package/vendor/heyspex-mcp/promote-capture.mjs +1280 -0
- package/vendor/heyspex-mcp/promote-diagnose.mjs +187 -0
- package/vendor/heyspex-mcp/promote-research-to-diagnose.mjs +338 -0
- package/vendor/heyspex-mcp/promote-research.mjs +1553 -0
- package/vendor/heyspex-mcp/promotion-helpers.mjs +280 -0
- package/vendor/heyspex-mcp/read-path.mjs +138 -0
- package/vendor/heyspex-mcp/recipe-tools.mjs +258 -0
- package/vendor/heyspex-mcp/regen-tasks.mjs +326 -0
- package/vendor/heyspex-mcp/register-spec.mjs +417 -0
- package/vendor/heyspex-mcp/research-focus.mjs +476 -0
- package/vendor/heyspex-mcp/research-tools.mjs +109 -0
- package/vendor/heyspex-mcp/research-type-suggest.mjs +112 -0
- package/vendor/heyspex-mcp/resolution-focus.mjs +45 -0
- package/vendor/heyspex-mcp/review-focus.mjs +55 -0
- package/vendor/heyspex-mcp/review-rollup.mjs +47 -0
- package/vendor/heyspex-mcp/run-front.mjs +60 -0
- package/vendor/heyspex-mcp/scheduler.mjs +813 -0
- package/vendor/heyspex-mcp/seat-identity.mjs +281 -0
- package/vendor/heyspex-mcp/settings-tools.mjs +119 -0
- package/vendor/heyspex-mcp/spec-id-lib.mjs +790 -0
- package/vendor/heyspex-mcp/split-research.mjs +832 -0
- package/vendor/heyspex-mcp/submit-for-review.mjs +190 -0
- package/vendor/heyspex-mcp/summary-contract.mjs +162 -0
- package/vendor/heyspex-mcp/test-helpers.mjs +43 -0
- package/vendor/heyspex-mcp/validate-linkage.mjs +574 -0
- package/vendor/heyspex-mcp/vault-resolve.mjs +297 -0
- package/vendor/heyspex-mcp/vault-settings.mjs +87 -0
- package/vendor/heyspex-mcp/verify-reproduction.mjs +314 -0
- package/vendor/heyspex-mcp/why-now.mjs +64 -0
- package/vendor/heyspex-mcp/yaml-scalar.mjs +34 -0
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deferred split-child reclaim + Resolution DLQ ([[HS-TASK-6OU5-deferred-work-reclaim-and-resolution-dlq]]).
|
|
3
|
+
* Consumes lease/heartbeat reclaim from [[HS-EPIC-96YK-claim-leases-heartbeats-and-passive-nudg]] —
|
|
4
|
+
* does not implement the sweep itself.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { readFileSync, existsSync, readdirSync, mkdirSync } from 'node:fs';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
|
|
10
|
+
import { allocateRandomVaultId } from '../../scripts/vault-id-lib.mjs';
|
|
11
|
+
import { yamlScalar } from './yaml-scalar.mjs';
|
|
12
|
+
import { mintFamilyKey, mintFileKey, parseSpecId } from './spec-id-lib.mjs';
|
|
13
|
+
import {
|
|
14
|
+
isoNow,
|
|
15
|
+
deriveSlug,
|
|
16
|
+
getFrontmatterBlock,
|
|
17
|
+
getScalarField,
|
|
18
|
+
setScalarField,
|
|
19
|
+
bumpUpdated,
|
|
20
|
+
appendChangeLogRow,
|
|
21
|
+
commitWrites,
|
|
22
|
+
} from './promotion-helpers.mjs';
|
|
23
|
+
import { extractHandoffEnvelopeYaml } from '../../spex-console/src/lib/indexer/handoff-envelope.mjs';
|
|
24
|
+
import { buildDiagnoseSkeletonSections } from './diagnose-skeleton.mjs';
|
|
25
|
+
|
|
26
|
+
/** Default cap when frontmatter omits `attempt_count` ([[HS-TASK-6OU5]]). */
|
|
27
|
+
export const DEFAULT_DEFER_RECLAIM_ATTEMPT_CAP = 3;
|
|
28
|
+
|
|
29
|
+
function collectOccupiedDiagnoseIds(vaultRoot) {
|
|
30
|
+
const occupied = new Set();
|
|
31
|
+
const dir = join(vaultRoot, 'specs', 'diagnoses');
|
|
32
|
+
if (!existsSync(dir)) return occupied;
|
|
33
|
+
for (const file of readdirSync(dir)) {
|
|
34
|
+
// Key the occupied set on the canonical family-first id (dual-read on both
|
|
35
|
+
// the basename and the frontmatter id) so suffix-collision detection matches
|
|
36
|
+
// what allocateRandomVaultId generates/compares ([[HS-EPIC-DLE3]]).
|
|
37
|
+
const fromName = parseSpecId(file.replace(/\.md$/i, ''));
|
|
38
|
+
if (fromName && fromName.typeLabel === 'DIAG') {
|
|
39
|
+
occupied.add(`HS-${fromName.familyKey}-DIAG`);
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
const raw = readFileSync(join(dir, file), 'utf8');
|
|
43
|
+
const idMatch = raw.match(/^id:\s*(\S+)/m);
|
|
44
|
+
if (idMatch) {
|
|
45
|
+
const fromId = parseSpecId(idMatch[1].replace(/^['"]|['"]$/g, ''));
|
|
46
|
+
if (fromId && fromId.typeLabel === 'DIAG') {
|
|
47
|
+
occupied.add(`HS-${fromId.familyKey}-DIAG`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
} catch {
|
|
51
|
+
/* skip */
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return occupied;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function readAttemptCount(fmBlock) {
|
|
58
|
+
const raw = getScalarField(fmBlock, 'attempt_count');
|
|
59
|
+
if (raw == null || raw === '') return 0;
|
|
60
|
+
const n = Number.parseInt(String(raw), 10);
|
|
61
|
+
return Number.isFinite(n) && n >= 0 ? n : 0;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function isDeferredSplitTaskRaw(raw) {
|
|
65
|
+
const fm = getFrontmatterBlock(raw);
|
|
66
|
+
if (!fm) return false;
|
|
67
|
+
const splitOf = getScalarField(fm.block, 'split_of');
|
|
68
|
+
const splitIndex = getScalarField(fm.block, 'split_index');
|
|
69
|
+
return Boolean(splitOf && splitIndex);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function handoffEnvelopeSectionFromBody(body) {
|
|
73
|
+
const extracted = extractHandoffEnvelopeYaml(body);
|
|
74
|
+
if (!extracted || 'missingFence' in extracted) return '';
|
|
75
|
+
return `## Handoff envelope
|
|
76
|
+
|
|
77
|
+
\`\`\`yaml
|
|
78
|
+
${extracted.yaml.trimEnd()}
|
|
79
|
+
\`\`\``;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function buildDlqDiagnoseContent({
|
|
83
|
+
diagnoseId,
|
|
84
|
+
fileKey,
|
|
85
|
+
familyKey,
|
|
86
|
+
taskBasename,
|
|
87
|
+
taskName,
|
|
88
|
+
attemptCount,
|
|
89
|
+
reclaimReason,
|
|
90
|
+
handoffSection,
|
|
91
|
+
now,
|
|
92
|
+
}) {
|
|
93
|
+
const slugPart = deriveSlug(`Deferred work DLQ — ${taskName}`);
|
|
94
|
+
const today = now.slice(0, 10);
|
|
95
|
+
const fm = `---
|
|
96
|
+
id: ${diagnoseId}
|
|
97
|
+
file_id: ${fileKey}
|
|
98
|
+
family: ${familyKey}
|
|
99
|
+
name: ${yamlScalar(`Deferred work DLQ — ${taskName}`)}
|
|
100
|
+
type: diagnose
|
|
101
|
+
status: open
|
|
102
|
+
owner: pwher
|
|
103
|
+
severity: warning
|
|
104
|
+
summary: |-
|
|
105
|
+
Deferred split child [[${taskBasename}]] exceeded the reclaim attempt cap (${attemptCount}) after repeated lease/heartbeat expiry.
|
|
106
|
+
Routed to Resolution for human triage; verify partial work on disk before continuing.
|
|
107
|
+
tags:
|
|
108
|
+
- delegation
|
|
109
|
+
- dlq
|
|
110
|
+
related:
|
|
111
|
+
- '[[${taskBasename}]]'
|
|
112
|
+
created: '${now}'
|
|
113
|
+
updated: '${now}'
|
|
114
|
+
---
|
|
115
|
+
`;
|
|
116
|
+
|
|
117
|
+
const body = `## Symptom
|
|
118
|
+
|
|
119
|
+
Deferred split child [[${taskBasename}]] was abandoned ${attemptCount} time(s). The last reclaim reason was \`${reclaimReason}\`.
|
|
120
|
+
|
|
121
|
+
## Reproduction
|
|
122
|
+
|
|
123
|
+
1. Open [[${taskBasename}]] and read the handoff envelope below.
|
|
124
|
+
2. Compare \`summary_done\` / git diff against what remains in \`remaining\`.
|
|
125
|
+
3. Decide whether to re-open the task, split again, or close as wont-fix.
|
|
126
|
+
|
|
127
|
+
${handoffSection || '_(No handoff envelope block found on the deferred task.)_'}
|
|
128
|
+
|
|
129
|
+
${buildDiagnoseSkeletonSections({
|
|
130
|
+
'Root cause': '_DLQ hint: likely repeated agent timeout / context loss on deferred pickup._',
|
|
131
|
+
Fix: '_DLQ hint: resume from verified partial state, or re-defer with a fresh handoff_id._',
|
|
132
|
+
})}
|
|
133
|
+
|
|
134
|
+
## Change log
|
|
135
|
+
|
|
136
|
+
| Date | Author | Change |
|
|
137
|
+
|---|---|---|
|
|
138
|
+
| ${today} | deferred-reclaim | Auto-filed from [[${taskBasename}]] after attempt_count ≥ cap. |
|
|
139
|
+
`;
|
|
140
|
+
|
|
141
|
+
// Era-3 file-key-first basename: `HS-<fileKey>-<familyKey>-DIAG-<slug>`.
|
|
142
|
+
return { content: fm + body, basename: `${diagnoseId}-${familyKey}-DIAG-${slugPart}` };
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function bumpAttemptCountInContent(raw, { now, author, reclaimReason }) {
|
|
146
|
+
const fm = getFrontmatterBlock(raw);
|
|
147
|
+
if (!fm) return { changed: false, content: raw, attemptCount: 0 };
|
|
148
|
+
const prev = readAttemptCount(fm.block);
|
|
149
|
+
const next = prev + 1;
|
|
150
|
+
let block = setScalarField(fm.block, 'attempt_count', String(next));
|
|
151
|
+
block = bumpUpdated(block, now);
|
|
152
|
+
let body = appendChangeLogRow(
|
|
153
|
+
fm.body,
|
|
154
|
+
now.slice(0, 10),
|
|
155
|
+
author,
|
|
156
|
+
`Reclaim attempt ${next} (${reclaimReason})`,
|
|
157
|
+
);
|
|
158
|
+
return {
|
|
159
|
+
changed: true,
|
|
160
|
+
content: `${fm.open}${block}${fm.close}${body}`,
|
|
161
|
+
attemptCount: next,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function cancelDeferredTaskContent(raw, diagnoseBasename, now, author) {
|
|
166
|
+
const fm = getFrontmatterBlock(raw);
|
|
167
|
+
if (!fm) return { changed: false, content: raw };
|
|
168
|
+
let block = setScalarField(fm.block, 'status', 'cancelled');
|
|
169
|
+
block = setScalarField(block, 'close_reason', 'duplicate');
|
|
170
|
+
block = bumpUpdated(block, now);
|
|
171
|
+
let body = appendChangeLogRow(
|
|
172
|
+
fm.body,
|
|
173
|
+
now.slice(0, 10),
|
|
174
|
+
author,
|
|
175
|
+
`Routed to Resolution DLQ → [[${diagnoseBasename}]]`,
|
|
176
|
+
);
|
|
177
|
+
return { changed: true, content: `${fm.open}${block}${fm.close}${body}` };
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* After a lease/heartbeat reclaim on a deferred split child: bump attempt_count;
|
|
182
|
+
* past cap → file HS-DIAG + cancel the deferred task.
|
|
183
|
+
*
|
|
184
|
+
* @param {string} vaultRoot
|
|
185
|
+
* @param {{ absPath: string, relPath: string, basename: string, raw: string }} task
|
|
186
|
+
* @param {{ reclaimReason: string, author?: string, attemptCap?: number, randomUnit?: () => number }} opts
|
|
187
|
+
*/
|
|
188
|
+
export function executeDeferredSplitReclaim(vaultRoot, task, opts = {}) {
|
|
189
|
+
if (!isDeferredSplitTaskRaw(task.raw)) {
|
|
190
|
+
return { ok: true, skipped: true, reason: 'not_deferred_split' };
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const now = isoNow();
|
|
194
|
+
const author = opts.author ?? 'deferred-reclaim';
|
|
195
|
+
const reclaimReason = opts.reclaimReason ?? 'lease_expired';
|
|
196
|
+
const attemptCap = opts.attemptCap ?? DEFAULT_DEFER_RECLAIM_ATTEMPT_CAP;
|
|
197
|
+
|
|
198
|
+
const bumped = bumpAttemptCountInContent(task.raw, { now, author, reclaimReason });
|
|
199
|
+
if (!bumped.changed) {
|
|
200
|
+
return { ok: false, error: 'INVALID_TASK', message: 'deferred task has no frontmatter' };
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const writes = [{ kind: 'update', absPath: task.absPath, content: bumped.content }];
|
|
204
|
+
|
|
205
|
+
if (bumped.attemptCount < attemptCap) {
|
|
206
|
+
const commitResult = commitWrites(writes);
|
|
207
|
+
if (!commitResult.ok) {
|
|
208
|
+
return {
|
|
209
|
+
ok: false,
|
|
210
|
+
error: 'WRITE_FAILED',
|
|
211
|
+
message: commitResult.error?.message ?? 'unknown write failure',
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
ok: true,
|
|
216
|
+
action: 'reopened',
|
|
217
|
+
attempt_count: bumped.attemptCount,
|
|
218
|
+
attempt_cap: attemptCap,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const fm = getFrontmatterBlock(task.raw);
|
|
223
|
+
const taskName = getScalarField(fm?.block ?? '', 'name') ?? task.basename;
|
|
224
|
+
const handoffSection = handoffEnvelopeSectionFromBody(fm?.body ?? '');
|
|
225
|
+
|
|
226
|
+
const occupied = collectOccupiedDiagnoseIds(vaultRoot);
|
|
227
|
+
// Era-3 file-key-first ([[naming-v3-7-rulings-hs-namespace-kept]]): the
|
|
228
|
+
// FAMILY token still comes from the legacy allocator's `HS-<family>-DIAG`
|
|
229
|
+
// draw; `id:` keys onto the file key alone.
|
|
230
|
+
const allocatedFamilyId = allocateRandomVaultId('diagnose', occupied, { randomUnit: opts.randomUnit });
|
|
231
|
+
const familyKey =
|
|
232
|
+
parseSpecId(allocatedFamilyId)?.familyKey ?? mintFamilyKey(vaultRoot, { randomUnit: opts.randomUnit });
|
|
233
|
+
// Per-file FILE KEY (owner ruling 2026-07-10) — filename + `file_id:` SSOT,
|
|
234
|
+
// and (V3) the anchor for `id:` itself.
|
|
235
|
+
const fileKey = mintFileKey(vaultRoot, { randomUnit: opts.randomUnit });
|
|
236
|
+
const diagnoseId = `HS-${fileKey}`;
|
|
237
|
+
const built = buildDlqDiagnoseContent({
|
|
238
|
+
diagnoseId,
|
|
239
|
+
fileKey,
|
|
240
|
+
familyKey,
|
|
241
|
+
taskBasename: task.basename,
|
|
242
|
+
taskName: String(taskName).replace(/^['"]|['"]$/g, ''),
|
|
243
|
+
attemptCount: bumped.attemptCount,
|
|
244
|
+
reclaimReason,
|
|
245
|
+
handoffSection,
|
|
246
|
+
now,
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
const diagnoseDir = join(vaultRoot, 'specs', 'diagnoses');
|
|
250
|
+
if (!existsSync(diagnoseDir)) mkdirSync(diagnoseDir, { recursive: true });
|
|
251
|
+
const diagnoseAbsPath = join(diagnoseDir, `${built.basename}.md`);
|
|
252
|
+
writes.push({ kind: 'create', absPath: diagnoseAbsPath, content: built.content });
|
|
253
|
+
|
|
254
|
+
const cancelled = cancelDeferredTaskContent(bumped.content, built.basename, now, author);
|
|
255
|
+
if (cancelled.changed) {
|
|
256
|
+
writes[0] = { kind: 'update', absPath: task.absPath, content: cancelled.content };
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const commitResult = commitWrites(writes);
|
|
260
|
+
if (!commitResult.ok) {
|
|
261
|
+
return {
|
|
262
|
+
ok: false,
|
|
263
|
+
error: 'WRITE_FAILED',
|
|
264
|
+
message: commitResult.error?.message ?? 'unknown write failure',
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return {
|
|
269
|
+
ok: true,
|
|
270
|
+
action: 'dlq',
|
|
271
|
+
attempt_count: bumped.attemptCount,
|
|
272
|
+
attempt_cap: attemptCap,
|
|
273
|
+
diagnose_id: diagnoseId,
|
|
274
|
+
diagnose_basename: built.basename,
|
|
275
|
+
diagnose_path: join('specs', 'diagnoses', `${built.basename}.md`),
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export const __testables = {
|
|
280
|
+
readAttemptCount,
|
|
281
|
+
isDeferredSplitTaskRaw,
|
|
282
|
+
bumpAttemptCountInContent,
|
|
283
|
+
buildDlqDiagnoseContent,
|
|
284
|
+
};
|