@tekyzinc/gsd-t 5.11.12 → 5.11.14
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 +42 -0
- package/README.md +1 -1
- package/bin/gsd-t-concise-rewrite.cjs +74 -52
- package/package.json +1 -1
- package/scripts/gsd-t-concise-hook.js +10 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,48 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to GSD-T are documented here. Updated with each release.
|
|
4
4
|
|
|
5
|
+
## [5.11.14] - 2026-08-09
|
|
6
|
+
|
|
7
|
+
### Fixed — the shortened reply appeared as a third copy instead of the only one
|
|
8
|
+
|
|
9
|
+
The hook told the model to "replace it with this shorter version". A model
|
|
10
|
+
cannot replace a reply already sent — it can only write another. Read as an
|
|
11
|
+
instruction to restate, it re-emitted the LONG original, so the reader saw the
|
|
12
|
+
full reply, then the short one, then the full one again.
|
|
13
|
+
|
|
14
|
+
The instruction now describes the only action available: your entire next
|
|
15
|
+
message is this text, copied exactly, nothing before or after, and do not repeat
|
|
16
|
+
any part of the previous reply. Stated in words rather than wrapper markers,
|
|
17
|
+
which the model copies through.
|
|
18
|
+
|
|
19
|
+
- `scripts/gsd-t-concise-hook.js`: the block instruction
|
|
20
|
+
- `test/m107-concise-rewrite.test.js`: 3 tests — no "replace", the repeat is forbidden outright, and no markers that could land in the reply
|
|
21
|
+
|
|
22
|
+
## [5.11.13] - 2026-08-09
|
|
23
|
+
|
|
24
|
+
### Fixed — the reply shortener discarded 4 of every 6 rewrites
|
|
25
|
+
|
|
26
|
+
A keyword check counted question marks, file paths and numbers, and threw the
|
|
27
|
+
whole rewrite away if a count dropped. Almost every rejection was the same
|
|
28
|
+
thing: the writer had asked *himself* a question ("Now the proof: does it
|
|
29
|
+
fire?"), the rewrite correctly cut it as narration, and the check saw a question
|
|
30
|
+
disappear. So a working shortener never once delivered.
|
|
31
|
+
|
|
32
|
+
Counting punctuation cannot tell an ask from thinking out loud. A reader can.
|
|
33
|
+
The same model now reads its own short version back against two questions — is
|
|
34
|
+
this only what he needs, and is it as short as his rules demand — and **fixes**
|
|
35
|
+
it. The reviewer returns text, never a verdict, so nothing is ever discarded. A
|
|
36
|
+
failed review keeps the first pass's rewrite rather than losing it.
|
|
37
|
+
|
|
38
|
+
Both passes now carry the relevance rule: keep only what changes what he
|
|
39
|
+
decides, does next, or now knows.
|
|
40
|
+
|
|
41
|
+
Measured on the reply that failed 4 of 6 before: **6 of 6 delivered, zero
|
|
42
|
+
discarded, 236 words down to 75-158.** Two Sonnet calls, 12-45s.
|
|
43
|
+
|
|
44
|
+
- `bin/gsd-t-concise-rewrite.cjs`: the check is gone; a review pass replaces it
|
|
45
|
+
- `test/m107-concise-rewrite.test.js`: 6 tests, including that the check cannot come back
|
|
46
|
+
|
|
5
47
|
## [5.11.12] - 2026-08-09
|
|
6
48
|
|
|
7
49
|
### Fixed — a retired command stayed typeable forever
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# GSD-T: Contract-Driven Development for Claude Code
|
|
2
2
|
|
|
3
|
-
**v5.11.
|
|
3
|
+
**v5.11.14** - 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.
|
|
@@ -59,16 +59,24 @@ Rewrite the reply below following these rules exactly:
|
|
|
59
59
|
answering a direct question about that. He asks when he wants it.
|
|
60
60
|
4. NO JARGON. Plain words. If a technical term is genuinely needed, put the
|
|
61
61
|
plain meaning first and the term in brackets after it.
|
|
62
|
-
5.
|
|
62
|
+
5. KEEP ONLY WHAT IS RELEVANT TO HIM. Ask of every sentence: does this change
|
|
63
|
+
what he decides, what he does next, or what he now knows? If not, cut it.
|
|
64
|
+
Work the writer did, steps taken, what was checked, what was ruled out — all
|
|
65
|
+
of that is the writer's business, not his, unless he asked.
|
|
63
66
|
6. Prefer a short list or a small table over a paragraph.
|
|
64
67
|
|
|
65
68
|
KEEP THESE. They are not optional, and dropping any one of them means the
|
|
66
69
|
rewrite is rejected and thrown away:
|
|
67
70
|
|
|
68
71
|
- The first line, if it is a dated status banner.
|
|
69
|
-
- EVERY question being asked
|
|
70
|
-
something, that question MUST appear in your rewrite,
|
|
71
|
-
the end. This is the single most common way a rewrite is
|
|
72
|
+
- EVERY question being asked OF THE READER — one he is meant to answer. If the
|
|
73
|
+
reply ends by asking him something, that question MUST appear in your rewrite,
|
|
74
|
+
as its own line, at the end. This is the single most common way a rewrite is
|
|
75
|
+
rejected.
|
|
76
|
+
A question the writer asks HIMSELF is not one of these. "Is that the cause?",
|
|
77
|
+
"Now the proof: does the hook fire?", "So what is slow here?" are thinking out
|
|
78
|
+
loud — cut them like any other narration. The test is simple: would he type an
|
|
79
|
+
answer to it? If not, it is not a question.
|
|
72
80
|
- Any warning, failure, or thing that went wrong.
|
|
73
81
|
- File paths and links, exactly as written.
|
|
74
82
|
- Code blocks, exactly as written.
|
|
@@ -99,46 +107,46 @@ function wordCount(s) {
|
|
|
99
107
|
}
|
|
100
108
|
|
|
101
109
|
/**
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
110
|
+
* The second pass — the rewrite reviewed before it is delivered.
|
|
111
|
+
*
|
|
112
|
+
* A keyword check used to sit here: it counted question marks, file paths and
|
|
113
|
+
* numbers, and threw the whole rewrite away if a count dropped. It discarded
|
|
114
|
+
* 4 of every 6 rewrites, almost always because the writer had asked HIMSELF a
|
|
115
|
+
* question ("Now the proof: does it fire?") which the rewrite correctly cut as
|
|
116
|
+
* narration. Counting punctuation cannot tell an ask from thinking out loud.
|
|
117
|
+
*
|
|
118
|
+
* A reader can. So the same model that wrote the short version now reads it
|
|
119
|
+
* back against one question — is this what David needs, and is it as short as
|
|
120
|
+
* his rules demand — and fixes it. The reviewer returns text, never a verdict,
|
|
121
|
+
* so there is no path on which the work is discarded.
|
|
105
122
|
*/
|
|
106
|
-
|
|
107
|
-
return {
|
|
108
|
-
questions: (text.match(/[^.!?\n]*\?/g) || []).map((q) => q.trim()).filter((q) => q.length > 10),
|
|
109
|
-
numbers: text.match(/\b\d[\d,._]*\b/g) || [],
|
|
110
|
-
paths: text.match(/[\w./-]+\.(?:js|cjs|mjs|ts|tsx|json|md|py|sh)\b/g) || [],
|
|
111
|
-
codeBlocks: (text.match(/```/g) || []).length / 2,
|
|
112
|
-
};
|
|
113
|
-
}
|
|
123
|
+
const REVIEW = `You are checking a shortened reply before it reaches David.
|
|
114
124
|
|
|
115
|
-
|
|
116
|
-
const a = extractInvariants(original);
|
|
117
|
-
const b = extractInvariants(rewritten);
|
|
118
|
-
const lost = [];
|
|
125
|
+
He is a slow reader. Every extra line costs him real time.
|
|
119
126
|
|
|
120
|
-
|
|
121
|
-
lost.push("a question to the reader was dropped");
|
|
122
|
-
}
|
|
123
|
-
const lostPaths = a.paths.filter((p) => !rewritten.includes(p));
|
|
124
|
-
if (lostPaths.length > 0 && lostPaths.length === a.paths.length && a.paths.length > 0) {
|
|
125
|
-
lost.push("every file path was dropped");
|
|
126
|
-
}
|
|
127
|
-
if (a.codeBlocks > 0 && b.codeBlocks < a.codeBlocks) {
|
|
128
|
-
lost.push("a code block was dropped");
|
|
129
|
-
}
|
|
130
|
-
// A number appearing in the rewrite that was never in the original means
|
|
131
|
-
// something was invented.
|
|
132
|
-
const invented = b.numbers.filter((n) => n.length > 2 && !a.numbers.includes(n));
|
|
133
|
-
if (invented.length > 0) {
|
|
134
|
-
lost.push(`a number appeared that was not in the original: ${invented[0]}`);
|
|
135
|
-
}
|
|
136
|
-
return lost;
|
|
137
|
-
}
|
|
127
|
+
Two questions, both about the SHORT version:
|
|
138
128
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
129
|
+
1. Is this ONLY what he needs? Cut anything that does not change what he
|
|
130
|
+
decides, what he does next, or what he now knows. The work someone did,
|
|
131
|
+
steps taken, what was checked, what was ruled out — his business only if he
|
|
132
|
+
asked.
|
|
133
|
+
|
|
134
|
+
2. Is it truly concise by his rules? Answer first, nothing before it. No
|
|
135
|
+
preamble, no backstory, no jargon standing in for a plain word. Lists and
|
|
136
|
+
small tables over paragraphs.
|
|
137
|
+
|
|
138
|
+
Then check nothing was lost that he needs:
|
|
139
|
+
- a question he is meant to ANSWER must still be there, as its own line at the
|
|
140
|
+
end. A question the writer asked himself is narration — it should be gone.
|
|
141
|
+
- warnings, failures, and things that went wrong stay.
|
|
142
|
+
- file paths, links, code blocks and specific numbers stay exactly as written.
|
|
143
|
+
- no fact, number or name may change, and nothing may be added.
|
|
144
|
+
|
|
145
|
+
Return the final reply and nothing else. If it is already right, return it
|
|
146
|
+
unchanged. Never return commentary, never return an empty response.`;
|
|
147
|
+
|
|
148
|
+
/** One call to a fresh Claude. Used by both passes. */
|
|
149
|
+
function askClaude(prompt, cfg) {
|
|
142
150
|
// `--setting-sources project` is what stops the shortener shortening itself.
|
|
143
151
|
//
|
|
144
152
|
// A child started with the personal settings inherits the very Stop hook that
|
|
@@ -181,6 +189,25 @@ function rewrite(text, cfg) {
|
|
|
181
189
|
return { ok: true, text: out };
|
|
182
190
|
}
|
|
183
191
|
|
|
192
|
+
/** Pass 1 — shorten it. */
|
|
193
|
+
function rewrite(text, cfg) {
|
|
194
|
+
return askClaude(`${RULES}\n\n--- REPLY TO REWRITE ---\n${text}`, cfg);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Pass 2 — read the short version back and fix what pass 1 got wrong.
|
|
199
|
+
*
|
|
200
|
+
* Returns text, never a verdict, so the work is never discarded. If the review
|
|
201
|
+
* itself fails, pass 1's rewrite stands: it was already an improvement, and
|
|
202
|
+
* losing it because a second opinion did not arrive would be the old bug in a
|
|
203
|
+
* new place.
|
|
204
|
+
*/
|
|
205
|
+
function review(original, shortened, cfg) {
|
|
206
|
+
const prompt = `${REVIEW}\n\n--- WHAT HE ORIGINALLY WROTE (for reference only) ---\n${original}\n\n--- THE SHORT VERSION TO CHECK AND RETURN ---\n${shortened}`;
|
|
207
|
+
const r = askClaude(prompt, cfg);
|
|
208
|
+
return r.ok ? r.text : shortened;
|
|
209
|
+
}
|
|
210
|
+
|
|
184
211
|
function parseArgs(argv) {
|
|
185
212
|
const args = { project: process.cwd() };
|
|
186
213
|
for (let i = 2; i < argv.length; i++) {
|
|
@@ -231,19 +258,14 @@ function main() {
|
|
|
231
258
|
}, args.json);
|
|
232
259
|
}
|
|
233
260
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
error: `the rewrite lost something: ${lost.join("; ")}`,
|
|
239
|
-
note: "Rewrite rejected — this is the original, unchanged.",
|
|
240
|
-
words: before,
|
|
241
|
-
}, args.json);
|
|
242
|
-
}
|
|
261
|
+
// Second pass: the same model reads its own short version back, against the
|
|
262
|
+
// only two questions that matter — is this what David needs, and is it as
|
|
263
|
+
// short as his rules demand. It returns text, so nothing is ever discarded.
|
|
264
|
+
const finalText = review(text, r.text, cfg);
|
|
243
265
|
|
|
244
|
-
const after = wordCount(
|
|
266
|
+
const after = wordCount(finalText);
|
|
245
267
|
emit({
|
|
246
|
-
ok: true, exitCode: EXIT_OK, text:
|
|
268
|
+
ok: true, exitCode: EXIT_OK, text: finalText,
|
|
247
269
|
words: before, wordsAfter: after,
|
|
248
270
|
saved: before - after,
|
|
249
271
|
}, args.json);
|
|
@@ -251,4 +273,4 @@ function main() {
|
|
|
251
273
|
|
|
252
274
|
if (require.main === module) main();
|
|
253
275
|
|
|
254
|
-
module.exports = { wordCount,
|
|
276
|
+
module.exports = { wordCount, readConfig, rewrite, review, askClaude, RULES, REVIEW };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tekyzinc/gsd-t",
|
|
3
|
-
"version": "5.11.
|
|
3
|
+
"version": "5.11.14",
|
|
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",
|
|
@@ -237,9 +237,17 @@ function main() {
|
|
|
237
237
|
const saved = (result.words || 0) - (result.wordsAfter || 0);
|
|
238
238
|
if (saved < 15) return allow(); // not worth the extra turn
|
|
239
239
|
|
|
240
|
+
// "Replace it with this" asks for something the model cannot do — it has no
|
|
241
|
+
// way to unsay a reply, only to write another. Read as an instruction to
|
|
242
|
+
// restate, it re-emitted the long original, so David saw the full reply,
|
|
243
|
+
// then the short one, then the full one again. The instruction has to
|
|
244
|
+
// describe the only real action: emit this text and stop.
|
|
240
245
|
block(
|
|
241
|
-
"
|
|
242
|
-
"
|
|
246
|
+
"STOP. Do not continue your previous reply and do not repeat any part of " +
|
|
247
|
+
"it. Your entire next message is the text below, copied exactly — nothing " +
|
|
248
|
+
"before it, nothing after it, no commentary, no heading, no explanation " +
|
|
249
|
+
"that you shortened anything. Everything from the next line onward IS " +
|
|
250
|
+
"your message:\n\n" +
|
|
243
251
|
result.text
|
|
244
252
|
);
|
|
245
253
|
};
|