feat(manual-qa): metrics-collection hooks + tokenomics export/HTML report - #48
Merged
Conversation
…port Optional add-on to the manual-qa bundle: collects token/cost/timing/ pass-rate metrics on every test-run-lead-driven session (purely observational — doesn't touch any agent or skill), plus two manual, on-demand scripts that reshape those metrics into the EPAM cross-factory factories-tokenomics-dataset schema and, optionally, a self-contained HTML report from it. - hooks/ — 5 Claude Code hook events (SessionStart, PreToolUse, PostToolUse, SubagentStop, SessionEnd) + 10 scripts. Ephemeral state files are session_id-scoped so concurrent test-run-lead sessions in one project don't clobber each other's metrics; orphaned files older than 7 days are swept on the next fresh session. - build-tokenomics-report.mjs / build-tokenomics-html.mjs — verified end-to-end against a real run (elitea-testing RUN-2026-07-22-005) before landing here; hooks/templates/ carries the one-time per-project setup (factory-profile.json + two READMEs) these two scripts need, since the bundle installer only copies hooks/scripts/. - test-run-lead — normalizes each test case's id before dispatch (source of truth: the TC file's own name), so tokens/cost stay attributable per TC even when a case's frontmatter id and filename briefly disagree. - tasks/baseline-web/ — 8 baseline TCs this add-on's own benchmarking was developed and verified against. - knowledge/metrics-format.md and knowledge/test-run-report-format.md document every field the current scripts actually read/produce (turns, subagent_dispatches, orchestrator_cost_pct, tokens_by_model, tokens_by_agent, and the optional tokenomics-export frontmatter keys), with a real, internally-consistent sample run throughout. Squashed from the original feat/manual-qa-challenges branch (10 iterative commits plus today's fixes) onto current main — that branch's history included an entire first implementation of this same feature (top-level hooks/scripts/build-run-metrics.mjs etc., plus a stray pre-run-ccusage hunk in the shared hooks/session-start) that got superseded by the bundle-based design two commits later but was never actually deleted; this squash omits it rather than asking reviewers to read past dead code marked "deprecated" inline. A straight `git rebase origin/main` was tried first and hit a real conflict on the very first of 12 commits (.gitignore) — not worth 11 more rounds of that for history nobody needs to re-read.
bermudas
added a commit
to bermudas/sdlc-skills
that referenced
this pull request
Jul 30, 2026
…ows, and the audit/retro toolchain Squashed from 41 commits onto current main. The history is omitted rather than replayed because a third of it builds a state board — 11 files under scripts/board/ — that a later commit deletes: a commit-by-commit reviewer would read an entire implementation that no longer exists, then read its removal. The net diff is the change. (Same reasoning as arozumenko#48.) WHY NO BOARD. The board recorded progress, and progress only needs recording if something reads it mid-run. Nothing did: the runtime already persists every agent's return to journal.jsonl, and resume replays from cache. What the board added was cost — every transition a clerk dispatch — and a second version of the truth that drifted: on one campaign 4 of 12 merged cases still sat at `approved-static`. Replaced by OUTCOMES: a case ends somewhere, it does not travel a state machine, and `findings[]` is orthogonal so a green case can still report a defect it found. Batch pipeline - One workflow per batch: analysts in K lanes → builds sequenced in the one working tree → parallel static review → integrate → hardening gate (N consecutive green) → one report at close. Campaign conductor on top: heads analysis → foundation (built, reviewed, mini-gated) → waves. - Two branch levels: case branches under a batch trunk, ONE PR to base — gating a trunk and then merging N case PRs proves one object and ships another. - The fix loop runs until the reviewer APPROVES. It stops only when every surviving blocker is `persists` or `external`; anything still `unaddressed` earns another round, because "forgotten" and "impossible" look identical in a finding list and demand opposite responses. Round caps are runaway backstops, not the working control. - Red-by-design is declared, not discovered: a ticketed product defect keeps its loud failure, the gate runs it without counting it, and the case reports `blocked` on the ticket rather than a green it never earned. - Contracts hold on every host. Where a script runs the loop on Claude Code, the orchestrator is the loop elsewhere; reviewer-contract.md and implementer-contract.md carry the same rules for hosts with no workflow tool. Recovery and bookkeeping - SubagentStop hook (bundle-scoped, workflow-only, async) records each agent's structured return under .agents/automation/_returns/. fold-returns.mjs reads them — including the agents that ended WITHOUT a structured result, which are exactly the dispatches a resume must re-run. Receipts are append-only facts; the fold is derived on demand and never persisted, or the board is back. - resume-report.mjs demoted from verdict to evidence: it now scopes the journal search to THIS project (it was taking the newest journal on the machine, from a different repository, and case ids collide), reads PR state (it fetched `state` and discarded it, so a CLOSED abandoned PR read as `built`), and says plainly what it cannot interpret. - Long jobs run in the FOREGROUND, every slot. An agent that ends its turn waiting on a background job is not waiting, it is done — measured: one such stall held a finished branch and a whole conductor for 12 minutes with no error anywhere. efficiency-audit / session-retrospective - Cost per case measured, not typed: --resolved-from reads the pipeline's own run reports, reports $/spec-delivered AND $/case-examined, folds re-entries, and refuses the ratio when nothing ties the spend to the cases. - GitHub Copilot support on both skills; self-contained HTML report + CSV. - Correction detection rewritten — the old regex was anchored to `^` and matched 1 of 160 user turns on a real session; now unanchored, ranked, labelled by kind, with interrupts counted. - Transcript discovery fixed: a repo-local .claude/projects is searched (a project can relocate its whole store there), and the project-dir encoding now maps every separator Claude Code maps — 6 of 28 real projects resolved before, 28 of 28 after. 291 tests, `npm run validate` clean.
bermudas
added a commit
to bermudas/sdlc-skills
that referenced
this pull request
Jul 30, 2026
…ows, and the audit/retro toolchain Squashed from 41 commits onto current main. The history is omitted rather than replayed because a third of it builds a state board — 11 files under scripts/board/ — that a later commit deletes: a commit-by-commit reviewer would read an entire implementation that no longer exists, then read its removal. The net diff is the change. (Same reasoning as arozumenko#48.) WHY NO BOARD. The board recorded progress, and progress only needs recording if something reads it mid-run. Nothing did: the runtime already persists every agent's return to journal.jsonl, and resume replays from cache. What the board added was cost — every transition a clerk dispatch — and a second version of the truth that drifted: on one campaign 4 of 12 merged cases still sat at `approved-static`. Replaced by OUTCOMES: a case ends somewhere, it does not travel a state machine, and `findings[]` is orthogonal so a green case can still report a defect it found. Batch pipeline - One workflow per batch: analysts in K lanes → builds sequenced in the one working tree → parallel static review → integrate → hardening gate (N consecutive green) → one report at close. Campaign conductor on top: heads analysis → foundation (built, reviewed, mini-gated) → waves. - Two branch levels: case branches under a batch trunk, ONE PR to base — gating a trunk and then merging N case PRs proves one object and ships another. - The fix loop runs until the reviewer APPROVES. It stops only when every surviving blocker is `persists` or `external`; anything still `unaddressed` earns another round, because "forgotten" and "impossible" look identical in a finding list and demand opposite responses. Round caps are runaway backstops, not the working control. - Red-by-design is declared, not discovered: a ticketed product defect keeps its loud failure, the gate runs it without counting it, and the case reports `blocked` on the ticket rather than a green it never earned. - Contracts hold on every host. Where a script runs the loop on Claude Code, the orchestrator is the loop elsewhere; reviewer-contract.md and implementer-contract.md carry the same rules for hosts with no workflow tool. Recovery and bookkeeping - SubagentStop hook (bundle-scoped, workflow-only, async) records each agent's structured return under .agents/automation/_returns/. fold-returns.mjs reads them — including the agents that ended WITHOUT a structured result, which are exactly the dispatches a resume must re-run. Receipts are append-only facts; the fold is derived on demand and never persisted, or the board is back. - resume-report.mjs demoted from verdict to evidence: it now scopes the journal search to THIS project (it was taking the newest journal on the machine, from a different repository, and case ids collide), reads PR state (it fetched `state` and discarded it, so a CLOSED abandoned PR read as `built`), and says plainly what it cannot interpret. - Long jobs run in the FOREGROUND, every slot. An agent that ends its turn waiting on a background job is not waiting, it is done — measured: one such stall held a finished branch and a whole conductor for 12 minutes with no error anywhere. efficiency-audit / session-retrospective - Cost per case measured, not typed: --resolved-from reads the pipeline's own run reports, reports $/spec-delivered AND $/case-examined, folds re-entries, and refuses the ratio when nothing ties the spend to the cases. - GitHub Copilot support on both skills; self-contained HTML report + CSV. - Correction detection rewritten — the old regex was anchored to `^` and matched 1 of 160 user turns on a real session; now unanchored, ranked, labelled by kind, with interrupts counted. - Transcript discovery fixed: a repo-local .claude/projects is searched (a project can relocate its whole store there), and the project-dir encoding now maps every separator Claude Code maps — 6 of 28 real projects resolved before, 28 of 28 after. Scope: bundles/test-automation/ plus the shared hooks/ (which serve every bundle by design). The feature-development bundle is deliberately untouched — its own session-retrospective copy still carries the old parser, and fixing it belongs in a branch scoped to that bundle. 285 tests, `npm run validate` clean.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Optional add-on to the
manual-qabundle: collects token/cost/timing/pass-ratemetrics on every
test-run-lead-driven session (purely observational — doesn'ttouch any agent or skill, doesn't change how the team runs), plus two manual,
on-demand scripts that reshape those metrics into the EPAM cross-factory
factories-tokenomics-datasetschema and, optionally, a self-contained HTMLreport from it.
hooks/— 5 Claude Code hook events (SessionStart,PreToolUse,PostToolUse,SubagentStop,SessionEnd) + 10 scripts. Ephemeral statefiles are
session_id-scoped so concurrenttest-run-leadsessions in oneproject don't clobber each other's metrics; orphaned files older than 7 days
are swept on the next fresh session.
build-tokenomics-report.mjs/build-tokenomics-html.mjs— verifiedend-to-end against a real run (
elitea-testingRUN-2026-07-22-005) beforelanding here.
hooks/templates/carries the one-time per-project setup(
factory-profile.json+ two READMEs) these two scripts need, since thebundle installer only copies
hooks/scripts/.test-run-lead— normalizes each test case's id before dispatch (sourceof truth: the TC file's own name), so tokens/cost stay attributable per TC
even when a case's frontmatter id and filename briefly disagree.
tasks/baseline-web/— 8 baseline TCs this add-on's own benchmarking wasdeveloped and verified against.
knowledge/metrics-format.mdandknowledge/test-run-report-format.mddocument every field the current scripts actually read/produce (
turns,subagent_dispatches,orchestrator_cost_pct,tokens_by_model,tokens_by_agent, and the optional tokenomics-export frontmatter keys), witha real, internally-consistent sample run throughout.
Squashed from the original
feat/manual-qa-challengesbranch (10 iterativecommits, developed over several sessions) onto current
mainas a singleclean commit. That branch's history included an entire first implementation
of this same feature (top-level
hooks/scripts,build-run-metrics.mjs,etc., plus a stray pre-run-ccusage hunk in the shared
hooks/session-start)that got superseded by the bundle-based design partway through but was never
actually deleted — this PR omits it rather than asking reviewers to read past
dead code marked "deprecated" inline. A straight rebase was tried first and
hit a real conflict on the very first of 12 commits (
.gitignore, from howfar
mainhad moved on) — squashed instead via a clean three-way merge ontofresh
main, which correctly preserved the unrelated changesmainhad madeto
bundles/manual-qa/README.md/BUNDLE.mdin the meantime.Test plan
node --checkon every.mjsscript in this PRbuild-tokenomics-report.mjsandbuild-tokenomics-html.mjsrunend-to-end in an isolated scratch directory against a real captured run
(
RUN-2026-07-22-005), producing output identical to the project-localcopies they were ported from
elitea-testingsession:reports/metrics/*.json,tokens_by_model,tokens_by_agent, and the tokenomics export allpopulated correctly end-to-end
knowledge/metrics-format.mdparses and isinternally consistent (
tokens_by_agentsums tosession.total_tokens)npx github:arozumenko/sdlc-skills init --bundle manual-qainstall+ one real run, on a clean project (not yet done from this exact PR
branch — please confirm on your end before merging, per the existing
"First-install self-check" in
hooks/README.md)not confirmed on real Mac/Linux hardware (flagged as a known caveat in
hooks/README.md)🤖 Generated with Claude Code