@tekyzinc/gsd-t 5.11.20 → 5.11.21

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 CHANGED
@@ -2,6 +2,29 @@
2
2
 
3
3
  All notable changes to GSD-T are documented here. Updated with each release.
4
4
 
5
+ ## [5.11.21] - 2026-08-10
6
+
7
+ ### Added — a final sweep that re-runs slices the rush broke
8
+
9
+ Two slices failed an otherwise clean run on rate limits alone: ten agents in
10
+ flight, the account throttled, and all three attempts landing inside the same
11
+ squeeze. That failure says nothing about the slice — only about when it ran.
12
+
13
+ After the deep scan, the run now waits 30 seconds for any active rate-limit
14
+ window to pass, then retries every failed slice **one at a time, outside the
15
+ concurrency gate**. Re-running failures through the same crowded gate that
16
+ caused them would reproduce the cause.
17
+
18
+ It costs a few minutes on runs that need it and nothing at all on runs that do
19
+ not. A recovered slice stops being a coverage gap and its findings reach the
20
+ register.
21
+
22
+ The sweep runs **before** the partial-coverage halt, so the run only stops for
23
+ what is genuinely lost.
24
+
25
+ - `templates/workflows/gsd-t-scan.workflow.js`: the sweep; `allFindings` now reads the array the sweep repairs
26
+ - `test/m112-scan-schema-tolerance.test.js`: 4 more tests — serial, before the halt, waits, and recovered findings reach the register
27
+
5
28
  ## [5.11.20] - 2026-08-10
6
29
 
7
30
  ### Fixed — the real cause of the scan failures: agents pass their answer as a string
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # GSD-T: Contract-Driven Development for Claude Code
2
2
 
3
- **v5.11.20** - A methodology for reliable, parallelizable development using Claude Code with optional Agent Teams support.
3
+ **v5.11.21** - A methodology for reliable, parallelizable development using Claude Code with optional Agent Teams support.
4
4
 
5
5
  **Eliminates context rot** — task-level fresh dispatch (one subagent per task, ~10-20% context each) means compaction never triggers.
6
6
  **Compaction-proof debug loops** — `gsd-t headless --debug-loop` runs test-fix-retest cycles as separate `claude -p` sessions. A JSONL debug ledger persists all hypothesis/fix/learning history across fresh sessions. Anti-repetition preamble injection prevents retrying failed hypotheses. Escalation tiers (sonnet → opus → human) and a hard iteration ceiling enforced externally.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tekyzinc/gsd-t",
3
- "version": "5.11.20",
3
+ "version": "5.11.21",
4
4
  "description": "GSD-T: Contract-Driven Development for Claude Code — 54 slash commands with headless-by-default workflow spawning, unattended supervisor relay with event stream, graph-powered code analysis, real-time agent dashboard, task telemetry, doc-ripple enforcement, backlog management, impact analysis, test sync, milestone archival, and PRD generation",
5
5
  "author": "Tekyz, Inc.",
6
6
  "license": "MIT",
@@ -824,9 +824,57 @@ slices.forEach((s, i) => {
824
824
  const r = resultsByIndex[i];
825
825
  if (!r || r.failed) failedSlices.push(s.key);
826
826
  });
827
+ // ── Final sweep: re-run what the rush broke ─────────────────────────────────
828
+ //
829
+ // A slice can exhaust its three attempts purely because the run was at full
830
+ // tilt — 10 agents in flight, the account rate-limited, and all three tries
831
+ // landing inside the same squeeze. That failure says nothing about the slice.
832
+ //
833
+ // So once the deep scan is over and the burst has drained, try the stragglers
834
+ // again: one at a time, unhurried, with the whole machine to themselves. It
835
+ // costs a few minutes on the runs that need it and nothing at all on the runs
836
+ // that do not.
837
+ //
838
+ // Serial and ungated on purpose. Re-running failures through the same crowded
839
+ // gate that caused them would reproduce the cause.
840
+ if (failedSlices.length > 0) {
841
+ log(`↻ final sweep — retrying ${failedSlices.length} failed slice(s) one at a time, now that the run has drained: ${failedSlices.join(", ")}`);
842
+ await sleep(30000); // let any active rate-limit window pass before starting
843
+
844
+ const stillFailed = [];
845
+ for (const key of failedSlices) {
846
+ const slice = slices.find((sl) => sl.key === key);
847
+ if (!slice) { stillFailed.push(key); continue; }
848
+
849
+ const recovered = await scanSlice(slice); // scanSlice resolves its own graph context
850
+
851
+ if (recovered && !recovered.failed) {
852
+ const idx = slices.indexOf(slice);
853
+ resultsByIndex[idx] = recovered;
854
+ log(`✓ sweep recovered "${key}" — ${(recovered.findings || []).length} finding(s)`);
855
+ } else {
856
+ stillFailed.push(key);
857
+ log(`✗ sweep could not recover "${key}"`);
858
+ }
859
+ }
860
+
861
+ // Only the failed list needs updating by hand — coverage and the findings
862
+ // list are computed from `resultsByIndex` below, which the sweep has already
863
+ // repaired in place.
864
+ failedSlices.length = 0;
865
+ failedSlices.push(...stillFailed);
866
+
867
+ log(stillFailed.length === 0
868
+ ? `✓ final sweep restored full coverage — ${slices.length}/${slices.length} slices`
869
+ : `⚠ final sweep left ${stillFailed.length} slice(s) unrecovered: ${stillFailed.join(", ")}`);
870
+ }
871
+
827
872
  const succeededCount = slices.length - failedSlices.length;
828
873
  const coverageComplete = failedSlices.length === 0;
829
- const allFindings = sliceResults.filter(Boolean).filter((r) => !r.failed).flatMap((r) => (r.findings || []).map((f) => ({ ...f, slice: r.slice })));
874
+ // Read from resultsByIndex, not sliceResults: the final sweep writes recovered
875
+ // slices back into resultsByIndex, and a recovered slice's findings must reach
876
+ // the register.
877
+ const allFindings = resultsByIndex.filter(Boolean).filter((r) => !r.failed).flatMap((r) => (r.findings || []).map((f) => ({ ...f, slice: r.slice })));
830
878
  if (!coverageComplete) {
831
879
  log(`⚠ PARTIAL COVERAGE — ${failedSlices.length}/${slices.length} slices failed after retry and produced NO findings: ${failedSlices.join(", ")}.`);
832
880