great-cto 3.74.0 → 3.75.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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "great-cto",
3
3
  "description": "You already have the agent. This is everything around it. great_cto runs Claude Code as a pipeline of 72 specialist agents \u2014 an independent model checks each stage before the next builds on it, spending caps refuse rather than warn, and three decisions stay yours: what gets built, how, and whether it ships.",
4
- "version": "3.74.0",
4
+ "version": "3.75.0",
5
5
  "author": {
6
6
  "name": "Alexander Velikiy",
7
7
  "url": "https://hashnode.com/@Greatcto"
@@ -92,8 +92,9 @@ snapshots, binaries) are excluded, because their size is not review effort.
92
92
  3. **Performance** — needless O(n²), N+1 queries, unbounded growth, sync work on a
93
93
  hot path, missing pagination/limits. Only when it matters at realistic scale.
94
94
  4. **Readability / maintainability** — naming, dead code, duplicated logic,
95
- missing tests for new behaviour, comments that lie, an abstraction that hides a
96
- bug. Match the surrounding code's idiom.
95
+ missing tests for new behaviour, a test an empty body would satisfy (it still
96
+ passes if the function under test does nothing, so it asserts nothing), comments
97
+ that lie, an abstraction that hides a bug. Match the surrounding code's idiom.
97
98
 
98
99
  ## Calibration — apply `shared/agent-fragments/argument-quality.md`
99
100
 
@@ -227,7 +227,9 @@ Runs all of Phase 4 (sections labeled in stdout):
227
227
  - **4A.0** intersects the top-20 largest source files with the top-20 most-git-churned files
228
228
  (last 6 months), writing scratch files to `/tmp/audit-{largest,churn,hotspots}.txt`. Every
229
229
  file in the intersection MUST receive concrete file:line citations in the findings table —
230
- these are the most expensive places to leave debt unaddressed.
230
+ these are the most expensive places to leave debt unaddressed. A hotspot with no test
231
+ beside it gets "characterize before change" in its Recommendation: the first edit there
232
+ should be a test pinning its current behaviour.
231
233
  - **4A** code structure signals — god files (>500 lines), circular-import risk count,
232
234
  dead-code marker count (TODO/FIXME/HACK/XXX/DEPRECATED), duplicated-basename files.
233
235
  - **4B** infrastructure & ops debt — Docker base image lines, k8s/Helm apiVersion usage,
@@ -611,6 +611,11 @@ asserts nothing. Mutation testing closes that — it introduces small faults
611
611
  (flip a comparison, drop a call, change a boundary) and reports how many the
612
612
  suite **catches**. A surviving mutant is a fault your tests would have shipped.
613
613
 
614
+ Small tasks skip the run, not the question: the cheap form is the empty-implementation
615
+ check — stub the function under test to do nothing; a test that still passes asserts
616
+ nothing. senior-dev runs it at RED and code-reviewer flags it; if you see such a test
617
+ in a small task, report it.
618
+
614
619
  Run it on the **changed files only** — a full-repo mutation run is minutes-to-hours
615
620
  and mostly re-verifies untouched code:
616
621
 
@@ -73,7 +73,8 @@ that get pushed back on, because those are the ones nobody else will catch.
73
73
  projects measured on 2026-09-21, 1,181 of 5,126 operator messages were "делай" /
74
74
  "да" answering exactly that question.
75
75
  - the next step of a plan that already passed `gate:plan`;
76
- - re-running a check after a fix, until it is green or the failure is understood.
76
+ - re-running a check after a fix, until it is green or the failure is understood (two failed
77
+ fixes on one assumption end that loop — see "Two fixes, one premise", step 5).
77
78
 
78
79
  This list does not replace **Ask before proceeding** above: a lint rule to disable, a
79
80
  pattern to copy, an "unrelated" failing test, a field added to an API, an empty
@@ -475,6 +476,11 @@ Schema: `skills/great_cto/references/knowledge-extraction.md`
475
476
  - If `data-platform` archetype → dbt tests + data contract validation / snapshot regression
476
477
  - If `ai-system` archetype → evals-first (write eval suite before any prompt/model changes)
477
478
  - All other archetypes → standard TDD (follow `superpowers:test-driven-development`):
479
+ - **Characterize first** — if the code you must change has no test covering it, write
480
+ a test that pins what it does TODAY (a golden/snapshot of current output is enough; it
481
+ records behaviour, not a verdict on it) and see it **pass on the unchanged code**. This
482
+ is the one test meant to pass before the change. Then change under RED/GREEN; when the
483
+ change alters the pinned output, update the pin deliberately and say so.
478
484
  - **RED**: write failing test, then **explicitly verify it fails**:
479
485
  ```bash
480
486
  npm test -- --testPathPattern="<new-test>" 2>&1 | grep -E "FAIL|PASS|Error" | head -5
@@ -488,9 +494,23 @@ Schema: `skills/great_cto/references/knowledge-extraction.md`
488
494
  PYTHONUNBUFFERED=1 pytest ... > /tmp/test-out.log 2>&1 &
489
495
  sleep 2; tail -f /tmp/test-out.log # then Ctrl-C when done
490
496
  ```
491
- If test PASSES before implementation → the test is wrong. Fix it first.
497
+ If test PASSES before implementation → the test is wrong. Fix it first. (The one
498
+ exception is the characterization pin above, which must pass on unchanged code.)
499
+ - **Stub check — before GREEN, even when RED is already confirmed.** A RED that failed
500
+ because the function does not exist ("not defined", an import error) says nothing about
501
+ the assertions. So create the stub (empty body: returns nothing, does nothing) and run
502
+ the new tests against it, then say in your reply which of them still pass. "Not
503
+ called", "does not throw" and "is defined" assertions all pass against it; a suite made
504
+ of them asserts nothing, so add the test for the positive effect (the call made, the
505
+ value returned) until the stub fails on an assertion. Mutation testing is skipped for
506
+ small tasks; this check is not.
492
507
  - **GREEN**: write minimal code to make test pass → re-run → confirm PASS
493
508
  - **REFACTOR**: clean up → confirm still PASS, no coverage regression
509
+ - **Two fixes, one premise → stop.** When two fixes resting on the same assumption have
510
+ failed the same check, write that assumption in one sentence and make no third edit on
511
+ it. Test the assumption itself first (print the value, query the real dependency, run
512
+ the one-line repro); if it is false, redesign from what you found, and if you cannot
513
+ test it, escalate. A third try on the same idea is a coin toss, not a fix.
494
514
  6. **Quality check**: all tests pass, no lint errors, coverage ≥80%, no hardcoded secrets
495
515
  6b. **Scope check against the IMPL-BRIEF** (governance Phase 3 — before staging):
496
516
  ```bash
@@ -34,7 +34,17 @@ import { fileURLToPath } from 'node:url';
34
34
 
35
35
  const sha = (s) => createHash('sha256').update(String(s)).digest('hex');
36
36
 
37
+ // Hooks read evidence under host deadlines of 5-15 s and must give up in time to
38
+ // fail closed themselves, so 5 s is the default. A long-lived caller on a loaded
39
+ // machine (the packaged controller probe) widens it with
40
+ // GREAT_CTO_GIT_READ_TIMEOUT_MS; it never narrows below 5 s nor passes 120 s.
41
+ export const GIT_READ_TIMEOUT_MS = 5000;
42
+ export function gitReadTimeoutMs(raw = process.env.GREAT_CTO_GIT_READ_TIMEOUT_MS) {
43
+ return /^\d{1,9}$/.test(raw ?? '') ? Math.min(Math.max(Number(raw), GIT_READ_TIMEOUT_MS), 120000) : GIT_READ_TIMEOUT_MS;
44
+ }
45
+
37
46
  function git(args, cwd, { maxBuffer = 32 * 1024 * 1024 } = {}) {
47
+ const timeout = gitReadTimeoutMs();
38
48
  try {
39
49
  // Reading evidence must not execute project-configured diff/filter/monitor helpers.
40
50
  const command = args[0] === 'diff' ? ['diff', '--no-ext-diff', '--no-textconv', ...args.slice(1)] : args;
@@ -45,14 +55,14 @@ function git(args, cwd, { maxBuffer = 32 * 1024 * 1024 } = {}) {
45
55
  let keys = '';
46
56
  try {
47
57
  keys = execFileSync('git', [...config, 'config', '--null', '--name-only', '--get-regexp', '^filter\\..*\\.(clean|process|required)$'],
48
- { cwd, encoding: 'utf8', maxBuffer: 65536, timeout: 5000, stdio: ['ignore', 'pipe', 'ignore'] });
58
+ { cwd, encoding: 'utf8', maxBuffer: 65536, timeout, stdio: ['ignore', 'pipe', 'ignore'] });
49
59
  } catch (error) { if (error.status !== 1) return null; }
50
60
  const filters = [...new Set(keys.split('\0').filter(Boolean).map(key => key.match(/^filter\.([\s\S]+)\.(?:clean|process|required)$/)?.[1]))];
51
61
  if (filters.length > 128 || filters.some(name => !name)) return null;
52
62
  for (const name of filters) config.push('-c', `filter.${name}.clean=`, '-c', `filter.${name}.process=`, '-c', `filter.${name}.required=false`);
53
63
  }
54
64
  return execFileSync('git', [...config, ...command],
55
- { cwd, encoding: 'utf8', maxBuffer, timeout: 5000, stdio: ['ignore', 'pipe', 'ignore'] });
65
+ { cwd, encoding: 'utf8', maxBuffer, timeout, stdio: ['ignore', 'pipe', 'ignore'] });
56
66
  } catch { return null; }
57
67
  }
58
68
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "great-cto",
3
- "version": "3.74.0",
3
+ "version": "3.75.0",
4
4
  "description": "One command install for the great_cto Claude Code plugin. Auto-detects your stack, picks the right archetype, bootstraps PROJECT.md.",
5
5
  "keywords": [
6
6
  "claude-code",