@dtlabs/ai-toolkit 0.24.8 → 0.24.9
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/CHANGELOG.md +9 -0
- package/package.json +1 -1
- package/src/claude/workflows/pm-phase1.js +52 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
## 0.1.4 (2026-07-21)
|
|
2
|
+
## [0.24.9](https://github.com/dtlab-tech/ai-toolkit/compare/v0.24.8...v0.24.9) (2026-11-03)
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
### Bug Fixes
|
|
6
|
+
|
|
7
|
+
* **pm-phase1:** never overwrite a good skeleton with a non-document reply, and repair last-cycle AC traceability once ([8f2f32f](https://github.com/dtlab-tech/ai-toolkit/commit/8f2f32f1852ade4551da62cbac8bc07d8f0c2961))
|
|
8
|
+
* **pm-phase1:** never overwrite a good skeleton with a non-document reply, and repair last-cycle AC traceability once ([3038efe](https://github.com/dtlab-tech/ai-toolkit/commit/3038efed641464b93da50377cd834cc1d4a85e48))
|
|
9
|
+
* **pm-phase1:** never overwrite a good skeleton with a non-document reply, and repair last-cycle AC traceability once ([784f814](https://github.com/dtlab-tech/ai-toolkit/commit/784f8141fb4afdefe2b2592f9d8b57a4f41207c2))
|
|
10
|
+
|
|
2
11
|
## [0.24.8](https://github.com/dtlab-tech/ai-toolkit/compare/v0.24.7...v0.24.8) (2026-11-02)
|
|
3
12
|
|
|
4
13
|
|
package/package.json
CHANGED
|
@@ -39,6 +39,32 @@ return c.run(meta.name, featureDir, prefix, async () => {
|
|
|
39
39
|
// per-UC and per-component generation loops' own fail-fast validity check.
|
|
40
40
|
const USE_CASE_RETRY_ATTEMPTS = 2
|
|
41
41
|
const COMPONENT_RETRY_ATTEMPTS = 2
|
|
42
|
+
const SKELETON_RETRY_ATTEMPTS = 2
|
|
43
|
+
|
|
44
|
+
// A skeleton worker occasionally answers with a question or an apology instead of the document
|
|
45
|
+
// ("I have not generated the skeleton yet ... I'm asking here"). The skeleton was written
|
|
46
|
+
// straight onto req/index.md or spec/index.md and only checked afterwards, so one such reply
|
|
47
|
+
// destroyed the good document that was there (FTR-034, revision cycle 2). The reply is now
|
|
48
|
+
// checked for every numbered section BEFORE the target file is touched; on a bad reply the
|
|
49
|
+
// worker is asked once more, and if that fails too the run stops with the existing file intact.
|
|
50
|
+
async function writeSkeleton(label, workerId, basePrompt, sectionCount, outPath, transform) {
|
|
51
|
+
let raw
|
|
52
|
+
for (let attempt = 1; attempt <= SKELETON_RETRY_ATTEMPTS; attempt++) {
|
|
53
|
+
const prompt = attempt === 1 ? basePrompt : basePrompt +
|
|
54
|
+
'\n\nYour previous reply was not the document. This is a non-interactive run: nobody can answer a question. ' +
|
|
55
|
+
'Reply with ONLY the complete document, every numbered section included, and with no preamble. Where feature.md ' +
|
|
56
|
+
'leaves a point undecided, record it inside the document as an open question instead of asking.'
|
|
57
|
+
raw = await c.worker(workerId, prompt, attempt === 1 ? undefined : { label: `${label}:skeleton:retry:${attempt}` })
|
|
58
|
+
if (missingSections(raw, sectionCount).length === 0) {
|
|
59
|
+
c.writeOutput(outPath, transform ? transform(raw) : raw)
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// same message the post-write completeness check has always produced (truncation guard)
|
|
64
|
+
try { assertCompleteSections(label, raw, sectionCount) } catch (e) {
|
|
65
|
+
throw new Error(`${e.message}; after ${SKELETON_RETRY_ATTEMPTS} attempts the existing file was left untouched`)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
42
68
|
|
|
43
69
|
// Templates live under the toolkit's own installed scripts/templates/ — outside this project
|
|
44
70
|
// for a globally-installed toolkit, which a non-interactive `--print` worker invocation has no
|
|
@@ -215,8 +241,9 @@ return c.run(meta.name, featureDir, prefix, async () => {
|
|
|
215
241
|
// 1. Skeleton (no declared worker() output — host writes it itself, mirroring FTR-020's
|
|
216
242
|
// skeleton step)
|
|
217
243
|
if (regenSkeleton) {
|
|
218
|
-
|
|
219
|
-
|
|
244
|
+
await writeSkeleton('Requirements', reqId,
|
|
245
|
+
withTemplate(featurePath, 'req/index.md', 'gaia-requirements-index-template.md') + revisionSection(revisionFindings),
|
|
246
|
+
9, reqIndexPath)
|
|
220
247
|
}
|
|
221
248
|
|
|
222
249
|
// 2. Structural self-consistency pre-check (req-skeleton-check.js, same
|
|
@@ -565,8 +592,9 @@ return c.run(meta.name, featureDir, prefix, async () => {
|
|
|
565
592
|
|
|
566
593
|
// 1. Skeleton (no declared worker() output — host writes it itself)
|
|
567
594
|
if (regenSkeleton) {
|
|
568
|
-
|
|
569
|
-
|
|
595
|
+
await writeSkeleton('Tech-Spec', specId,
|
|
596
|
+
withTemplate(featurePath, 'spec/index.md', 'gaia-tech-spec-index-template.md') + revisionSection(revisionFindings),
|
|
597
|
+
12, specIndexPath, skeleton => applyComponentSlugs(skeleton, manifest))
|
|
570
598
|
}
|
|
571
599
|
|
|
572
600
|
// 2. Structural pre-check (tech-spec-graph-checks.js, unmodified — FTR-023 — now pointed at
|
|
@@ -769,14 +797,29 @@ return c.run(meta.name, featureDir, prefix, async () => {
|
|
|
769
797
|
break
|
|
770
798
|
}
|
|
771
799
|
if (cycle === 3) {
|
|
772
|
-
// The deterministic AC<->component traceability gaps stay a hard failure
|
|
773
|
-
// mechanical and the Work Breakdown relies on that
|
|
800
|
+
// The deterministic AC<->component traceability gaps stay a hard failure if the repair
|
|
801
|
+
// below cannot close them: they are mechanical and the Work Breakdown relies on that
|
|
802
|
+
// mapping. What the validator judges
|
|
774
803
|
// (open design points, drill-down findings) is for a person to accept or reject, and Gate
|
|
775
804
|
// 1 is that review: regenerating again cannot decide a point feature.md leaves undecided
|
|
776
805
|
// (on FTR-034 three full runs of three cycles each never converged for that reason).
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
806
|
+
//
|
|
807
|
+
// A traceability gap found on the LAST cycle used to be unrecoverable: a Requirements
|
|
808
|
+
// revision on cycle 2 can add acceptance criteria the Tech-Spec does not yet address, and
|
|
809
|
+
// that gap is only routed to a Tech-Spec revision on the cycle after. Give it one repair:
|
|
810
|
+
// regenerate the Tech-Spec once with the gaps as feedback, then re-check mechanically.
|
|
811
|
+
let repaired = false
|
|
812
|
+
if (structuralFindings.length) {
|
|
813
|
+
revisionFindings = structuralFindings
|
|
814
|
+
await generateTechSpec(true)
|
|
815
|
+
assembledTechSpec = assembleTechSpec()
|
|
816
|
+
if (computeAcComponentTraceabilityGaps(c.read(reqIndexPath), c.read(specIndexPath)).length) throw new Error('Validation gaps remain after 3 cycles')
|
|
817
|
+
repaired = true
|
|
818
|
+
c.append(file('Validation-Report'), '\n\n## Post-validation repair\nThe AC traceability findings listed above were repaired after the last validation cycle by regenerating the Tech-Spec once. The repaired Tech-Spec was checked mechanically (every AC is addressed) but was not re-validated by the validator.\n')
|
|
819
|
+
}
|
|
820
|
+
openGaps = mergedFindings.filter(f => !structuralFindings.includes(f))
|
|
821
|
+
validationSummary = `${openGaps.length} open gap(s) after 3 cycles, left for Gate 1 review (see the Validation Report)` +
|
|
822
|
+
(repaired ? '; the Tech-Spec was regenerated once to repair AC traceability and not re-validated' : '')
|
|
780
823
|
break
|
|
781
824
|
}
|
|
782
825
|
if (!mergedNeedsRequirementsFix && !mergedNeedsTechSpecFix) throw new Error(`Validation agent reported gaps on cycle ${cycle} but flagged neither document for revision`)
|