@tekyzinc/gsd-t 5.19.11 → 5.20.11
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 +57 -0
- package/README.md +2 -2
- package/bin/gsd-t-estimate-sheet.cjs +1184 -0
- package/bin/gsd-t.js +44 -0
- package/commands/cpua.md +18 -1
- package/commands/gsd-t-estimate.md +92 -111
- package/commands/gsd-t-help.md +3 -3
- package/package.json +1 -1
- package/templates/CLAUDE-global.md +1 -1
- package/templates/estimate-config.json +5 -2
- package/templates/estimate-sheet-spec.md +261 -0
- package/templates/playbooks/tekyz-estimation-and-prd-playbook.md +8 -4
package/bin/gsd-t.js
CHANGED
|
@@ -1910,6 +1910,10 @@ const GLOBAL_BIN_TOOLS = [
|
|
|
1910
1910
|
// caught four times before ([[project_global_bin_propagation_gap]]). Also in
|
|
1911
1911
|
// PROJECT_BIN_TOOLS below — both lists, both tools.
|
|
1912
1912
|
"gsd-t-testplan-lint.cjs", "gsd-t-testplan-halt.cjs", "gsd-t-testplan-rows.cjs",
|
|
1913
|
+
// v5.20.10 — deterministic Tekyz estimate-sheet writer + read-back audit
|
|
1914
|
+
// (`gsd-t estimate-sheet`). Dispatched by bin/gsd-t.js AND read by
|
|
1915
|
+
// /gsd-t-estimate, so it ships in BOTH lists ([[project_global_bin_propagation_gap]]).
|
|
1916
|
+
"gsd-t-estimate-sheet.cjs",
|
|
1913
1917
|
];
|
|
1914
1918
|
|
|
1915
1919
|
// Directories under bin/ that must ship whole. A runner whose parts stay behind
|
|
@@ -2180,6 +2184,7 @@ const SHARED_TEMPLATES = [
|
|
|
2180
2184
|
"design-contract.md",
|
|
2181
2185
|
"shared-services-contract.md",
|
|
2182
2186
|
"estimate-config.json",
|
|
2187
|
+
"estimate-sheet-spec.md",
|
|
2183
2188
|
];
|
|
2184
2189
|
|
|
2185
2190
|
function installSharedTemplates() {
|
|
@@ -3461,6 +3466,20 @@ async function doUpdateAll() {
|
|
|
3461
3466
|
);
|
|
3462
3467
|
}
|
|
3463
3468
|
|
|
3469
|
+
// Numeric dotted-version compare: negative when a < b, 0 when equal, positive when a > b.
|
|
3470
|
+
// GSD-T versions are plain Major.Minor.Patch integers (patch always ≥ 10), so a
|
|
3471
|
+
// segment-wise numeric compare is exact; no prerelease tags exist.
|
|
3472
|
+
function versionCmp(a, b) {
|
|
3473
|
+
const pa = String(a).split(".").map((n) => parseInt(n, 10));
|
|
3474
|
+
const pb = String(b).split(".").map((n) => parseInt(n, 10));
|
|
3475
|
+
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
3476
|
+
const x = Number.isNaN(pa[i]) ? 0 : pa[i];
|
|
3477
|
+
const y = Number.isNaN(pb[i]) ? 0 : pb[i];
|
|
3478
|
+
if (x !== y) return x - y;
|
|
3479
|
+
}
|
|
3480
|
+
return 0;
|
|
3481
|
+
}
|
|
3482
|
+
|
|
3464
3483
|
// Upgrade the globally-installed @tekyzinc/gsd-t to @latest. Returns
|
|
3465
3484
|
// { upgraded: bool, reexec: bool, error?: string }.
|
|
3466
3485
|
// - reexec=true when the on-disk version after `npm install -g` is newer than
|
|
@@ -3494,6 +3513,19 @@ async function upgradeGlobalBinary() {
|
|
|
3494
3513
|
// Best-effort; fall through.
|
|
3495
3514
|
}
|
|
3496
3515
|
|
|
3516
|
+
if (newVersion && versionCmp(newVersion, PKG_VERSION) < 0) {
|
|
3517
|
+
// v5.20.10 (2026-09-17): right after `npm publish`, npm's cached package
|
|
3518
|
+
// listing still named the PREVIOUS version as @latest, so this step
|
|
3519
|
+
// installed 5.19.11 over a running 5.20.10, reported it as an "upgrade",
|
|
3520
|
+
// handed off to the OLD binary, and that binary overwrote ~/.claude/commands
|
|
3521
|
+
// and every project with the old release. A downgrade is never an upgrade —
|
|
3522
|
+
// HALT and say how to fix it, never continue on a stale listing.
|
|
3523
|
+
error(`HALT: npm installed v${newVersion} over the running v${PKG_VERSION} — @latest resolved to an OLDER release.`);
|
|
3524
|
+
info("npm's cached package listing is stale. Run `npm cache clean --force`, wait until");
|
|
3525
|
+
info(`\`curl -sI https://registry.npmjs.org/@tekyzinc/gsd-t/-/gsd-t-${PKG_VERSION}.tgz\` returns 200, then re-run update-all.`);
|
|
3526
|
+
info(`Restore the current release first: npm install -g @tekyzinc/gsd-t@${PKG_VERSION}`);
|
|
3527
|
+
process.exit(1);
|
|
3528
|
+
}
|
|
3497
3529
|
if (newVersion && newVersion !== PKG_VERSION) {
|
|
3498
3530
|
success(`Global binary upgraded: v${PKG_VERSION} → v${newVersion}`);
|
|
3499
3531
|
info("Handing off to the newly-installed binary for propagation...");
|
|
@@ -3701,6 +3733,10 @@ const PROJECT_BIN_TOOLS = [
|
|
|
3701
3733
|
// and /gsd-t-test-plan calls them directly — same propagation-gap class as the
|
|
3702
3734
|
// graph tools above. Also in GLOBAL_BIN_TOOLS — both lists, both tools.
|
|
3703
3735
|
"gsd-t-testplan-lint.cjs", "gsd-t-testplan-halt.cjs", "gsd-t-testplan-rows.cjs",
|
|
3736
|
+
// v5.20.10 — deterministic Tekyz estimate-sheet writer + read-back audit
|
|
3737
|
+
// (`gsd-t estimate-sheet`). Dispatched by bin/gsd-t.js AND read by
|
|
3738
|
+
// /gsd-t-estimate, so it ships in BOTH lists ([[project_global_bin_propagation_gap]]).
|
|
3739
|
+
"gsd-t-estimate-sheet.cjs",
|
|
3704
3740
|
];
|
|
3705
3741
|
|
|
3706
3742
|
// Files that older versions of this installer copied into project bin/ but
|
|
@@ -5990,6 +6026,14 @@ if (require.main === module) {
|
|
|
5990
6026
|
});
|
|
5991
6027
|
process.exit(res.status == null ? 1 : res.status);
|
|
5992
6028
|
}
|
|
6029
|
+
case "estimate-sheet": {
|
|
6030
|
+
// v5.20.10 — deterministic Tekyz estimate-sheet writer + audit
|
|
6031
|
+
// (`gsd-t estimate-sheet read|plan-check|write|audit --sheet <id>`).
|
|
6032
|
+
const { spawnSync } = require("child_process");
|
|
6033
|
+
const js = path.join(__dirname, "gsd-t-estimate-sheet.cjs");
|
|
6034
|
+
const res = spawnSync(process.execPath, [js, ...args.slice(1)], { stdio: "inherit" });
|
|
6035
|
+
process.exit(res.status == null ? 1 : res.status);
|
|
6036
|
+
}
|
|
5993
6037
|
case "test-data": {
|
|
5994
6038
|
// M58 D1 — `gsd-t test-data --list|--purge` thin dispatcher.
|
|
5995
6039
|
const { spawnSync } = require("child_process");
|
package/commands/cpua.md
CHANGED
|
@@ -120,6 +120,19 @@ G="$(npm root -g)/@tekyzinc/gsd-t"
|
|
|
120
120
|
# the pre-publish package listing cached and `@tekyzinc/gsd-t@{NEW}` returns ETARGET
|
|
121
121
|
# for minutes while `npm view` already shows the version (v5.17.14, 2026-09-03).
|
|
122
122
|
# The tarball URL bypasses the cached listing and is deterministic.
|
|
123
|
+
# 1b. WAIT until the registry actually SERVES the tarball, then CLEAR npm's cached listing.
|
|
124
|
+
# v5.20.10 (2026-09-17): `npm publish` printed "+ @tekyzinc/gsd-t@5.20.10" and `npm view`
|
|
125
|
+
# showed it, but the tarball URL 404'd for ~4 minutes. Worse, npm's cached package
|
|
126
|
+
# listing still said latest = the PREVIOUS version, so `gsd-t update-all` (which runs
|
|
127
|
+
# `npm install -g @tekyzinc/gsd-t@latest`) DOWNGRADED the global, handed off to the old
|
|
128
|
+
# binary, and that binary rewrote ~/.claude/commands and 34 projects with the old release
|
|
129
|
+
# — twice. Poll the tarball, then clean the cache, then install. Never skip either.
|
|
130
|
+
for i in $(seq 1 60); do
|
|
131
|
+
[ "$(curl -s -o /dev/null -w '%{http_code}' "https://registry.npmjs.org/@tekyzinc/gsd-t/-/gsd-t-{NEW_VERSION}.tgz")" = "200" ] && break
|
|
132
|
+
sleep 10
|
|
133
|
+
done
|
|
134
|
+
[ "$(curl -s -o /dev/null -w '%{http_code}' "https://registry.npmjs.org/@tekyzinc/gsd-t/-/gsd-t-{NEW_VERSION}.tgz")" = "200" ] || { echo "HALT: tarball still 404 after 10 min"; exit 1; }
|
|
135
|
+
npm cache clean --force
|
|
123
136
|
npm install -g "https://registry.npmjs.org/@tekyzinc/gsd-t/-/gsd-t-{NEW_VERSION}.tgz"
|
|
124
137
|
# 2. VERIFY ON DISK — never trust npm's exit code for this step. On v5.17.13 `npm install -g`
|
|
125
138
|
# reported success and left the OLD version in place; `update-all` then ran from the
|
|
@@ -140,7 +153,11 @@ fi
|
|
|
140
153
|
# file and the command files; only then does update-all see the new release.
|
|
141
154
|
gsd-t install 2>&1 | tail -5
|
|
142
155
|
[ "$(cat ~/.claude/.gsd-t-version)" = "{NEW_VERSION}" ] || { echo "HALT: ~/.claude/.gsd-t-version did not advance"; exit 1; }
|
|
143
|
-
# 4.
|
|
156
|
+
# 4. Prove `@latest` now resolves to the NEW version (update-all installs `@latest`; a stale
|
|
157
|
+
# listing here is the downgrade path — since v5.20.11 update-all HALTS on a downgrade
|
|
158
|
+
# instead of handing off, but do not rely on the halt: check first).
|
|
159
|
+
[ "$(npm view @tekyzinc/gsd-t dist-tags.latest)" = "{NEW_VERSION}" ] || { echo "HALT: registry latest is not {NEW_VERSION}"; exit 1; }
|
|
160
|
+
# 5. Propagate, then prove the global is STILL the new version and a NEW file reached a project.
|
|
144
161
|
gsd-t update-all 2>&1 | tail -30
|
|
145
162
|
[ "$(node -p "require('$G/package.json').version")" = "{NEW_VERSION}" ] || { echo "HALT: global package reverted during update-all"; exit 1; }
|
|
146
163
|
```
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
# GSD-T: Estimate — Tekyz Client Estimate +
|
|
1
|
+
# GSD-T: Estimate — Tekyz Client Estimate (T-Shirt Size + Team Mix + Technology Stack)
|
|
2
2
|
|
|
3
|
-
You are turning a **structured work document** into a **Tekyz client estimate**
|
|
3
|
+
You are turning a **structured work document** into a **Tekyz client estimate** in a Google Sheet: a **T-Shirt Size** tab (sized line-items → days → dollars), a **Team Mix** tab (who does the work, month by month), and a **Technology Stack** tab. The input can be a GSD-T tech-debt scan register, a gap-analysis sheet, a new-feature or new-application requirements doc, or any comparable spec. `$ARGUMENTS` may carry `--sheet <url>`, `--input <path>`, and a scope override (`--severity high`).
|
|
4
4
|
|
|
5
|
-
**
|
|
5
|
+
**Scope is the SHEET only.** This command does NOT write a PRD or any other document — a client PRD is `/gsd-t-prd`'s job, run separately if wanted. The one client-facing artifact here is the sheet; the only optional file is `share/<Repo>-estimate-redteam-notes.md` (overridden Red Team objections).
|
|
6
|
+
|
|
7
|
+
**THE SHEET IS WRITTEN BY A TOOL, NOT BY HAND.** `gsd-t estimate-sheet` (`bin/gsd-t-estimate-sheet.cjs`, project-local `bin/` first, else the global `gsd-t`) reads the sheet, validates a JSON plan, writes all three tabs with the exact formulas and styling, and audits by reading back — halting on any violation. **You never PUT a cell or send a batchUpdate yourself.** Your output is the plan (judgment only: sizes, team FTE, tech-stack lines); the tool computes everything derived. Spec: `~/.claude/templates/estimate-sheet-spec.md` (bundled: `templates/estimate-sheet-spec.md`) — §6 shows the plan shape (`gsd-t estimate-sheet plan-schema` prints it). Procedure background: `~/.claude/playbooks/tekyz-estimation-and-prd-playbook.md` (else `templates/playbooks/`).
|
|
6
8
|
|
|
7
9
|
> **Client-billed work, not GSD-T build work.** This produces a paid client estimate — the "no cost estimates" rule (`feedback_no_human_hour_estimates`) governs GSD-T's OWN Max-funded build work, NOT client deliverables. Dollar figures here are correct and expected.
|
|
8
10
|
|
|
@@ -10,180 +12,159 @@ You are turning a **structured work document** into a **Tekyz client estimate**
|
|
|
10
12
|
|
|
11
13
|
This process is judgment-heavy. **You (the operator) are the final arbiter of every estimate.** The command does NOT run end-to-end autonomously.
|
|
12
14
|
|
|
13
|
-
- **Judgment phases PAUSE for review** before advancing: **Step 2 (sizing)**, **Step 2.5 (adjustments)**, **Step
|
|
14
|
-
- **Mechanical phases FLOW but SHOW their result**: Step 1 (numbering), Step
|
|
15
|
+
- **Judgment phases PAUSE for review** before advancing: **Step 2 (sizing)**, **Step 2.5 (adjustments)**, **Step 4 (Team Mix roster + ramp)**, **Step 8 (Red Team)**. Present the output, wait for `continue` or corrections.
|
|
16
|
+
- **Mechanical phases FLOW but SHOW their result**: Step 1 (numbering), Step 6 (sheet write + audit), Step 7 (reconcile). Don't block, but display what happened so nothing is invisible.
|
|
17
|
+
- **Never skip Step 2.5 or Step 8 silently.** Both were skipped on shipped estimates and the operator had to ask for them afterwards. If you skip one, say so in the report and why.
|
|
15
18
|
- **Escape hatch:** if the user says e.g. "run through sizing and grouping, then stop," batch those phases and pause where they asked.
|
|
16
19
|
|
|
17
20
|
## Configuration (parameterized — defaults are Tekyz values)
|
|
18
21
|
|
|
19
|
-
Read
|
|
22
|
+
Read from `$ARGUMENTS` or `.gsd-t/estimate-config.json` if present; otherwise use the Tekyz defaults. **Always name the active values in the report** (no silent defaults). The config is **optional and NOT auto-created** — to override, copy `templates/estimate-config.json` (or `~/.claude/templates/estimate-config.json`) to `.gsd-t/estimate-config.json` and edit. Every field is individually optional.
|
|
20
23
|
|
|
21
24
|
| Param | Default (Tekyz) | Meaning |
|
|
22
25
|
|-------|-----------------|---------|
|
|
23
26
|
| `rate` | `$50/hr` | Blended hourly rate for the LOW figure. |
|
|
24
27
|
| `hoursPerDay` | `8` | Hours per person-day. |
|
|
25
28
|
| `sizeScale` | `XS 0.25 · S 0.5 · M 1 · L 3 · XL 5 · XXL 7` | T-shirt → person-days. |
|
|
26
|
-
| `totalMF` | `0.7` | Overhead multiplier
|
|
27
|
-
| `highFactor` | `1.25` | HIGH = LOW × this. |
|
|
28
|
-
| `sheetTemplateId` | (blank) | Optional template to clone; normally blank — operator
|
|
29
|
+
| `totalMF` | `0.7` | Overhead multiplier. **The sheet's own MF list (`E4:F9`) wins when a sheet exists** — read it, never overwrite it. Hilo sheets run `0.9` (QA .3 · PM .1 · Analysis .1 · Deployment .05 · StdUps/Mtgs .15 · Buffer .2). |
|
|
30
|
+
| `highFactor` | `1.25` | HIGH = LOW × this (the sheet's `G4` wins when a sheet exists). |
|
|
31
|
+
| `sheetTemplateId` | (blank) | Optional template to clone; normally blank — the operator supplies the target sheet. |
|
|
29
32
|
| `gcpProject` | `ai-estimator-415612` | GCP project hosting the permanent Sheets-writer SA. |
|
|
30
33
|
| `serviceAccountEmail` | `gsd-t-sheets-writer@ai-estimator-415612.iam.gserviceaccount.com` | **Permanent** SA — share each sheet with this as Editor. |
|
|
31
34
|
| `serviceAccountKeyPath` | `~/.claude/gsd-t-secrets/gsd-t-sheets-writer-key.json` | SA key (chmod 600, outside any repo). |
|
|
35
|
+
| `newTeamDefault` | `true` | Apply the new-team familiarization adjustment (Step 2.5a) by default. |
|
|
32
36
|
|
|
33
37
|
## Step 0: Inputs + Scope + Sheet
|
|
34
38
|
|
|
35
|
-
1. **
|
|
36
|
-
2. **
|
|
37
|
-
3.
|
|
38
|
-
4. **
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
6. Confirm the active config values above (rate/MF/highFactor — from `.gsd-t/estimate-config.json` or Tekyz defaults).
|
|
43
|
-
7. Decide whether this is a **new-team project** (triggers the familiarization adjustment, Step 2.5) — usually YES for a fresh client.
|
|
39
|
+
1. **Resolve the Google Sheet.** Take `--sheet <url>` from `$ARGUMENTS`; otherwise ask: *"Paste the Google Sheet URL for this estimate."* The operator ALWAYS provides an existing sheet — this command never creates one. Extract the **sheet ID** (between `/d/` and the next `/`) and confirm it back.
|
|
40
|
+
2. **Probe access + read the layout in one step:** `gsd-t estimate-sheet read --sheet <url>` (then `--tab "T-Shirt Size Estimate"`, `--tab "Team Mix"`). A `403` halt means the sheet is not shared — prompt the operator to share it with the SA email as **Editor** ("Notify people" unchecked), wait, re-run. (The tool never sends `X-Goog-User-Project`; with it these sheets 403 even when shared.)
|
|
41
|
+
3. From the read: note the MF list (`E4:F9`), high factor (`G4`), rate (`H4`), whether item rows already exist (→ `sizes` mode) or the tab is empty (→ `items` mode), and whether the Technology Stack tab is filled. The tool reads these again at write time; you read them now so the plan matches the sheet.
|
|
42
|
+
4. **Resolve the input document** (`--input`, else `.gsd-t/techdebt.md`). None → "No input document found. Pass `--input <path>` or run `/gsd-t-scan` / `/gsd-t-gap-analysis` first." and stop.
|
|
43
|
+
5. **Classify the input** so the line-item vocabulary matches: scan register → *findings* (`TD-n`) scoped by severity; gap-analysis sheet → *gaps* (`GA-n`, rows already on the T-Shirt tab with columns A–D filled — you fill E–G only); requirements / feature / app spec → *requirements* (`FR-n` or the doc's own numbering).
|
|
44
|
+
6. **Scope**: scan default = all CRITICAL findings; `--severity high|medium|low|all` widens. Requirements default = all. Confirm scope + item count with the user before sizing.
|
|
45
|
+
7. **Confirm the active config values** — rate, MF list (from the sheet), high factor, and whether this is a **new-team project** (Step 2.5a; usually YES for a fresh client).
|
|
44
46
|
|
|
45
47
|
## Step 1: Numbering hygiene (MECHANICAL — show result)
|
|
46
48
|
|
|
47
|
-
Client-facing line-items
|
|
48
|
-
|
|
49
|
-
**Renumber ONLY when the numbering is absent, non-sequential, or doesn't start at 1.** If it is already sequential and rational, LEAVE IT.
|
|
49
|
+
Client-facing line-items carry **sequential, rational numbering starting at 1**. Renumber ONLY when numbering is absent, non-sequential, or doesn't start at 1 (a crashed-and-rerun scan starting at TD-618 looks bad). Already clean → leave it.
|
|
50
50
|
|
|
51
|
-
- **Unnumbered
|
|
52
|
-
- **Hierarchical
|
|
53
|
-
- **
|
|
54
|
-
- When you DO renumber, do it SAFELY (numbering-only, zero value changes):
|
|
55
|
-
- Confirm the id range is contiguous first, so a blind offset aligns.
|
|
56
|
-
- **Range-bounded regex** — remap ONLY numbers in the doc's actual range, so you never corrupt `DC-n`, another project's `TD-4`, or a different repo's numbering.
|
|
57
|
-
- **Scope to CURRENT deliverables only:** the input doc, plain-English companion, `.gsd-t/scan/*.md`, `docs/*.md`, README, the PRD, `share/*`, and the Google Sheet labels. **Leave `.gsd-t/scan/archive/`, transcripts, heartbeats UNTOUCHED.**
|
|
58
|
-
- **Second pass for non-prefixed formats:** bare `| 618 |` table cells, slashed chains (`TD-2/623`), header text. A first-pass `PREFIX-NNN` regex misses these.
|
|
59
|
-
- **Back up files before the bulk edit.**
|
|
51
|
+
- **Unnumbered** → assign sequential ids (`FR-1, FR-2, …` or `TD-1, …`).
|
|
52
|
+
- **Hierarchical** (`1`, `1.1`, `1.1.1`) → preserve the hierarchy; renumber only to make each level sequential within its parent. Never flatten.
|
|
53
|
+
- When you DO renumber, do it SAFELY: confirm the id range is contiguous; **range-bounded regex** so you never touch `DC-n` or another project's numbering; scope to CURRENT deliverables only (input doc, plain-English companion, `.gsd-t/scan/*.md`, `docs/*.md`, README, `share/*`, the sheet labels) — **leave `.gsd-t/scan/archive/`, transcripts, heartbeats untouched**; second pass for non-prefixed forms (`| 618 |`, `TD-2/623`, headers); **back up files first**.
|
|
60
54
|
- A client that wants the original numbering keeps it — offer, don't force.
|
|
61
55
|
|
|
62
56
|
## Step 2: Size each line-item (T-Shirt Size tab) — JUDGMENT · PAUSE FOR REVIEW
|
|
63
57
|
|
|
64
|
-
For each in-scope item
|
|
58
|
+
For each in-scope item build a row per spec §1.2 — `A` Module · `B` User Type · `C` Functionality (**with the item id**) · `D` Low-Level Requirement · `E` Phase · `F` Web Portal size · `G` Backend/API size. `H:L` are formulas, never values.
|
|
65
59
|
|
|
66
|
-
- **Size each column INDEPENDENTLY** (FE and BE each get their own letter; blank = 0).
|
|
67
|
-
-
|
|
68
|
-
-
|
|
69
|
-
- **
|
|
70
|
-
- **
|
|
60
|
+
- **Size each column INDEPENDENTLY** (FE and BE each get their own letter; blank = 0). Scale: **XS 0.25 · S 0.5 · M 1 · L 3 · XL 5 · XXL 7** person-days.
|
|
61
|
+
- **Bare codes in `F:G`** — `XS` `S` `M` `L` `XL` `XXL`. Never the legend text (`"XS - Extra Small"`). The lookup happens to compute either way, which is why the long form shipped unnoticed.
|
|
62
|
+
- The sheet computes: `Days = F+G` → `MFactor Days = Days × Total MF` → `Total Days` → `LOW $ = Total × 8 × rate` → `HIGH $ = LOW × high factor`.
|
|
63
|
+
- **Cluster by fix-shape to size fast**: "add existing guard to N routes" (XS–S, repeated) vs "new backend surface" (M, +FE) vs "config / single route" (XS). Size the cluster once, apply to members.
|
|
64
|
+
- **Tune the MF per project** (raise Buffer/QA when confidence is low; raise the high factor above 1.25 for more unknowns) — but change the sheet's MF list only with the operator's say-so.
|
|
65
|
+
- **PAUSE:** present the sized rows (or clusters + representative sizes) and the running total (recomputed from raw sizes: `Σ(FE,BE days) × (1 + MF)`). Wait for `continue` or corrections.
|
|
71
66
|
|
|
72
67
|
## Step 2.5: Estimate Adjustments (familiarization + risk/unknowns) — JUDGMENT · PAUSE FOR REVIEW
|
|
73
68
|
|
|
74
|
-
Base sizes assume *familiar* devs on *well-understood* work. Adjust for the two things that make real work heavier
|
|
69
|
+
Base sizes assume *familiar* devs on *well-understood* work. Adjust for the two things that make real work heavier. Document each adjustment per-item so the client sees **why**. **This step is ON by default (`newTeamDefault: true`) — it was skipped on shipped estimates and had to be asked for.**
|
|
70
|
+
|
|
71
|
+
**(a) New-team familiarization** — bump each item's SIZE in proportion to its complexity — **NOT the MF** (the Analysis MF is for a Business Analyst, not dev ramp). Trivial config / single route → no bump. Repeated-pattern guards, few routes → +0–1 tier. High-volume sweeps + new-surface builds → +1 tier. Optionally add a one-time **"Codebase Onboarding & Downstream Analysis"** Common line (L–XL), documented as optional.
|
|
75
72
|
|
|
76
|
-
**(
|
|
77
|
-
- Trivial config / single-route → **no bump**. Repeated-pattern guards, few routes → **+0–1 tier**. High-volume sweeps + new-surface builds → **+1 tier**.
|
|
78
|
-
- Optionally add a one-time **"Codebase Onboarding & Downstream Analysis"** Common line (sized L–XL) — document as optional, client can remove.
|
|
73
|
+
**(b) R&D / unknown-approach / spike risk** — an item needing research, an unproven approach, or an unknown integration gets an uplift for the uncertainty: bump its SIZE or raise the high factor if unknowns dominate. Name the unknown explicitly ("requires spike: undocumented 3rd-party API").
|
|
79
74
|
|
|
80
|
-
|
|
75
|
+
**⚠️ The scale is NON-LINEAR. M→L is a 3× cliff (1 day → 3 days).** Never push an item across M→L unless it is genuinely multi-day. Cap routine-work bumps at M. Calibration: HILO 21 criticals = $8,700 familiar → $11,730 new-team (+35%, bumps capped at M).
|
|
81
76
|
|
|
82
|
-
**⚠️ The scale is NON-LINEAR. M→L is a 3× cliff (1 day → 3 days).** A blind one-tier bump across M→L doubles the total. **Never push an item across M→L unless it is genuinely multi-day.** Cap routine-work bumps at M.
|
|
83
|
-
- Reference calibration: HILO 21 criticals = $8,700 familiar → $11,730 new-team (+35%, bumps capped at M) → $13,090 incl Project Setup.
|
|
84
77
|
- **PAUSE:** present every adjustment (item, reason, before→after size, total delta). Wait for `continue` or corrections.
|
|
85
78
|
|
|
86
|
-
## Step 3: Group by domain +
|
|
79
|
+
## Step 3: Group by domain + section headings (T-Shirt tab)
|
|
80
|
+
|
|
81
|
+
Reorder items into domains. Insert a **section-heading row** before each group per spec §1.2 (merge `A:L`, bg `#1C4F8B`, white bold Arial 10). **No subtotals.**
|
|
82
|
+
|
|
83
|
+
- Insert rows with `insertDimension` (it shifts ranges); never write into rows below a summed range.
|
|
84
|
+
- After reordering, **re-point EVERY aggregate on the tab**: the totals row, the phase rollups `K4:N7` (their `$E$14:$E$<last>` ranges), and the summary block — then move the summary block BELOW the totals row if the template left it inside the summed range (circular `#REF!` otherwise).
|
|
87
85
|
|
|
88
|
-
|
|
86
|
+
## Step 4: Team Mix — JUDGMENT · PAUSE FOR REVIEW
|
|
89
87
|
|
|
90
|
-
|
|
88
|
+
Your judgment is ONE thing: the FTE per discipline (`teamMix.fte` in the plan — `backend` `frontend` `qa` `pm` `ba`, optionally `techlead` `devops`). Everything else on the tab is computed by the tool per spec §2: the split into people (saturate at 1.00, then spill), months, the column count, the ramp by discipline, the remainder formula.
|
|
91
89
|
|
|
92
|
-
|
|
90
|
+
1. **Staff every weighted MF factor** — QA → `qa`, PM → `pm`, Analysis → `ba`. Deployment / standups / buffer are absorbed by the engineers and lead. Typical fractions: PM 0.20–0.25 · BA 0.10 · Tech Lead 0.25 · QA 0.40–0.50. The tool HALTS on a roster that leaves a factor unstaffed — do not argue with it; add the person.
|
|
91
|
+
2. **Run `gsd-t estimate-sheet plan-check --sheet <url> --plan <plan.json>`.** It prints the MF list it read, the T-Shirt total, and the roster table it WOULD write (person · Count · Mths · Days · Hrs · Mon 1..N with the remainder) — or halts with the violation.
|
|
92
|
+
3. **PAUSE:** present that table verbatim. Wait for `continue` or corrections (a resize or a different FTE → edit the plan, re-run plan-check, present again).
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
## Step 5: Technology Stack
|
|
95
95
|
|
|
96
|
-
- **
|
|
97
|
-
- **Check for hardcoded cells** breaking the formula chain (restore `=E×B`, `=J` where a static number was pasted — the Testing row is a known offender).
|
|
98
|
-
- **Verify BOTH halves (F13, J13) equal the T-shirt total.**
|
|
96
|
+
Fill the tab per spec §3 from **internal, grep-able facts** — `docs/architecture.md`, `docs/infrastructure.md`, package manifests, lockfiles, CI config. One row per category that applies (`Frontend` · `Backend` · `Auth` · `Data Store` · `Cache / Session Store` · `Object Storage` · `Events / Webhooks` · `Tools / Integrations` · `LLM / Reasoning` · `Observability` · `Infrastructure`), one plain-English line each with versions where the manifest states them. **Never leave the tab blank and never guess a version** — an unknown is "not determined from the repo", not an invented number.
|
|
99
97
|
|
|
100
|
-
## Step
|
|
98
|
+
## Step 6: Write to the Google Sheet + audit (MECHANICAL · show result)
|
|
101
99
|
|
|
102
|
-
**
|
|
100
|
+
**Write the plan to `.gsd-t/estimate-plan.json`, then run:**
|
|
103
101
|
|
|
104
|
-
|
|
105
|
-
-
|
|
106
|
-
|
|
107
|
-
- **Key file:** `~/.claude/gsd-t-secrets/gsd-t-sheets-writer-key.json` (chmod 600, outside any repo — never commit an SA key)
|
|
102
|
+
```bash
|
|
103
|
+
gsd-t estimate-sheet write --sheet <url> --plan .gsd-t/estimate-plan.json # add --replace only if the T-Shirt tab already has rows you mean to overwrite
|
|
104
|
+
```
|
|
108
105
|
|
|
109
|
-
|
|
110
|
-
```bash
|
|
111
|
-
PROJECT=ai-estimator-415612
|
|
112
|
-
SA=gsd-t-sheets-writer@$PROJECT.iam.gserviceaccount.com
|
|
113
|
-
KEY=~/.claude/gsd-t-secrets/gsd-t-sheets-writer-key.json
|
|
114
|
-
gcloud services enable sheets.googleapis.com --project=$PROJECT
|
|
115
|
-
gcloud iam service-accounts describe "$SA" --project=$PROJECT >/dev/null 2>&1 || \
|
|
116
|
-
gcloud iam service-accounts create gsd-t-sheets-writer \
|
|
117
|
-
--display-name="GSD-T Estimate Sheets Writer (permanent, reusable)" --project=$PROJECT
|
|
118
|
-
# SA creation is eventually-consistent — poll describe before minting the key
|
|
119
|
-
[ -f "$KEY" ] || { mkdir -p ~/.claude/gsd-t-secrets && chmod 700 ~/.claude/gsd-t-secrets && \
|
|
120
|
-
gcloud iam service-accounts keys create "$KEY" --iam-account="$SA" --project=$PROJECT && chmod 600 "$KEY"; }
|
|
121
|
-
```
|
|
122
|
-
2. **Share check:** the SA has no access until the sheet is shared with it. If a read-probe (below) returns `403`, **prompt the operator to share the sheet with `gsd-t-sheets-writer@ai-estimator-415612.iam.gserviceaccount.com` as Editor** (uncheck "Notify people"), wait for confirmation, re-probe. Because the SA is permanent, this is a **one-time** share per sheet — no re-share churn.
|
|
123
|
-
3. **Auth = self-signed JWT** (pure stdlib + openssl, no client libraries): read the key file, sign an RS256 JWT (`openssl dgst -sha256 -sign`), scope `https://www.googleapis.com/auth/spreadsheets`, exchange at `oauth2.googleapis.com/token` (grant `urn:ietf:params:oauth:grant-type:jwt-bearer`) for a Bearer token. JWT `exp = now + 3600`; **mint fresh each run** (1h expiry).
|
|
124
|
-
4. **Write via Sheets v4 REST** with the Bearer token: `values/<range>/PUT?valueInputOption=USER_ENTERED` for cell values; `:batchUpdate` for inserts/formatting/merges. **Reads:** `GET spreadsheets/<id>?ranges=...&includeGridData=true` (used for the 403 share-probe too).
|
|
125
|
-
5. **Gotcha fixes (all proven on HILO):**
|
|
126
|
-
- **403 quota-project** on the Sheets API → add header `X-Goog-User-Project: ai-estimator-415612`.
|
|
127
|
-
- **URL-encode every range** (`urllib.parse.quote`) — spaces in tab names (e.g. `'T-Shirt Size Estimate'!A19`) break the URL.
|
|
128
|
-
- **Hardcoded SUMIF/total ranges don't auto-expand** on a plain values-write → use `insertDimension` (which shifts ranges) when inserting rows (ties back to Step 3's WIDEN note).
|
|
129
|
-
- **`drive.file` scope 404s on a pre-existing sheet** → must use the full `spreadsheets` scope.
|
|
130
|
-
6. **No cleanup / no delete.** The SA is PERMANENT and reused — never delete it, never delete the key. (Deleting + recreating an SA changes its internal id and silently breaks every existing sheet share even with an identical email → 403. Keeping it permanent is the whole point.)
|
|
106
|
+
It writes the T-Shirt tab (items or sizes mode), the Team Mix, the Technology Stack, re-points every rollup, propagates the Phase dropdown, applies the styling — and then runs the spec §5 audit by reading back, printing every check with ✓/✗. **Exit 4 = a ✗ — fix the plan (or the sheet, for a template problem it names) and re-run. Exit 64 = auth/API/input halt.** Show the tool's output to the operator verbatim. Do not hand-patch cells around the tool; if the tool cannot express something the sheet needs, that is a tool change, and you say so.
|
|
131
107
|
|
|
132
|
-
|
|
108
|
+
**Auth** (used by the tool) = the PERMANENT reusable service account (never create a throwaway, never delete or recreate it — recreation breaks every existing share): email `gsd-t-sheets-writer@ai-estimator-415612.iam.gserviceaccount.com`, project `ai-estimator-415612`, key `~/.claude/gsd-t-secrets/gsd-t-sheets-writer-key.json` (chmod 600, outside any repo). gcloud's `spreadsheets` OAuth scope is Google-blocked, so: read the key, sign an RS256 JWT (`openssl dgst -sha256 -sign`), scope `https://www.googleapis.com/auth/spreadsheets`, exchange at `oauth2.googleapis.com/token` (grant `urn:ietf:params:oauth:grant-type:jwt-bearer`), `exp = now + 3600`, mint fresh each run. If the key file is missing, provision ONCE:
|
|
133
109
|
|
|
134
|
-
|
|
110
|
+
```bash
|
|
111
|
+
PROJECT=ai-estimator-415612
|
|
112
|
+
SA=gsd-t-sheets-writer@$PROJECT.iam.gserviceaccount.com
|
|
113
|
+
KEY=~/.claude/gsd-t-secrets/gsd-t-sheets-writer-key.json
|
|
114
|
+
gcloud services enable sheets.googleapis.com --project=$PROJECT
|
|
115
|
+
gcloud iam service-accounts describe "$SA" --project=$PROJECT >/dev/null 2>&1 || \
|
|
116
|
+
gcloud iam service-accounts create gsd-t-sheets-writer \
|
|
117
|
+
--display-name="GSD-T Estimate Sheets Writer (permanent, reusable)" --project=$PROJECT
|
|
118
|
+
# SA creation is eventually-consistent — poll describe before minting the key
|
|
119
|
+
[ -f "$KEY" ] || { mkdir -p ~/.claude/gsd-t-secrets && chmod 700 ~/.claude/gsd-t-secrets && \
|
|
120
|
+
gcloud iam service-accounts keys create "$KEY" --iam-account="$SA" --project=$PROJECT && chmod 600 "$KEY"; }
|
|
121
|
+
```
|
|
135
122
|
|
|
136
|
-
|
|
137
|
-
- **§3.0 requirement↔finding crosswalk** — per-domain tables (Requirement · Finding · Fix). `FR-xN` (domain-sequenced requirement id) and `TD-n` (permanent scan finding id) do NOT run in parallel — always crosswalk them. (For a pure requirements input with no scan, the "Finding" column becomes the source requirement id.)
|
|
138
|
-
- **§3.1 FR tables** — a **dedicated Finding/Source column** (never bury the id in trailing prose).
|
|
139
|
-
- **§3.2 NFR** — an **"Applies to" column listing EVERY id** each cross-cutting NFR touches.
|
|
140
|
-
- **§4 enforcement, §8 API, §10 estimate** — explicit id refs (not bare numbers).
|
|
141
|
-
- **§10 total MUST equal the live sheet rollup** — verify against the sheet's rollup cell, not memory. Watch that Project Setup carries its MF (M/M = 2 raw → 3.4 total, not 2.0). Point-in-time sync is fine; note it.
|
|
142
|
-
- **§15 sign-off = "Approved to proceed (scope, not fixed cost)".**
|
|
143
|
-
- Group tables **by domain with a bold header per group** (no repeating "Domain" column — reads as broken).
|
|
144
|
-
- **Save to `share/<Repo-Name>-PRD-*.md`** (repo-name prefix, matching `/gsd-t-scan`'s `share/` convention).
|
|
145
|
-
- **PAUSE:** present the PRD (or its outline + disclaimer + §10 total) for review before finalizing.
|
|
123
|
+
**What the tool does** (spec §0, all learned the hard way — listed so you can recognise a template problem when it halts): no `X-Goog-User-Project` header; every range URL-encoded; Phase cells `copyPaste`d from the sheet's existing dropdown cell (it halts if the template has none — add one to E14); clear-then-paint from the current shape; small batches that halt on the first failure; Team Mix header on row 2 only with `Mon 1..N` + `Total Hrs` derived from the month count; sage on exactly Days / Hrs / Total Hrs; Arial 10; bands across every month column; then the read-back audit. **Any ✗ is fixed before Step 7** — a 200 on the write is not evidence the cell landed.
|
|
146
124
|
|
|
147
|
-
## Step 7: Verify — reconcile
|
|
125
|
+
## Step 7: Verify — reconcile (MECHANICAL · show result)
|
|
148
126
|
|
|
149
|
-
|
|
127
|
+
- `gsd-t estimate-sheet audit --sheet <url>` must exit 0 (it recomputes **T-Shirt `Total Days` == Team Mix `Σ Days`** independently — raw sizes × (1+MF) vs Σ Count × Mths × 20 — and checks every §5 line). A ✗ here after a clean write means someone edited the sheet; find the break before the Red Team.
|
|
128
|
+
- **Overview `C2/E2/C3/E3` resolve to numbers** (they reference the T-Shirt rollups `L8/K8/N8/M8`; the estimates index imports exactly these cells).
|
|
129
|
+
- If the estimate is linked from the estimates index and shows `#REF!`, that is the one-time `IMPORTRANGE` "Allow access" click — report it for the operator; it is not yours to fix.
|
|
150
130
|
|
|
151
131
|
## Step 8: Estimate Red Team (adversarial) — JUDGMENT · PAUSE · YOU ARE THE ARBITER
|
|
152
132
|
|
|
153
|
-
An independent adversarial pass that challenges the estimate before it reaches the client
|
|
133
|
+
An independent adversarial pass that challenges the estimate before it reaches the client. **Its job is to protect Tekyz from a money-losing under-estimate AND to keep the estimate competitive** (paired realism, per `feedback_red_team_realism_gate` — don't pad every item to XXL).
|
|
154
134
|
|
|
155
135
|
**What it attacks:**
|
|
156
136
|
- **Under-sized items** — "this 'S' implies a DB migration + backfill → really M; +2 days."
|
|
157
|
-
- **Missing line-items** — work a requirement implies but nothing sized (migrations, tests, auth, error states, rollout).
|
|
158
|
-
- **
|
|
159
|
-
- **
|
|
160
|
-
- **
|
|
161
|
-
- **
|
|
137
|
+
- **Missing line-items** — work a requirement implies but nothing sized (migrations, tests, auth, error states, rollout, sandbox issuance, decision cycles with the client, gate-acceptance evidence).
|
|
138
|
+
- **Counts that were guessed** — "510 call sites" that measure at 897; re-measure the big ones.
|
|
139
|
+
- **Optimistic multipliers** — Buffer/QA too low for the stated confidence; high factor too tight for the unknowns.
|
|
140
|
+
- **Adjustment gaps** — an R&D/unknown item sized as if routine; familiarization not applied.
|
|
141
|
+
- **Team Mix realism** — a role missing for a weighted MF factor, a flat ramp, a smeared roster.
|
|
142
|
+
- **Cross-check integrity** — do the two totals ACTUALLY reconcile, or is a hardcoded cell hiding a break.
|
|
143
|
+
- **Assumption / scope gaps** — unstated assumptions that would blow up mid-project (record them on the Overview as assumptions, not padding).
|
|
162
144
|
|
|
163
|
-
**Verdict:** `FAIL` (material under-estimate or missing scope
|
|
145
|
+
**Verdict:** `FAIL` (material under-estimate or missing scope) / `GRUDGING-PASS` (exhaustive search, nothing material).
|
|
164
146
|
|
|
165
|
-
### The arbitration protocol (
|
|
147
|
+
### The arbitration protocol (the operator is the final judge — NOT bot ping-pong)
|
|
166
148
|
|
|
167
|
-
When the Red Team returns `FAIL`, it does **NOT** loop
|
|
149
|
+
When the Red Team returns `FAIL`, it does **NOT** loop with the skill until it grudgingly passes. It surfaces to **the operator**:
|
|
168
150
|
|
|
169
|
-
1. **Present each objection PLAINLY:** *what* shouldn't pass, *why*, and *the estimate impact* (
|
|
170
|
-
2. **The operator decides, per objection:**
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
3. **Definitive-decision override:** if the operator says anything conclusive — e.g. *"No more argument. I've decided on X,"* or any clearly final ruling — the Red Team **MUST grudgingly accept the operator's decision immediately, regardless of how many rounds have passed.** It **MAY document its unresolved objection** (in the PRD as a footnote or a `share/<Repo>-estimate-redteam-notes.md` file) **for later consideration** — but it does not re-litigate.
|
|
174
|
-
4. The Red Team **never self-satisfies into a pass** and **never overrides the operator.** It either persuades the operator or defers to them.
|
|
151
|
+
1. **Present each objection PLAINLY:** *what* shouldn't pass, *why*, and *the estimate impact* (item, before→after size, dollar delta). One list, ranked by dollar impact.
|
|
152
|
+
2. **The operator decides, per objection:** **Agree** → `continue` → edit the plan and re-run Steps 4, 6, 7 (a resize changes the roster and the month count; the tool recomputes both). **Disagree** → operator gives feedback → **the Red Team argues back** until one side concedes or the operator ends it.
|
|
153
|
+
3. **Definitive-decision override:** anything conclusive from the operator ("No more argument. I've decided on X") is accepted immediately, regardless of round count. The Red Team **MAY document its unresolved objection** in `share/<Repo>-estimate-redteam-notes.md` — it does not re-litigate.
|
|
154
|
+
4. The Red Team **never self-satisfies into a pass** and **never overrides the operator.**
|
|
175
155
|
|
|
176
156
|
**PAUSE** at every objection — this phase is inherently interactive.
|
|
177
157
|
|
|
178
158
|
## Step 9: Deliver
|
|
179
159
|
|
|
180
|
-
|
|
160
|
+
Report: input type + scope + item count; the active config values (rate / MF list / high factor); Total Days and the LOW–HIGH dollar range; the sheet URL; the roster (people × Count, months); the audit checklist result; the Red Team verdict and any documented-but-overridden objections; any `#REF!` awaiting the operator's Allow-access click.
|
|
181
161
|
|
|
182
162
|
## Document Ripple
|
|
183
163
|
|
|
184
|
-
-
|
|
164
|
+
- The Google Sheet (external) — T-Shirt Size Estimate, Team Mix, Technology Stack (+ Overview cells verified) + optional `share/<Repo>-estimate-redteam-notes.md`.
|
|
185
165
|
- If renumbering (Step 1) ran: the input + plain-English + `scan/*.md` + `docs/*` + README + `share/*` were remapped (archives untouched) — note it in the report so the numbering change is traceable.
|
|
166
|
+
- No PRD. A client PRD is `/gsd-t-prd`.
|
|
186
167
|
|
|
187
168
|
## ▶ Next Up
|
|
188
169
|
|
|
189
|
-
Standalone command — no auto-successor. After delivering, the user shares the sheet
|
|
170
|
+
Standalone command — no auto-successor. After delivering, the user shares the sheet with the client (and runs `/gsd-t-prd` if a PRD is wanted).
|
package/commands/gsd-t-help.md
CHANGED
|
@@ -378,10 +378,10 @@ Use these when user asks for help on a specific command:
|
|
|
378
378
|
- **Use when**: Ready to address technical debt items
|
|
379
379
|
|
|
380
380
|
### estimate
|
|
381
|
-
- **Summary**: Turn any structured work document — a scan register, a new-feature or new-app requirements doc
|
|
381
|
+
- **Summary**: Turn any structured work document — a scan register, a gap-analysis sheet, a new-feature or new-app requirements doc — into a Tekyz client estimate Google Sheet: **T-Shirt Size + Team Mix + Technology Stack**, written and audited against `~/.claude/templates/estimate-sheet-spec.md`. No PRD (`/gsd-t-prd` owns that)
|
|
382
382
|
- **Auto-invoked**: No
|
|
383
|
-
- **Updates**: the Tekyz estimate Google Sheet + `share/<Repo>-
|
|
384
|
-
- **Use when**: You need a client-facing paid estimate
|
|
383
|
+
- **Updates**: the Tekyz estimate Google Sheet (three tabs, written and read-back-audited by `gsd-t estimate-sheet` from `.gsd-t/estimate-plan.json`) + optional `share/<Repo>-estimate-redteam-notes.md` (and, if renumbered, the source doc/docs/scan files)
|
|
384
|
+
- **Use when**: You need a client-facing paid estimate (T-shirt sizing, dollar range, staffed team by month) from a scan, a gap analysis, or a requirements/feature/app spec. **SUPERVISED** — judgment phases (sizing, adjustments, Team Mix, Red Team) pause for your review; **you are the final arbiter** of an Estimate Red Team that challenges the numbers. Accepts `--sheet <url>`. Rate + factors are parameterized (default Tekyz; the sheet's own MF list wins). Playbook: `~/.claude/playbooks/tekyz-estimation-and-prd-playbook.md`
|
|
385
385
|
|
|
386
386
|
### stories
|
|
387
387
|
- **Summary**: Generate a dev-team handoff document in the Tekyz user-stories format — discrete user stories with workflows, grouped acceptance criteria, per-story flow diagrams (Mermaid rendered to embedded images), and mapped test-case tables — from any source (scan register, requirements doc, design contract, or a reverse-engineered codebase)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tekyzinc/gsd-t",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.20.11",
|
|
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",
|
|
@@ -617,7 +617,7 @@ Add `**Also available:**` with `- /gsd-t-{alt} — {desc}` lines if alternatives
|
|
|
617
617
|
| `integrate` | `verify` | |
|
|
618
618
|
| `verify` | *(auto-invokes complete-milestone)* | |
|
|
619
619
|
| `complete-milestone` | `status` | |
|
|
620
|
-
| `scan` | `promote-debt` | `milestone`, `estimate` (client estimate
|
|
620
|
+
| `scan` | `promote-debt` | `milestone`, `estimate` (client estimate sheet) |
|
|
621
621
|
| `init` | `scan` | `milestone` |
|
|
622
622
|
| `init-scan-setup` | `milestone` | |
|
|
623
623
|
| `gap-analysis` | `milestone` | `feature` |
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"_totalMF": "Overhead multiplier applied to raw Days. Tekyz default 0.7 = QA 0.3 + PM 0.1 + Analysis 0.05 + Deployment 0.05 + Buffer 0.2. Raise Buffer/QA when confidence is low.",
|
|
15
15
|
|
|
16
16
|
"mfBreakdown": { "qa": 0.3, "pm": 0.1, "analysis": 0.05, "deployment": 0.05, "buffer": 0.2 },
|
|
17
|
-
"_mfBreakdown": "Optional itemized breakdown of totalMF (must sum to totalMF). Tune per project; e.g. raise buffer for low-confidence scope.",
|
|
17
|
+
"_mfBreakdown": "Optional itemized breakdown of totalMF (must sum to totalMF). Tune per project; e.g. raise buffer for low-confidence scope. When a target sheet exists its own MF list (T-Shirt tab E4:F9) is the source of truth and is READ, never overwritten — Hilo sheets run 0.9 (qa .3, pm .1, analysis .1, deployment .05, standups .15, buffer .2). Every non-zero factor must have a person in Team Mix (see estimate-sheet-spec.md section 2.4).",
|
|
18
18
|
|
|
19
19
|
"highFactor": 1.25,
|
|
20
20
|
"_highFactor": "HIGH dollar figure = LOW x this. Raise above 1.25 when unknowns dominate (many R&D / spike items).",
|
|
@@ -35,5 +35,8 @@
|
|
|
35
35
|
"_serviceAccountKeyPath": "Local path to the SA JSON key (chmod 600, outside any repo — NEVER commit). Step 5 self-provisions the SA+key here if missing.",
|
|
36
36
|
|
|
37
37
|
"newTeamDefault": true,
|
|
38
|
-
"_newTeamDefault": "Whether to assume a new-team familiarization adjustment (Step 2.5a) by default. Usually true for a fresh client."
|
|
38
|
+
"_newTeamDefault": "Whether to assume a new-team familiarization adjustment (Step 2.5a) by default. Usually true for a fresh client.",
|
|
39
|
+
|
|
40
|
+
"sheetSpec": "~/.claude/templates/estimate-sheet-spec.md",
|
|
41
|
+
"_sheetSpec": "The layout/formula/styling/roster spec every write is audited against. Bundled at templates/estimate-sheet-spec.md in the GSD-T package."
|
|
39
42
|
}
|