diff --git a/skills/kvb-check-confidence/SKILL.md b/skills/kvb-check-confidence/SKILL.md index 987f9aa..807f6f4 100644 --- a/skills/kvb-check-confidence/SKILL.md +++ b/skills/kvb-check-confidence/SKILL.md @@ -14,8 +14,8 @@ and never estimates one itself. 1. **Fix confidence** (percent): probability the change does what it claims. **Break risk** (percent): probability it breaks anything else, from the `kvb-check-break-risk` skill. Two numbers, never one blended figure. -2. **Score**: pass both, with efficiency from the `kvb-check-efficiency` - skill, speed from the `kvb-check-speed` skill and security and the +2. **Score**: pass both, with cost from the `kvb-check-efficiency` + skill, time from the `kvb-check-speed` skill and security and the critical count from `security.py` of the `kvb-check-security` skill, to `${CLAUDE_SKILL_DIR}/../kvb-check-score/scripts/score.py --fix --break --efficiency --speed --security --critical ` diff --git a/skills/kvb-check-efficiency/SKILL.md b/skills/kvb-check-efficiency/SKILL.md index 84481a1..7271fd4 100644 --- a/skills/kvb-check-efficiency/SKILL.md +++ b/skills/kvb-check-efficiency/SKILL.md @@ -4,7 +4,7 @@ description: > Token cost of skill edits, CPU and RAM of code edits. --- -Efficiency is the share of its base's resources a change uses: under 100 % +๐Ÿ’ธ Cost is the share of the base's resources a change uses: under 100 % it saves, over 100 % it costs more. Paste the script's lines, never a paragraph about them. `` is the commit the change starts from: `HEAD` for uncommitted work, the merge base with the default @@ -20,7 +20,7 @@ It compares every changed `*.md` under `skills/`, untracked ones included, at `` with the working tree, and the always-loaded listing: all `description:` words, counted by the repository's `scripts/budget.py`. Tokens are an estimate, characters / 4. Changed files without any base text -print `efficiency new`, which counts as over 100. Skills have no speed. +print `cost new`, which counts as over 100. Skills have no time. A second line, `๐Ÿ’ฐ value 1:` (`:1` when value < cost), weighs both per day and never changes the exit code; pass its quotient or `?` to @@ -45,15 +45,15 @@ python3 ${CLAUDE_SKILL_DIR}/scripts/measure.py --base -- Start it in the directory the command expects. It checks `` out as a detached worktree under `/tmp`, runs the command there and in the working tree from the same relative directory, compares CPU seconds and peak RSS, -and removes the worktree. Efficiency is the mean of the CPU and the RAM -ratio. The same run measures wall time for `kvb-check-speed`. +and removes the worktree. Cost is the mean of the CPU and the RAM ratio. +It also measures wall time for `kvb-check-speed`. - **Runs**: one per tree. Both values at most 100 end it; otherwise 4 more per tree, alternating, and the line reports the mean of all 5 (`mean of 5`). - **Other load**: a 1 s sample of system CPU busy before and after, and per run the busy share beyond the command's own CPU time. Above 30 %, or - unreadable without `/proc/stat`, the result is an estimate: speed comes + unreadable without `/proc/stat`, the result is an estimate: time comes from the CPU-time ratio, both values carry `~` and the line ends in `(estimated: other load %)`. Pass the numbers without `~` to `kvb-check-score`; the exit code holds as for a measured result. @@ -64,7 +64,7 @@ ratio. The same run measures wall time for `kvb-check-speed`. `${CLAUDE_SKILL_DIR}/../kvb-org-queue/scripts/queue.py hold --kind --task -- python3 ...`, in the background, by the `kvb-org-queue` skill; a cancelled wait there also exits 3, but - prints no ๐ŸŒฑ line. A light one self-admits with + prints no ๐Ÿ’ธ line. A light one self-admits with `watch.py admit --kind test-nostack` of `kvb-org-organize`. - Report the run you made; never rerun to pick the best result. diff --git a/skills/kvb-check-efficiency/scripts/measure.py b/skills/kvb-check-efficiency/scripts/measure.py index 82bd76f..f0d59ab 100755 --- a/skills/kvb-check-efficiency/scripts/measure.py +++ b/skills/kvb-check-efficiency/scripts/measure.py @@ -9,26 +9,26 @@ Args: relative to each tree's root; its output is discarded. Runs: - One run per tree, base first. When efficiency and speed are both at most 100 that + One run per tree, base first. When cost and time are both at most 100 that is the result; otherwise 4 more runs per tree, alternating, and the arithmetic mean of all 5 per tree counts. Other load: A 1 s /proc/stat sample of system CPU busy before and after the runs, and per run the busy jiffies minus the command's own CPU time, as a share of all jiffies. When - any share exceeds 30 % or cannot be read, the result is an estimate: speed comes + any share exceeds 30 % or cannot be read, the result is an estimate: time comes from the CPU-time ratio instead of wall time. Output: - `๐ŸŒฑ efficiency

% (cpu โ†’ s, ram โ†’ MB) ยท โšก speed

% (wall โ†’ s)`, + `๐Ÿ’ธ cost

% (cpu โ†’ s, ram โ†’ MB) ยท โฑ๏ธ time

% (wall โ†’ s)`, then ` ยท mean of 5` after the extra runs. An estimate marks both values with `~`, - shows `(cpu โ†’ s)` for speed and ends in `(estimated: other load %)`, or - `unknown` for . Efficiency is the mean of the CPU ratio (user plus system seconds + shows `(cpu โ†’ s)` for time and ends in `(estimated: other load %)`, or + `unknown` for . Cost is the mean of the CPU ratio (user plus system seconds of the command and its waited-for children) and the peak RSS ratio; each ratio is working tree over base, times 100. Exit codes: - 0 efficiency and speed at most 100, 2 usage error or a failing command + 0 cost and time at most 100, 2 usage error or a failing command (its tree, exit code and last stderr line on stderr), 3 either over 100. """ @@ -144,9 +144,9 @@ def line(found: dict) -> str: basis = "cpu" if found["estimated"] else "wall" before, after = found["base"], found["head"] text = ( - f"๐ŸŒฑ efficiency {mark}{found['efficiency']} % (cpu {before['cpu']:.2f}โ†’{after['cpu']:.2f} s, " + f"๐Ÿ’ธ cost {mark}{found['efficiency']} % (cpu {before['cpu']:.2f}โ†’{after['cpu']:.2f} s, " f"ram {before['ram']:.1f}โ†’{after['ram']:.1f} MB) ยท " - f"โšก speed {mark}{found['speed']} % ({basis} {before[basis]:.2f}โ†’{after[basis]:.2f} s)" + f"โฑ๏ธ time {mark}{found['speed']} % ({basis} {before[basis]:.2f}โ†’{after[basis]:.2f} s)" ) if found["runs"] > 1: text += f" ยท mean of {found['runs']}" diff --git a/skills/kvb-check-efficiency/scripts/tokens.py b/skills/kvb-check-efficiency/scripts/tokens.py index 317ba7c..093935a 100755 --- a/skills/kvb-check-efficiency/scripts/tokens.py +++ b/skills/kvb-check-efficiency/scripts/tokens.py @@ -15,8 +15,8 @@ Args: shipped change instead. Output: - Line 1: `๐ŸŒฑ efficiency

% (skills โ†’ tokens; listing โ†’ words)`, p = after / before * 100, - or `๐ŸŒฑ efficiency new (+ tokens; listing โ†’ words)` when the changed files hold no + Line 1: `๐Ÿ’ธ cost

% (skills โ†’ tokens; listing โ†’ words)`, p = after / before * 100, + or `๐Ÿ’ธ cost new (+ tokens; listing โ†’ words)` when the changed files hold no base tokens. Changed files are the *.md under skills/ that `git diff ` names plus untracked ones; a file missing on a side counts 0. Tokens are an estimate: characters / 4. The listing is the sum of every skills/*/SKILL.md description word. @@ -298,9 +298,9 @@ def check(argv: list[str]) -> int: else: listing = f"listing {listing_before}โ†’{listing_after} words" if efficiency is None: - print(f"๐ŸŒฑ efficiency new (+{after} tokens; {listing})") + print(f"๐Ÿ’ธ cost new (+{after} tokens; {listing})") else: - print(f"๐ŸŒฑ efficiency {efficiency} % (skills {before}โ†’{after} tokens; {listing})") + print(f"๐Ÿ’ธ cost {efficiency} % (skills {before}โ†’{after} tokens; {listing})") print(money) return 3 if efficiency is None or efficiency > LIMIT else 0 diff --git a/skills/kvb-check-gate/SKILL.md b/skills/kvb-check-gate/SKILL.md index 64a7262..069a354 100644 --- a/skills/kvb-check-gate/SKILL.md +++ b/skills/kvb-check-gate/SKILL.md @@ -6,7 +6,7 @@ description: > --- The gate rule, stated here and nowhere else: nothing is declared 90/5 (fix -confidence โ‰ฅ 90 %, break risk โ‰ค 5 %, efficiency and speed โ‰ค 100 % in +confidence โ‰ฅ 90 %, break risk โ‰ค 5 %, cost and time โ‰ค 100 % in `kvb-check-score`; over 100 %, ask the operator before the commit, naming the cause) before every `make test*` target of the project, each Makefile target named `test` or starting with `test-`, ran green on the exact head with a clean tracked tree. Until then diff --git a/skills/kvb-check-score/SKILL.md b/skills/kvb-check-score/SKILL.md index efd6cd0..6c888a4 100644 --- a/skills/kvb-check-score/SKILL.md +++ b/skills/kvb-check-score/SKILL.md @@ -1,7 +1,7 @@ --- name: kvb-check-score description: > - Score fix, break, efficiency, speed and security; run wherever confidence is reported. + Score fix, break, cost, time and security; run wherever confidence is reported. --- Run it wherever fix confidence and break risk are reported: every @@ -16,17 +16,18 @@ python3 ${CLAUDE_SKILL_DIR}/scripts/score.py --fix <0-100> --break <0-100> --eff | --- | --- | --- | | ๐ŸŽฏ | fix confidence | `kvb-check-confidence` | | ๐Ÿ’ฅ | break risk | `kvb-check-break-risk` | -| ๐ŸŒฑ | efficiency | `tokens.py` (skills) or `measure.py` (code) of `kvb-check-efficiency` | -| โšก | speed | `measure.py`, see `kvb-check-speed` | +| ๐Ÿ’ธ | cost, `--efficiency` | `tokens.py` (skills) or `measure.py` (code) of `kvb-check-efficiency` | +| โฑ๏ธ | time, `--speed` | `measure.py`, see `kvb-check-speed` | | ๐Ÿ›ก๏ธ | security, critical count | `security.py` of `kvb-check-security`; `~` from a review by hand | | ๐Ÿ’ฐ | cost:value quotient, tables and message block only | ๐Ÿ’ฐ line of `tokens.py` (skills) of `kvb-check-efficiency` | | ๐Ÿ† | score | this script | -`-` means not measured or not relevant (skills have no speed) and counts as +Cost and time: after over base in percent, over 100 worse. `-` means not +measured or not relevant (skills have no time) and counts as 100; it shows as `โ€“`. `new` (changed skill text without a base) counts as 100 in the score, yet still asks. Never invent a value: measure it or pass `-`. -Score = `fix * (100 - break) / 100 * 100 / efficiency * 100 / speed * security / 100`, +Score = `fix * (100 - break) / 100 * 100 / cost * 100 / time * security / 100`, capped to 0..100 and rounded. ## Gate @@ -41,11 +42,11 @@ The second line is the verdict, first match wins: in the block and commit only on the operator's word. Close the gap as the last section of `kvb-check-break-risk` says. - `โš ๏ธ gate: : ask the operator before the commit` (exit 3), naming - each of `efficiency % > 100`, `speed % > 100` and + each of `cost % > 100`, `time % > 100` and `security % < 100`: ask with the block what the cost buys or why each finding is acceptable; commit only on a yes, never carried over to another commit. -- `โœ… gate: 90/5, efficiency and speed <= 100, security 100 %` (exit 0): +- `โœ… gate: 90/5, cost and time <= 100, security 100 %` (exit 0): commit as usual. 90/5 still needs `gate: green` of `kvb-check-gate`. - Exit 2: usage error. @@ -53,12 +54,11 @@ The second line is the verdict, first match wins: Each flag replaces the two lines; values, gate and exit code stay: -- `--table`: one markdown table, `| ๐ŸŽฏ Fix | ๐Ÿ’ฅ Break | ๐ŸŒฑ Efficiency | - โšก Speed | ๐Ÿ›ก๏ธ Security | ๐Ÿ† Score | Gate |`. -- `--commit-table `: that table led by `๐Ÿ“ Worktree | ๐ŸŒฟ Branch | - ๐Ÿ“Š Diff stat` from git (top level, branch or `detached at `, staged - shortstat as ` files +/-`). Every commit block is this - table; after the commit, `--commit ` shows that commit's diff stat +- `--table`: one markdown table, `| ๐ŸŽฏ Fix | ๐Ÿ’ฅ Break | ๐Ÿ’ธ Cost | + โฑ๏ธ Time | ๐Ÿ›ก๏ธ Security | ๐Ÿ† Score | Gate |`. +- `--commit-table `: that table led by `๐ŸŒฟ Branch | ๐Ÿ“Š Diff stat` + from git, ๐Ÿ“ worktree path below, alone in a code block. Every commit + block is this table; after the commit, `--commit ` shows that commit's diff stat and a `๐Ÿ”– Commit` column. - `--message-block`: one value per line, `๐ŸŽฏ Fix: %` through `๐Ÿ† Score: ` and `๐Ÿšฆ Gate: `. Every commit message carries it @@ -66,6 +66,6 @@ Each flag replaces the two lines; values, gate and exit code stay: `-m` argument, so the approval prompt and git history show the values. On a skill change add `--value `, the quotient of the ๐Ÿ’ฐ line (`?` -while it has no value): a `๐Ÿ’ฐ Value` column after `๐ŸŒฑ Efficiency`, or line +while it has no value): a `๐Ÿ’ฐ Value` column after `๐Ÿ’ธ Cost`, or line after `๐Ÿ›ก๏ธ Security`. It changes neither score nor gate; alone it is a usage error. diff --git a/skills/kvb-check-score/scripts/score.py b/skills/kvb-check-score/scripts/score.py index aab20c2..b331cd6 100755 --- a/skills/kvb-check-score/scripts/score.py +++ b/skills/kvb-check-score/scripts/score.py @@ -1,38 +1,41 @@ #!/usr/bin/env python3 -"""Fold fix confidence, break risk, efficiency, speed and security into one score and one gate verdict. +"""Fold fix confidence, break risk, cost, time and security into one score and one gate verdict. Args: --fix: fix confidence in percent, 0 to 100. --break: break risk in percent, 0 to 100. - --efficiency: efficiency in percent above 0; `-` when not measured or not - relevant, `new` when the change has no base. Both count as 100 in the score. - --speed: speed in percent above 0, `-` or `new` as for --efficiency. + --efficiency: cost in percent above 0, from kvb-check-efficiency; `-` when not + measured or not relevant, `new` when the change has no base. Both count as 100 + in the score. + --speed: time in percent above 0, from kvb-check-speed; `-` or `new` as for + --efficiency. --security: security in percent, 0 to 100, from security.py of kvb-check-security; `~` for a value from a review by hand. --critical: count of critical security findings. --table: print one markdown table instead of the two lines. - --commit-table : the same table, led by the worktree, branch and staged - diff stat of that repository. + --commit-table : the same table, led by the branch and staged diff stat of + that repository, then a blank line, `๐Ÿ“ Worktree:` and the top level path + alone in a ```text block, so it copies in one go. --commit : with --commit-table, the diff stat of that commit instead of the staged one, plus a commit column. --message-block: print the commit message block instead of the two lines, one - value per line: `๐ŸŽฏ Fix: %`, `๐Ÿ’ฅ Break: %`, `๐ŸŒฑ Efficiency: `, - `โšก Speed: `, `๐Ÿ›ก๏ธ Security: %`, `๐Ÿ’ฐ Value: ` with --value only, + value per line: `๐ŸŽฏ Fix: %`, `๐Ÿ’ฅ Break: %`, `๐Ÿ’ธ Cost: `, + `โฑ๏ธ Time: `, `๐Ÿ›ก๏ธ Security: %`, `๐Ÿ’ฐ Value: ` with --value only, `๐Ÿ† Score: `, `๐Ÿšฆ Gate: `; values and markers as in line 1. --value : with --table, --commit-table or --message-block, a value after - the efficiency one (--message-block: after security): the cost:value quotient of + the cost one (--message-block: after security): the cost:value quotient of tokens.py of kvb-check-efficiency, `?` when unknown. It changes neither score nor gate. Output: - Line 1: `๐ŸŽฏ fix % ยท ๐Ÿ’ฅ break % ยท ๐ŸŒฑ efficiency % ยท โšก speed % ยท + Line 1: `๐ŸŽฏ fix % ยท ๐Ÿ’ฅ break % ยท ๐Ÿ’ธ cost % ยท โฑ๏ธ time % ยท ๐Ÿ›ก๏ธ security % ยท ๐Ÿ† score `, `โ€“` in place of ` %` for `-`, `new` for `new`. - Score is fix * (100 - break) / 100 * 100 / efficiency * 100 / speed * security / 100, + Score is fix * (100 - break) / 100 * 100 / cost * 100 / time * security / 100, capped to 0..100, rounded half up. Line 2: the gate verdict, `โœ… gate: ...`, `โ›” gate: ...` or `โš ๏ธ gate: ...`. Exit codes: 0 gate passed, 1 fix under 90 or break over 5, 2 usage error, - 3 efficiency or speed over 100 or new, or security under 100: ask the operator + 3 cost or time over 100 or new, or security under 100: ask the operator before the commit, 4 a critical security finding: do not commit. """ @@ -51,10 +54,11 @@ SAFE = 100 DASH = "-" NEW = "new" ESTIMATE = "~" -SCORE_HEADER = ("๐ŸŽฏ Fix", "๐Ÿ’ฅ Break", "๐ŸŒฑ Efficiency", "โšก Speed", "๐Ÿ›ก๏ธ Security", "๐Ÿ† Score", "Gate") -COMMIT_HEADER = ("๐Ÿ“ Worktree", "๐ŸŒฟ Branch", "๐Ÿ“Š Diff stat") +SCORE_HEADER = ("๐ŸŽฏ Fix", "๐Ÿ’ฅ Break", "๐Ÿ’ธ Cost", "โฑ๏ธ Time", "๐Ÿ›ก๏ธ Security", "๐Ÿ† Score", "Gate") +COMMIT_HEADER = ("๐ŸŒฟ Branch", "๐Ÿ“Š Diff stat") +WORKTREE = "๐Ÿ“ Worktree:" VALUE_HEADER = "๐Ÿ’ฐ Value" -VALUE_AT = SCORE_HEADER.index("๐ŸŒฑ Efficiency") + 1 +VALUE_AT = SCORE_HEADER.index("๐Ÿ’ธ Cost") + 1 UNKNOWN = "?" QUOTIENT = re.compile(r"\d+(?:\.\d+)?:\d+(?:\.\d+)?") SHORTSTAT = re.compile( @@ -143,13 +147,13 @@ def gate(args: argparse.Namespace) -> tuple[str, str, int]: failed.append(f"break {number(args.risk)} % > {BREAK_MAX}") value, mark = args.security unsafe = f"security {mark}{number(value)} % < {SAFE}" if value < SAFE else None - asks = [text for text in (over("efficiency", args.efficiency), over("speed", args.speed), unsafe) if text] + asks = [text for text in (over("cost", args.efficiency), over("time", args.speed), unsafe) if text] ask = f"{', '.join(asks)}: ask the operator before the commit" if asks else "" if failed: return "โ›”", "; ".join(part for part in (", ".join(failed), ask) if part), 1 if asks: return "โš ๏ธ", ask, 3 - return "โœ…", f"{FIX_MIN}/{BREAK_MAX}, efficiency and speed <= {COST_MAX}, security {SAFE} %", 0 + return "โœ…", f"{FIX_MIN}/{BREAK_MAX}, cost and time <= {COST_MAX}, security {SAFE} %", 0 def git(repo: str, *args: str) -> str: @@ -173,13 +177,9 @@ def diffstat(shortstat: str) -> str: def commit_cells(repo: str, commit: str | None) -> tuple[list[str], list[str]]: branch = git(repo, "branch", "--show-current") or f"detached at {git(repo, 'rev-parse', '--short', 'HEAD')}" if commit is None: - stat = git(repo, "diff", "--cached", "--shortstat") - return list(COMMIT_HEADER), [git(repo, "rev-parse", "--show-toplevel"), branch, diffstat(stat)] + return list(COMMIT_HEADER), [branch, diffstat(git(repo, "diff", "--cached", "--shortstat"))] stat = git(repo, "show", "--shortstat", "--format=", commit) - return ( - [*COMMIT_HEADER, "๐Ÿ”– Commit"], - [git(repo, "rev-parse", "--show-toplevel"), branch, diffstat(stat), git(repo, "rev-parse", "--short", commit)], - ) + return [*COMMIT_HEADER, "๐Ÿ”– Commit"], [branch, diffstat(stat), git(repo, "rev-parse", "--short", commit)] def cell(text: str) -> str: @@ -229,20 +229,22 @@ def main() -> int: row.insert(VALUE_AT, args.value) if args.commit_table: lead, cells = commit_cells(args.commit_table, args.commit) + top = git(args.commit_table, "rev-parse", "--show-toplevel") print(table([*lead, *header], [*cells, *row])) + print(f"\n{WORKTREE}\n\n```text\n{top}\n```") elif args.table: print(table(header, row)) elif args.message_block: worth_line = [f"๐Ÿ’ฐ Value: {args.value}"] if args.value else [] print("\n".join(( - f"๐ŸŽฏ Fix: {values[0]}", f"๐Ÿ’ฅ Break: {values[1]}", f"๐ŸŒฑ Efficiency: {values[2]}", - f"โšก Speed: {values[3]}", f"๐Ÿ›ก๏ธ Security: {values[4]}", *worth_line, + f"๐ŸŽฏ Fix: {values[0]}", f"๐Ÿ’ฅ Break: {values[1]}", f"๐Ÿ’ธ Cost: {values[2]}", + f"โฑ๏ธ Time: {values[3]}", f"๐Ÿ›ก๏ธ Security: {values[4]}", *worth_line, f"๐Ÿ† Score: {total}", f"๐Ÿšฆ Gate: {values[6]}", ))) else: print( - f"๐ŸŽฏ fix {values[0]} ยท ๐Ÿ’ฅ break {values[1]} ยท ๐ŸŒฑ efficiency {values[2]} ยท " - f"โšก speed {values[3]} ยท ๐Ÿ›ก๏ธ security {values[4]} ยท ๐Ÿ† score {total}" + f"๐ŸŽฏ fix {values[0]} ยท ๐Ÿ’ฅ break {values[1]} ยท ๐Ÿ’ธ cost {values[2]} ยท " + f"โฑ๏ธ time {values[3]} ยท ๐Ÿ›ก๏ธ security {values[4]} ยท ๐Ÿ† score {total}" ) print(f"{emoji} gate: {verdict}") return code diff --git a/skills/kvb-check-speed/SKILL.md b/skills/kvb-check-speed/SKILL.md index 8449b5e..e240587 100644 --- a/skills/kvb-check-speed/SKILL.md +++ b/skills/kvb-check-speed/SKILL.md @@ -4,15 +4,15 @@ description: > Wall-clock speed of changed code versus its base commit. --- -Speed is the share of its base's wall-clock time a change needs: under -100 % it is faster, over 100 % slower. It has no script of its own: one run +Its โฑ๏ธ time is the share of its base's wall-clock time a change needs: +under 100 % it is faster, over 100 % slower. It has no script of its own: one run of the `kvb-check-efficiency` measurement yields both values. ```bash python3 ${CLAUDE_SKILL_DIR}/../kvb-check-efficiency/scripts/measure.py --base -- ``` -Its `โšก speed

% (wall โ†’ s)` compares wall seconds at `` and +Its `โฑ๏ธ time

% (wall โ†’ s)` compares wall seconds at `` and in the working tree: one run each, or the mean of 5 each when a value exceeds 100. The command, the runs, the `queue.py hold` wrapper for heavy commands and the exit codes are those of the `kvb-check-efficiency` skill; @@ -24,6 +24,6 @@ pasting its whole line reports both values at once. renders) has no speed either: `--speed -`, and say why. - **Other load**: wall time follows host load. Above 30 % other load the script falls back to the CPU-time ratio and marks the estimate: - `โšก speed ~

% (cpu โ†’ s)`, ending in + `โฑ๏ธ time ~

% (cpu โ†’ s)`, ending in `(estimated: other load %)`. Report the run you made; never rerun to pick the best result. diff --git a/skills/kvb-ci-triage/funnel.md b/skills/kvb-ci-triage/funnel.md index 777a296..6789e62 100644 --- a/skills/kvb-ci-triage/funnel.md +++ b/skills/kvb-ci-triage/funnel.md @@ -24,7 +24,7 @@ skill's Rules apply here too. --task -- `, which waits for the rule-based grant and releases on exit. The fix enters the main line only at the funnel's bar (the `kvb-org-split` skill's: fix confidence โ‰ฅ 90 %, - break risk โ‰ค 5 %, efficiency and speed โ‰ค 100 % in the `kvb-check-score` + break risk โ‰ค 5 %, cost and time โ‰ค 100 % in the `kvb-check-score` block; over 100 %, ask the operator before the commit, naming the cause) after its independent review; below the bar the cluster ends as a proposal for the operator, never as a merge. Never mask a failure: no diff --git a/skills/kvb-code-tune/listen.md b/skills/kvb-code-tune/listen.md index ae2ef43..3ff4788 100644 --- a/skills/kvb-code-tune/listen.md +++ b/skills/kvb-code-tune/listen.md @@ -16,6 +16,6 @@ checklist (multi-select) with suggestions, free text allowed: be changed (files, roles, services); whether new dependencies, toolchains or languages may be introduced; whether infrastructure or CI configuration may change; the merge bar (default: the `kvb-org-split` skill's bar of fix - confidence โ‰ฅ 90 %, break risk โ‰ค 5 %, efficiency and speed โ‰ค 100 %, over + confidence โ‰ฅ 90 %, break risk โ‰ค 5 %, cost and time โ‰ค 100 %, over 100 % only after asking the operator, naming the cause); a time cap per delegated agent (default 60 minutes). diff --git a/skills/kvb-git-commit-no-verify/SKILL.md b/skills/kvb-git-commit-no-verify/SKILL.md index 4e9c4d1..5e1b27b 100644 --- a/skills/kvb-git-commit-no-verify/SKILL.md +++ b/skills/kvb-git-commit-no-verify/SKILL.md @@ -12,14 +12,14 @@ description: > 2. Show in the message right before the `git commit` call, never only after it, the full staged diff (`git diff --cached`), then the commit table of the kvb-check-score skill (`score.py ... --commit-table `): - ๐Ÿ“ worktree, ๐ŸŒฟ branch, ๐Ÿ“Š staged diff stat, then fix, break, efficiency, - speed, security, score and gate of the staged bundle, as the + ๐Ÿ“ worktree, ๐ŸŒฟ branch, ๐Ÿ“Š staged diff stat, then fix, break, cost, + time, security, score and gate of the staged bundle, as the kvb-check-confidence skill produces them: break risk derived through the kvb-check-break-risk skill, never estimated. 3. Approval-prompt duty: the commit call's approval prompt (Claude Code: the Bash `description`; other runtimes: their prompt text) names the worktree path, the branch, the diff stat and the score values (๐ŸŽฏ fix, ๐Ÿ’ฅ break, - ๐ŸŒฑ efficiency, โšก speed, ๐Ÿ›ก๏ธ security, ๐Ÿ† score). Missing any item: do not + ๐Ÿ’ธ cost, โฑ๏ธ time, ๐Ÿ›ก๏ธ security, ๐Ÿ† score). Missing any item: do not send the call. Gate exit 4 (critical security finding) means no commit: the call is never sent, not even on the operator's word; fix and rescan first. Exit 1 (below 90/5) is shown, the operator's word decides; exit 3 diff --git a/skills/kvb-git-pr-create/SKILL.md b/skills/kvb-git-pr-create/SKILL.md index 23c4f52..3050021 100644 --- a/skills/kvb-git-pr-create/SKILL.md +++ b/skills/kvb-git-pr-create/SKILL.md @@ -24,9 +24,9 @@ confirms it. branch fixes, each verified as the `kvb-git-issue-close` skill does. 5. **Confirm** with one `AskUserQuestion`: title (Conventional Commits), base, state and labels. The state follows the bar of the `kvb-org-split` - skill (fix confidence โ‰ฅ 90 %, break risk โ‰ค 5 %, efficiency and speed + skill (fix confidence โ‰ฅ 90 %, break risk โ‰ค 5 %, cost and time โ‰ค 100 %): ready at or above it, a draft with the residuals in the body - below it. An efficiency or speed over 100 % goes into this question with + below it. A cost or time over 100 % goes into this question with its cause. 6. **Create**: `gh pr create --base --head --title "" --body-file <file>`, plus `--draft` below the bar. diff --git a/skills/kvb-git-pr-label/SKILL.md b/skills/kvb-git-pr-label/SKILL.md index 162df2d..bf7f7cd 100644 --- a/skills/kvb-git-pr-label/SKILL.md +++ b/skills/kvb-git-pr-label/SKILL.md @@ -12,7 +12,7 @@ holds: failure on it, a red default-branch run or an issue that reproduces there; name the run or issue. - **`90/5`**: the pull request meets the bar of the `kvb-org-split` skill (fix - confidence โ‰ฅ 90 %, break risk โ‰ค 5 %, efficiency and speed โ‰ค 100 %; over + confidence โ‰ฅ 90 %, break risk โ‰ค 5 %, cost and time โ‰ค 100 %; over 100 %, ask the operator first, naming the cause), from the `kvb-check-score` block in its body or freshly assessed, and only when `gate.py status` of the `kvb-check-gate` skill prints `gate: green` with @@ -27,7 +27,7 @@ holds: 3. A missing label is created once: `gh label create hotfix --color B60205 --description "Fixes a failure on the default branch"`, `gh label create 90/5 --color 0E8A16 --description - "Fix confidence >= 90 %, break risk <= 5 %, efficiency and speed <= 100 %"`. + "Fix confidence >= 90 %, break risk <= 5 %, cost and time <= 100 %"`. 4. Standalone, confirm the changes with one `AskUserQuestion`; from `kvb-git-pr-create`, its confirmation covers them. 5. `gh pr edit <pr> --add-label <l>` or `--remove-label <l>`. A draft that diff --git a/skills/kvb-org-matrix/SKILL.md b/skills/kvb-org-matrix/SKILL.md index 45fe418..03c9465 100644 --- a/skills/kvb-org-matrix/SKILL.md +++ b/skills/kvb-org-matrix/SKILL.md @@ -38,8 +38,8 @@ One table, most-blocking first, one row per item: - **State**: `open`, `running`, `blocked`, `done`. `done` means verified (a passing run, a green check, a reproduction that now succeeds); work that merely looks finished is `open`. -- **Score**: the `kvb-check-score` line (๐ŸŽฏ fix, ๐Ÿ’ฅ break, ๐ŸŒฑ efficiency, - โšก speed, ๐Ÿ† score) per the `kvb-check-confidence` skill, only for rows +- **Score**: the `kvb-check-score` line (๐ŸŽฏ fix, ๐Ÿ’ฅ break, ๐Ÿ’ธ cost, + โฑ๏ธ time, ๐Ÿ† score) per the `kvb-check-confidence` skill, only for rows that changed something; `-` for pure observation rows. - **Evidence / next step**: for `done` the strongest proof line (what ran, what it returned), otherwise the single next action. diff --git a/skills/kvb-org-split/SKILL.md b/skills/kvb-org-split/SKILL.md index 03f32a7..47d5531 100644 --- a/skills/kvb-org-split/SKILL.md +++ b/skills/kvb-org-split/SKILL.md @@ -12,7 +12,7 @@ in a sidetree until it does, or leaves as a proposal. ## The bar -- **Fix confidence โ‰ฅ 90 %, break risk โ‰ค 5 %, efficiency and speed โ‰ค 100 %**, +- **Fix confidence โ‰ฅ 90 %, break risk โ‰ค 5 %, cost and time โ‰ค 100 %**, all from the `kvb-check-score` block of `kvb-check-confidence`; over 100 %, ask the operator before the commit, naming the cause. - The operator may set a different bar. Never lower it to make a change fit. diff --git a/tests/test_efficiency.py b/tests/test_efficiency.py index 09cb261..e3b14e3 100644 --- a/tests/test_efficiency.py +++ b/tests/test_efficiency.py @@ -33,8 +33,8 @@ NEW_B = "๐Ÿ’ฐ value ?:? (cost 0/day; pass --value with evidence; kvb-b new: all CHEAP = "print('cheap')\n" COSTLY = "data = list(range(2_000_000))\nprint(sum(data))\n" LINE = re.compile( - r"^๐ŸŒฑ efficiency (?P<mark>~?)(?P<efficiency>\d+) % \(cpu \d+\.\d\dโ†’\d+\.\d\d s, ram \d+\.\dโ†’\d+\.\d MB\) ยท " - r"โšก speed (?P<speed_mark>~?)(?P<speed>\d+) % \((?P<basis>wall|cpu) \d+\.\d\dโ†’\d+\.\d\d s\)(?P<tail>.*)$" + r"^๐Ÿ’ธ cost (?P<mark>~?)(?P<efficiency>\d+) % \(cpu \d+\.\d\dโ†’\d+\.\d\d s, ram \d+\.\dโ†’\d+\.\d MB\) ยท " + r"โฑ๏ธ time (?P<speed_mark>~?)(?P<speed>\d+) % \((?P<basis>wall|cpu) \d+\.\d\dโ†’\d+\.\d\d s\)(?P<tail>.*)$" ) @@ -121,7 +121,7 @@ class TestTokens(GitRepo): self.write("skills/kvb-a/scripts/tool.py", "print(1)\n" * 50) result = self.tokens() self.assertEqual( - result.stdout.splitlines(), ["๐ŸŒฑ efficiency 50 % (skills 100โ†’50 tokens; listing 3โ†’3 words)", NO_VALUE] + result.stdout.splitlines(), ["๐Ÿ’ธ cost 50 % (skills 100โ†’50 tokens; listing 3โ†’3 words)", NO_VALUE] ) self.assertEqual(result.returncode, 0, result.stderr) @@ -130,7 +130,7 @@ class TestTokens(GitRepo): self.write("skills/kvb-b/SKILL.md", SKILL_B.ljust(200, "y")) result = self.tokens() self.assertEqual( - result.stdout.splitlines(), ["๐ŸŒฑ efficiency 200 % (skills 100โ†’200 tokens; listing 3โ†’5 words)", NEW_B] + result.stdout.splitlines(), ["๐Ÿ’ธ cost 200 % (skills 100โ†’200 tokens; listing 3โ†’5 words)", NEW_B] ) self.assertEqual(result.returncode, 3) result = self.tokens("--json") @@ -157,7 +157,7 @@ class TestTokens(GitRepo): def test_only_new_files_print_new(self): self.write("skills/kvb-b/SKILL.md", SKILL_B.ljust(200, "y")) result = self.tokens() - self.assertEqual(result.stdout.splitlines(), ["๐ŸŒฑ efficiency new (+50 tokens; listing 3โ†’5 words)", NEW_B]) + self.assertEqual(result.stdout.splitlines(), ["๐Ÿ’ธ cost new (+50 tokens; listing 3โ†’5 words)", NEW_B]) self.assertEqual(result.returncode, 3) self.assertIsNone(json.loads(self.tokens("--json").stdout)["efficiency"]) @@ -165,14 +165,14 @@ class TestTokens(GitRepo): self.git("mv", "skills/kvb-a/notes.md", "skills/kvb-a/moved.md") result = self.tokens() self.assertEqual( - result.stdout.splitlines(), ["๐ŸŒฑ efficiency 100 % (skills 100โ†’100 tokens; listing 3โ†’3 words)", NO_VALUE] + result.stdout.splitlines(), ["๐Ÿ’ธ cost 100 % (skills 100โ†’100 tokens; listing 3โ†’3 words)", NO_VALUE] ) self.assertEqual(result.returncode, 0) def test_no_change_is_100(self): result = self.tokens() self.assertEqual( - result.stdout.splitlines(), ["๐ŸŒฑ efficiency 100 % (skills 0โ†’0 tokens; listing 3โ†’3 words)", NO_VALUE] + result.stdout.splitlines(), ["๐Ÿ’ธ cost 100 % (skills 0โ†’0 tokens; listing 3โ†’3 words)", NO_VALUE] ) self.assertEqual(result.returncode, 0) @@ -193,7 +193,7 @@ class TestTokens(GitRepo): self.assertEqual( result.stdout.splitlines(), [ - "๐ŸŒฑ efficiency 869 % (skills 13โ†’113 tokens; listing 3โ†’5 words)", + "๐Ÿ’ธ cost 869 % (skills 13โ†’113 tokens; listing 3โ†’5 words)", "๐Ÿ’ฐ value ?:? (cost 203/day; pass --value with evidence)", ], ) diff --git a/tests/test_score.py b/tests/test_score.py index 03f1969..2fcaa36 100644 --- a/tests/test_score.py +++ b/tests/test_score.py @@ -12,9 +12,9 @@ from pathlib import Path REPO_ROOT = Path(__file__).resolve().parents[1] SCORE = REPO_ROOT / "skills" / "kvb-check-score" / "scripts" / "score.py" -PASS = "โœ… gate: 90/5, efficiency and speed <= 100, security 100 %" +PASS = "โœ… gate: 90/5, cost and time <= 100, security 100 %" BASE = {"fix": "95", "break": "2", "efficiency": "100", "speed": "100", "security": "100", "critical": "0"} -HEADER = "| ๐ŸŽฏ Fix | ๐Ÿ’ฅ Break | ๐ŸŒฑ Efficiency | โšก Speed | ๐Ÿ›ก๏ธ Security | ๐Ÿ† Score | Gate |" +HEADER = "| ๐ŸŽฏ Fix | ๐Ÿ’ฅ Break | ๐Ÿ’ธ Cost | โฑ๏ธ Time | ๐Ÿ›ก๏ธ Security | ๐Ÿ† Score | Gate |" ASK = ": ask the operator before the commit" ENV = {"PATH": os.environ["PATH"]} @@ -37,12 +37,12 @@ class TestScore(unittest.TestCase): def test_formula_and_line_format(self): self.assertEqual( self._score(fix="95", **{"break": "4"}), - (["๐ŸŽฏ fix 95 % ยท ๐Ÿ’ฅ break 4 % ยท ๐ŸŒฑ efficiency 100 % ยท โšก speed 100 % ยท ๐Ÿ›ก๏ธ security 100 % ยท ๐Ÿ† score 91", + (["๐ŸŽฏ fix 95 % ยท ๐Ÿ’ฅ break 4 % ยท ๐Ÿ’ธ cost 100 % ยท โฑ๏ธ time 100 % ยท ๐Ÿ›ก๏ธ security 100 % ยท ๐Ÿ† score 91", PASS], 0), ) lines, code = self._score(efficiency="97", speed="-") self.assertEqual( - lines[0], "๐ŸŽฏ fix 95 % ยท ๐Ÿ’ฅ break 2 % ยท ๐ŸŒฑ efficiency 97 % ยท โšก speed โ€“ ยท ๐Ÿ›ก๏ธ security 100 % ยท ๐Ÿ† score 96" + lines[0], "๐ŸŽฏ fix 95 % ยท ๐Ÿ’ฅ break 2 % ยท ๐Ÿ’ธ cost 97 % ยท โฑ๏ธ time โ€“ ยท ๐Ÿ›ก๏ธ security 100 % ยท ๐Ÿ† score 96" ) self.assertEqual(code, 0) self.assertEqual(self._score(fix="92.5")[0][0].split(" ยท ")[0], "๐ŸŽฏ fix 92.5 %") @@ -51,14 +51,14 @@ class TestScore(unittest.TestCase): lines, code = self._score(fix="92", efficiency="-", speed="-", **{"break": "3"}) self.assertEqual( (lines, code), - (["๐ŸŽฏ fix 92 % ยท ๐Ÿ’ฅ break 3 % ยท ๐ŸŒฑ efficiency โ€“ ยท โšก speed โ€“ ยท ๐Ÿ›ก๏ธ security 100 % ยท ๐Ÿ† score 89", PASS], 0), + (["๐ŸŽฏ fix 92 % ยท ๐Ÿ’ฅ break 3 % ยท ๐Ÿ’ธ cost โ€“ ยท โฑ๏ธ time โ€“ ยท ๐Ÿ›ก๏ธ security 100 % ยท ๐Ÿ† score 89", PASS], 0), ) def test_security_multiplies_and_asks_below_100(self): lines, code = self._score(fix="100", efficiency="-", speed="-", security="75", **{"break": "0"}) self.assertEqual( (lines, code), - (["๐ŸŽฏ fix 100 % ยท ๐Ÿ’ฅ break 0 % ยท ๐ŸŒฑ efficiency โ€“ ยท โšก speed โ€“ ยท ๐Ÿ›ก๏ธ security 75 % ยท ๐Ÿ† score 75", + (["๐ŸŽฏ fix 100 % ยท ๐Ÿ’ฅ break 0 % ยท ๐Ÿ’ธ cost โ€“ ยท โฑ๏ธ time โ€“ ยท ๐Ÿ›ก๏ธ security 75 % ยท ๐Ÿ† score 75", f"โš ๏ธ gate: security 75 % < 100{ASK}"], 3), ) lines, code = self._score(security="~80") @@ -94,7 +94,7 @@ class TestScore(unittest.TestCase): ({"fix": "80", "break": "10"}, "โ›” gate: fix 80 % < 90, break 10 % > 5"), ( {"fix": "85", "efficiency": "150", "speed": "new", "security": "50"}, - f"โ›” gate: fix 85 % < 90; efficiency 150 % > 100, speed new, security 50 % < 100{ASK}", + f"โ›” gate: fix 85 % < 90; cost 150 % > 100, time new, security 50 % < 100{ASK}", ), ): with self.subTest(values=values): @@ -103,13 +103,13 @@ class TestScore(unittest.TestCase): def test_costs_ask_the_operator_exit_3(self): for values, verdict in ( - ({"efficiency": "120"}, f"โš ๏ธ gate: efficiency 120 % > 100{ASK}"), - ({"efficiency": "-", "speed": "130"}, f"โš ๏ธ gate: speed 130 % > 100{ASK}"), - ({"efficiency": "100.5", "speed": "-"}, f"โš ๏ธ gate: efficiency 100.5 % > 100{ASK}"), - ({"efficiency": "new", "speed": "-"}, f"โš ๏ธ gate: efficiency new{ASK}"), + ({"efficiency": "120"}, f"โš ๏ธ gate: cost 120 % > 100{ASK}"), + ({"efficiency": "-", "speed": "130"}, f"โš ๏ธ gate: time 130 % > 100{ASK}"), + ({"efficiency": "100.5", "speed": "-"}, f"โš ๏ธ gate: cost 100.5 % > 100{ASK}"), + ({"efficiency": "new", "speed": "-"}, f"โš ๏ธ gate: cost new{ASK}"), ( {"efficiency": "120", "speed": "130", "security": "90"}, - f"โš ๏ธ gate: efficiency 120 % > 100, speed 130 % > 100, security 90 % < 100{ASK}", + f"โš ๏ธ gate: cost 120 % > 100, time 130 % > 100, security 90 % < 100{ASK}", ), ): with self.subTest(values=values): @@ -128,7 +128,7 @@ class TestScore(unittest.TestCase): def test_new_counts_as_100_in_the_score(self): lines, _ = self._score(efficiency="new", speed="-", **{"break": "0"}) self.assertEqual( - lines[0], "๐ŸŽฏ fix 95 % ยท ๐Ÿ’ฅ break 0 % ยท ๐ŸŒฑ efficiency new ยท โšก speed โ€“ ยท ๐Ÿ›ก๏ธ security 100 % ยท ๐Ÿ† score 95" + lines[0], "๐ŸŽฏ fix 95 % ยท ๐Ÿ’ฅ break 0 % ยท ๐Ÿ’ธ cost new ยท โฑ๏ธ time โ€“ ยท ๐Ÿ›ก๏ธ security 100 % ยท ๐Ÿ† score 95" ) def test_table(self): @@ -138,7 +138,7 @@ class TestScore(unittest.TestCase): [ HEADER, "| --- | --- | --- | --- | --- | --- | --- |", - "| 95 % | 2 % | 97 % | โ€“ | 100 % | 96 | โœ… 90/5, efficiency and speed <= 100, security 100 % |", + "| 95 % | 2 % | 97 % | โ€“ | 100 % | 96 | โœ… 90/5, cost and time <= 100, security 100 % |", ], ) self.assertEqual(result.returncode, 0) @@ -152,8 +152,8 @@ class TestScore(unittest.TestCase): (result.stdout.splitlines(), result.returncode), ( [ - "๐ŸŽฏ Fix: 95 %", "๐Ÿ’ฅ Break: 2 %", "๐ŸŒฑ Efficiency: 97 %", "โšก Speed: โ€“", "๐Ÿ›ก๏ธ Security: 100 %", - "๐Ÿ† Score: 96", "๐Ÿšฆ Gate: โœ… 90/5, efficiency and speed <= 100, security 100 %", + "๐ŸŽฏ Fix: 95 %", "๐Ÿ’ฅ Break: 2 %", "๐Ÿ’ธ Cost: 97 %", "โฑ๏ธ Time: โ€“", "๐Ÿ›ก๏ธ Security: 100 %", + "๐Ÿ† Score: 96", "๐Ÿšฆ Gate: โœ… 90/5, cost and time <= 100, security 100 %", ], 0, ), @@ -165,7 +165,7 @@ class TestScore(unittest.TestCase): (result.stdout.splitlines(), result.returncode), ( [ - "๐ŸŽฏ Fix: 95 %", "๐Ÿ’ฅ Break: 2 %", "๐ŸŒฑ Efficiency: 100 %", "โšก Speed: 100 %", "๐Ÿ›ก๏ธ Security: ~80 %", + "๐ŸŽฏ Fix: 95 %", "๐Ÿ’ฅ Break: 2 %", "๐Ÿ’ธ Cost: 100 %", "โฑ๏ธ Time: 100 %", "๐Ÿ›ก๏ธ Security: ~80 %", "๐Ÿ’ฐ Value: 1:20", "๐Ÿ† Score: 74", f"๐Ÿšฆ Gate: โš ๏ธ security ~80 % < 100{ASK}", ], 3, @@ -188,9 +188,9 @@ class TestScore(unittest.TestCase): def test_value_column_changes_neither_score_nor_gate(self): for value, verdict, code in ( - ("1:20", "โœ… 90/5, efficiency and speed <= 100, security 100 %", 0), - ("4.1:1", "โœ… 90/5, efficiency and speed <= 100, security 100 %", 0), - ("?", "โš ๏ธ efficiency 120 % > 100" + ASK, 3), + ("1:20", "โœ… 90/5, cost and time <= 100, security 100 %", 0), + ("4.1:1", "โœ… 90/5, cost and time <= 100, security 100 %", 0), + ("?", "โš ๏ธ cost 120 % > 100" + ASK, 3), ): with self.subTest(value=value): efficiency = "97" if code == 0 else "120" @@ -201,7 +201,7 @@ class TestScore(unittest.TestCase): self.assertEqual( result.stdout.splitlines(), [ - HEADER.replace("๐ŸŒฑ Efficiency |", "๐ŸŒฑ Efficiency | ๐Ÿ’ฐ Value |"), + HEADER.replace("๐Ÿ’ธ Cost |", "๐Ÿ’ธ Cost | ๐Ÿ’ฐ Value |"), "|" + " --- |" * 8, f"| 95 % | 2 % | {efficiency} % | {value} | โ€“ | 100 % | {score} | {verdict} |", ], @@ -235,8 +235,9 @@ class TestScore(unittest.TestCase): (repo / "a.txt").write_text("two\n", encoding="utf-8") (repo / "b.txt").write_text("three\nfour\n", encoding="utf-8") git("add", "a.txt", "b.txt") - head = ["๐Ÿ“ Worktree", "๐ŸŒฟ Branch", "๐Ÿ“Š Diff stat"] - score = "| 95 % | 2 % | 100 % | 100 % | 100 % | 93 | โœ… 90/5, efficiency and speed <= 100, security 100 % |" + head = ["๐ŸŒฟ Branch", "๐Ÿ“Š Diff stat"] + score = "| 95 % | 2 % | 100 % | 100 % | 100 % | 93 | โœ… 90/5, cost and time <= 100, security 100 % |" + worktree = ["", "๐Ÿ“ Worktree:", "", "```text", str(repo.resolve()), "```"] result = self._run(*flags(BASE), "--commit-table", str(repo), cwd=repo) self.assertEqual(result.returncode, 0, result.stderr) @@ -244,27 +245,29 @@ class TestScore(unittest.TestCase): result.stdout.splitlines(), [ "| " + " | ".join(head) + " " + HEADER, - "|" + " --- |" * 10, - f"| {repo.resolve()} | main | 2 files +3/-1 " + score, + "|" + " --- |" * 9, + "| main | 2 files +3/-1 " + score, + *worktree, ], ) git("commit", "-qm", "change") sha = git("rev-parse", "--short", "HEAD") result = self._run(*flags(BASE), "--commit-table", str(repo), "--commit", "HEAD", cwd=repo) self.assertEqual(result.stdout.splitlines()[0], "| " + " | ".join([*head, "๐Ÿ”– Commit"]) + " " + HEADER) - self.assertEqual(result.stdout.splitlines()[2], f"| {repo.resolve()} | main | 2 files +3/-1 | {sha} " + score) + self.assertEqual(result.stdout.splitlines()[2], f"| main | 2 files +3/-1 | {sha} " + score) + self.assertEqual(result.stdout.splitlines()[3:], worktree) result = self._run(*flags(BASE), "--commit-table", str(repo), "--commit", "HEAD", "--value", "?", cwd=repo) self.assertEqual( result.stdout.splitlines()[0], - "| " + " | ".join([*head, "๐Ÿ”– Commit"]) + " " + HEADER.replace("๐ŸŒฑ Efficiency |", "๐ŸŒฑ Efficiency | ๐Ÿ’ฐ Value |"), + "| " + " | ".join([*head, "๐Ÿ”– Commit"]) + " " + HEADER.replace("๐Ÿ’ธ Cost |", "๐Ÿ’ธ Cost | ๐Ÿ’ฐ Value |"), ) self.assertEqual( result.stdout.splitlines()[2], - f"| {repo.resolve()} | main | 2 files +3/-1 | {sha} " + score.replace("| 100 % |", "| 100 % | ? |", 1), + f"| main | 2 files +3/-1 | {sha} " + score.replace("| 100 % |", "| 100 % | ? |", 1), ) git("checkout", "-q", "--detach", "HEAD") result = self._run(*flags(BASE), "--commit-table", str(repo), cwd=repo) - self.assertEqual(result.stdout.splitlines()[2], f"| {repo.resolve()} | detached at {sha} | 0 files +0/-0 " + score) + self.assertEqual(result.stdout.splitlines()[2], f"| detached at {sha} | 0 files +0/-0 " + score) self.assertEqual(self._run(*flags(BASE), "--commit-table", tmp.name, cwd=repo).returncode, 2) def test_usage_errors_exit_2(self):