Skip to content

Keep the what and why in generated commit messages - #44

Open
rafaeelricco wants to merge 6 commits into
mainfrom
rafaeelricco/keep-commit-message-meaning
Open

rafaeelricco wants to merge 6 commits into
mainfrom
rafaeelricco/keep-commit-message-meaning

Conversation

@rafaeelricco

Copy link
Copy Markdown
Owner

Motivation

Since the compression work landed, generated commit messages have been losing their meaning: they read more like a list of the files that changed than an account of what changed and why.

What's New

Compression Budget

  • renderWithinBudget gives leftover budget back to files fitToBudget reduced. fitToBudget could drop a whole file to a stat line and leave most of the budget unused, as when 6b6e2d9 in pov-studio-pro went from 19,945 tokens to 225 against a 12,000 budget. That commit now sends about 12,000 tokens.
  • Long files are cut at a # ... N more changed lines cut marker. Lines are taken round-robin, so every hunk is represented before any hunk gets more.
  • Source files are served first, then tests, then deleted files, so a deleted body only takes what the others leave over. Diffs under budget are still sent byte-for-byte.
  • The legend now describes the cut marker, and tells the model not to infer changes from line counts.

Split Plan Messages

  • Split plans use the configured effort instead of always running at the lowest. An unset effort still falls back to low, or Gemini's first level.
  • The split prompt asks for behavior, each distinct change, and the reason when the diff shows it, and rules out file lists and line counts. Custom templates keep control of the message's shape.
  • Raw line breaks in a message's JSON string are now accepted. Multi-line messages make that reply more likely, and it would otherwise fail the whole commit run.

Adjust

  • refineCommitMessage receives context.diff instead of the file list, so an adjustment such as "explain why" can see the code. Each adjust can resend up to about 12,000 tokens.

Split Review

  • Editing a message now changes only its title and keeps the body. p.text keeps just the last line of a multi-line value once you type, which lost the body.
  • The commit picker shows titles, and the plan note indents bodies under their number.

Compressed Context Flow

flowchart TB
    A["Staged diff"] --> B{"Fits 12,000 tokens?"}
    B -->|Yes| C["Send the exact diff"]
    B -->|No| D["fitToBudget: lower detail per file"]
    D --> E["Leftover budget"]
    E --> F["Source files"]
    F --> G["Test files"]
    G --> H["Deleted files"]
    H --> I["Send with cut markers"]
Loading

Changed Files

File Change Type Summary
src/domain/context/compress.ts Modified Add renderWithinBudget, round-robin cuts, fair shares
src/domain/context/context.ts Modified Use renderWithinBudget, rewrite the legend
src/domain/commit/prompts.ts Modified Add split message guidance, send the diff to refine
src/domain/llm/router.ts Modified Use configured effort for split plans, rename refine input
src/domain/split/plan.ts Modified Accept raw line breaks in message strings
src/cli/split.ts Modified Edit titles only, show titles in the picker, indent bodies
src/cli/commit.ts Modified Pass context.diff to refine
scripts/measure-context.ts Modified Rename the manifest label
test/domain/context/, test/domain/commit/, test/domain/llm/, test/domain/split/, test/cli/ Modified Cover the behavior above

Testing & Feedback

Typecheck, Prettier, lint:ci, the build, and all 413 tests pass. I also ran the real split review in a pseudo-terminal with real git commits, and replayed 1,002 commits from 7 repos through buildStagedContext. Commits sending under half the budget fell from 24 to 3: two with huge single-line changes, and one with an identical edit across 98 files. One commit stays over budget, because its 527 renames make the file list alone about 23,000 tokens.

No real provider call has gone through the tool yet. Message comparisons used Haiku on the generated prompts by hand, one sample per case. Please look closely at:

  • Split plans at high effort. They now use the configured level, and a slow or truncated reply would surface as a timeout or invalid JSON, which isn't retried.
  • A double-escaped \\n from a model still commits a literal \n in the message.
  • fast-commit-model will conflict with this branch in prompts.ts and router.ts. fc4a7d6 is already covered here.

If you find any bugs or have recommendations for improvements, please open an issue and assign it to me.

- Call `generateContent` with `withDefaultMinEffort(config)` in `generateSplitPlan`, so an explicit effort reaches the provider and an unset one still falls back to `low`, or Gemini's first level.
- Drop the unused `withMinEffort` import from `src/domain/llm/router.ts` and list split plans under `withDefaultMinEffort` in its header.
- Assert a configured `high` reaches the provider and an unset effort defaults to `low` in the split-plan router tests.
- Add `renderWithinBudget`, which gives leftover budget back to files `fitToBudget` reduced, so a 19,945-token diff now sends about 12,000 tokens instead of 225.
- Cut long files at a `# ... N more changed lines cut` marker, taking lines round-robin so every hunk is represented before any hunk gets more.
- Serve source files first, then tests, then deleted files, so a deleted body only takes what the others leave over.
- Hand a share to the other files when a file's lines are too long to use it.
- Rewrite the legend to describe the cut marker and tell the model not to infer changes from line counts.
- Cover Markdown files, many hunks, many files, huge single lines, deleted files, and the budget limit with unit tests.
- Pass `context.diff` to `refineCommitMessage` from `Commit.refine`, so an adjustment like "explain why" can see the code.
- Rename the refine input to `diff` and wrap it in `<diff>` in `getRefinePrompt`.
- Update the module headers and the `pnpm measure` label that described Adjust as manifest-only.
- Assert the diff reaches the provider in the commit, prompt, and router tests.
- Tell the split prompt to describe behavior, cover each distinct change, give the reason when the diff shows it, and not list files or quote line counts.
- State the multi-bullet message shape for the built-in conventions and leave the shape to a custom template.
- Add a detailed multi-bullet example, and keep the one-line example for custom templates.
- Ask for line breaks as `\n` inside the JSON string.
- Assert the guidance, the custom template case, and that the examples parse as JSON.
- Edit only the title in the split plan, because `p.text` keeps just the last line of a multi-line value once you type, which lost the body.
- Show titles in the commit picker and indent bodies under their number in the plan note.
- Cover the picker, the note, and the edit flow with unit tests.
- Retry `JSON.parse` with line breaks inside strings escaped, so a multi-line message written with raw newlines no longer fails the whole `commit` run with "Split plan: invalid JSON".
- Cover escaped and raw line breaks, and a reply that is still not JSON, with unit tests.
@rafaeelricco rafaeelricco self-assigned this Nov 4, 2026
@rafaeelricco
rafaeelricco marked this pull request as ready for review November 4, 2026 23:07
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-04T23:08:25.135783Z 7b05fde Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant