great-cto 3.6.0 → 3.7.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.
@@ -2,7 +2,7 @@
2
2
  "name": "great_cto",
3
3
  "id": "great_cto",
4
4
  "description": "Engineering process for solo founders and teams up to 50 engineers. Agents do architecture, code review, QA, and security. You make two decisions per feature.",
5
- "version": "3.6.0",
5
+ "version": "3.7.0",
6
6
  "author": {
7
7
  "name": "Great CTO",
8
8
  "url": "https://github.com/avelikiy/great_cto"
@@ -141,16 +141,42 @@ function readVerdicts(cwd = null, health = null) {
141
141
  if (!fs.existsSync(histPath)) continue;
142
142
  const lines = fs.readFileSync(histPath, 'utf8').split('\n').filter(Boolean);
143
143
  for (const line of lines) {
144
- const m = line.match(/^(\S+)\s+(\S+)\s+(\d+\.?\d*)/);
144
+ // Anchored on a real ISO timestamp rather than "the first run of
145
+ // non-space characters". The writer used to emit an entire compact-JSON
146
+ // verdict in that position, and `\S+` accepted it — producing keys like
147
+ // `{"v":1,"ts":"202|qa-engineer` that could never match a verdict.
148
+ // Lines from that era are skipped here instead of being half-parsed.
149
+ const m = line.match(/^(\d{4}-\d{2}-\d{2}T\S+)\s+(\S+)\s+(\d+\.?\d*)(?:\s|$)/);
145
150
  if (!m) continue;
151
+ const usd = parseFloat(m[3]);
152
+ // A recorded zero is `log-verdict.sh` writing through whatever the agent
153
+ // reported, which is nothing. Enriching a zero verdict with a zero from
154
+ // this file changes no number and would label it `measured` — a claim
155
+ // that something was measured when the file says only that a line exists.
156
+ if (!(usd > 0)) continue;
146
157
  const key = `${m[1].slice(0, 16)}|${m[2]}`; // minute + agent
147
- if (!costByKey.has(key)) costByKey.set(key, parseFloat(m[3])); // project wins
158
+ if (!costByKey.has(key)) costByKey.set(key, usd); // project wins
148
159
  }
149
160
  }
150
161
  for (const v of results) {
151
- if (v.cost_usd != null) continue;
162
+ // A self-reported ZERO is not a measurement — it is the absence of one,
163
+ // and it must not shadow a figure that was actually measured.
164
+ //
165
+ // This read `if (v.cost_usd != null) continue`, and every verdict carries
166
+ // `cost_usd: 0` because agents do not measure their own spend. Zero is not
167
+ // null, so enrichment was skipped for all 26 verdicts in the window while
168
+ // the measured costs sat in cost-history.log unused — and the budgets
169
+ // screen reported `unmeasured`, which was true of what it read and false
170
+ // of what existed.
171
+ //
172
+ // A measured value overrides a zero; nothing overrides a non-zero figure
173
+ // an agent actually reported.
174
+ if (v.cost_usd != null && v.cost_usd > 0) continue;
152
175
  const key = `${(v.ts || '').slice(0, 16)}|${v.agent}`;
153
- if (costByKey.has(key)) v.cost_usd = costByKey.get(key);
176
+ if (costByKey.has(key)) {
177
+ v.cost_usd = costByKey.get(key);
178
+ v.cost_source = 'measured'; // read from a transcript, not self-reported
179
+ }
154
180
  }
155
181
  }
156
182
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "great-cto",
3
- "version": "3.6.0",
3
+ "version": "3.7.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",