Skip to content

Govern the solution server hint prompt as a versioned Jinja2 template#930

Open
fabianvf wants to merge 3 commits into
konveyor:mainfrom
fabianvf:prompt-template-governance
Open

Govern the solution server hint prompt as a versioned Jinja2 template#930
fabianvf wants to merge 3 commits into
konveyor:mainfrom
fabianvf:prompt-template-governance

Conversation

@fabianvf

@fabianvf fabianvf commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

What

Moves the solution server's live hint prompt (generate_hint_v3) out of an inline f-string in server.py and into a versioned Jinja2 template under kai_mcp_solution_server/src/kai_mcp_solution_server/prompts/, rendered through a small render_prompt(...) registry. A checksummed manifest.yaml tracks it.

Why

This is the Kai side of the prompt-template governance we just landed in editor-extensions (ISO 42001 A.5.2). That work explicitly scoped out the solution-server prompts, noting they're owned here — this closes that loop. The hint prompt is effectively the instruction set for hint generation, so it gets version control, peer review, and CI validation independent of the application code. The incident loop now lives in the template; the AST-diff computation stays in Python and is passed in as a variable.

Behavior

No behavior change for the live prompt. A parity suite renders the template and asserts it matches a verbatim copy of the old f-string byte-for-byte across the incident / AST-diff matrix (0/1/N incidents, empty/populated diff, multi-line and special-char fields). Jinja renders None/dicts identically to the old f-strings, so there's no silent drift.

generate_hint_v1 and generate_hint_v2 were never called (only v3 is wired up, at server.py:1098) — they're removed as dead code, along with the now-unused get_diff import.

What's here

  • prompts/ — the Jinja2 template + manifest and the render registry; shipped as package data (verified present in the built wheel).
  • scripts/prompts_version.py + .github/workflows/prompt-validation.yml — validate Jinja syntax, declared-vs-referenced variables, and manifest checksums on any prompts/** change, plus the parity and a deterministic (mock-model) semantic-regression test.
  • PROMPT_GOVERNANCE.md, a new .github/CODEOWNERS (scoped to the prompts dir only), and an audit-evidence doc.

Verification

uv build (template + manifest in the wheel), pytest tests/prompts (7 pass), python scripts/prompts_version.py check, mypy src, and ruff/Trunk all green. requirements.txt regenerated for the new jinja2 dependency.

Needs a repo admin (can't be done in code)

  • Create the @konveyor/kai-prompt-reviewers team.
  • Branch protection requiring the Validate prompt templates check + Code-Owner review on the prompts directory (documented in PROMPT_GOVERNANCE.md).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added governed prompt rendering for the server, enabling the latest migration hint output to be generated from structured templates.
    • Introduced a refreshed hint format with clearer, consistent sections and example-driven guidance.
  • Bug Fixes

    • Improved prompt validation so missing values, template issues, and content drift are caught earlier.
    • Added checks to help keep generated prompts consistent across updates.

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@fabianvf, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 43 minutes and 59 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: aec2d1fe-bde3-49d5-a746-d03ed14ec428

📥 Commits

Reviewing files that changed from the base of the PR and between 68e68e4 and 009c511.

📒 Files selected for processing (3)
  • .trunk/trunk.yaml
  • kai_mcp_solution_server/scripts/prompts_version.py
  • kai_mcp_solution_server/tests/prompts/test_semantic_regression.py
📝 Walkthrough

Walkthrough

This PR adds prompt governance documentation, a manifest-driven Jinja2 prompt renderer, a new generate_hint_v3 template, server wiring to use render_prompt, validation tooling and tests, and a Trunk Node runtime update.

Changes

Prompt governance and rendering pipeline

Layer / File(s) Summary
Policy and ownership
.github/CODEOWNERS, kai_mcp_solution_server/PROMPT_GOVERNANCE.md, kai_mcp_solution_server/docs/ISO-42001-A5.2-evidence.md
CODEOWNERS routes prompt-path changes to the prompt reviewers team, and the governance/evidence docs describe prompt lifecycle, review, validation, threat-model checks, and branch-protection requirements.
Manifest and renderer
kai_mcp_solution_server/pyproject.toml, kai_mcp_solution_server/requirements.txt, kai_mcp_solution_server/src/kai_mcp_solution_server/prompts/manifest.yaml, kai_mcp_solution_server/src/kai_mcp_solution_server/prompts/__init__.py
Jinja2 is added as a dependency, the manifest registers generate_hint_v3, and render_prompt resolves template ids through a strict Jinja2 environment.
Template and server
kai_mcp_solution_server/src/kai_mcp_solution_server/prompts/templates/generate_hint_v3.md.jinja, kai_mcp_solution_server/src/kai_mcp_solution_server/server.py
The generate_hint_v3 template defines the prompt structure, and server.generate_hint_v3 now renders it through render_prompt after removing the older hint-generation functions and inline prompt assembly.
Validation automation
.github/workflows/prompt-validation.yml, kai_mcp_solution_server/scripts/prompts_version.py
The new workflow runs the prompt version checker and prompt tests on prompt-related pull requests, and the CLI checks manifest coverage, checksums, syntax, placeholder leftovers, and declared variables.
Parity and regression tests
kai_mcp_solution_server/tests/prompts/*
The oracle plus parity and semantic regression tests render generate_hint_v3 and assert byte-for-byte output matching plus fixed output-contract content across baseline scenarios.

Node runtime update

Layer / File(s) Summary
Node runtime version
.trunk/trunk.yaml
The enabled Node runtime in Trunk changes from node@18.12.1 to node@22.16.0.

Sequence Diagram(s)

sequenceDiagram
  participant Server as "server.generate_hint_v3"
  participant PromptAPI as render_prompt
  participant Env as "Jinja2 Environment"
  participant Template as "generate_hint_v3.md.jinja"

  Server->>PromptAPI: render_prompt("generate_hint_v3", incidents, ast_diff_str)
  PromptAPI->>Env: load template by prompt id
  Env->>Template: render with incidents and ast_diff_str
  Template-->>Env: rendered prompt text
  Env-->>PromptAPI: rendered prompt text
  PromptAPI-->>Server: final prompt string
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I nibbled the prompt, then gave a hop,
Jinja2 carrots made the warnings stop.
The server leapt to render_prompt with glee,
And tests said, “Yes—this is what it should be!”
Bink! went the rabbit, as checksums aligned.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly captures the main change: moving the hint prompt to a versioned Jinja2 template under governance.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@fabianvf fabianvf force-pushed the prompt-template-governance branch from f1957ad to 9e2f469 Compare June 24, 2026 19:35
Extract the live generate_hint_v3 prompt out of server.py into a versioned
Jinja2 asset under src/kai_mcp_solution_server/prompts/, rendered via
render_prompt(). The incident loop now lives in the template; the AST-diff
computation stays in Python and is passed in as a variable. This brings the
solution server's hint prompt under the same governance the editor-extensions
repo adopted for its prompts (ISO 42001 A.5.2) — the surface that work
explicitly left to be governed here.

- prompts/: Jinja2 template + manifest (semver + checksum), render registry;
  ships as package data (verified present in the built wheel)
- byte-exact parity tests prove the template reproduces the previous prompt
  string exactly across the incident / AST-diff matrix, plus a deterministic
  mock-model semantic-regression check
- scripts/prompts_version.py + prompt-validation.yml validate Jinja syntax,
  declared variables, and manifest checksums on any prompts/** change
- PROMPT_GOVERNANCE.md, a new CODEOWNERS, and an audit-evidence doc
- remove the never-called generate_hint_v1/v2 (dead code) and the now-unused
  get_diff import

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Fabian von Feilitzsch <fabian@fabianism.us>
@fabianvf fabianvf force-pushed the prompt-template-governance branch from 9e2f469 to cba8734 Compare June 24, 2026 19:42
Trunk Check fails on any PR touching Markdown or TOML because two tools can't
run in CI:
  - markdownlint@0.48.0 crashes at startup under the bundled node 18.12.1
    ("SyntaxError: Invalid regular expression flags" — string-width uses the
    unicode-sets `v` regex flag, which needs node 20+).
  - taplo@0.10.0's Linux binary fails to install ("Binary not found") with the
    old plugins definitions.

Bump the node runtime to 22.16.0, the trunk-io/plugins ref to v1.10.2 (refreshes
tool download definitions; pinned tool versions are unchanged), and markdownlint
to 0.49.0. `trunk check` reports no new issues across the changed files.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Fabian von Feilitzsch <fabian@fabianism.us>
@fabianvf fabianvf force-pushed the prompt-template-governance branch from 68e68e4 to e007b11 Compare June 24, 2026 20:55

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
kai_mcp_solution_server/tests/prompts/test_semantic_regression.py (1)

69-73: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert all incident fields that the prompt contract depends on.

The regression currently checks only a subset of incident fields. Add assertions for code_snip, line_number, and variables to catch accidental template regressions in those sections.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@kai_mcp_solution_server/tests/prompts/test_semantic_regression.py` around
lines 69 - 73, The semantic regression test is only validating a subset of the
incident data rendered by the prompt. Update the assertions in
test_semantic_regression to also check code_snip, line_number, and variables for
each incident, alongside the existing uri, message, and violation_name checks,
so the prompt contract covers all fields the template depends on.
.github/workflows/prompt-validation.yml (1)

25-35: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low value

Optional: align with the repo's action-pinning / credential-hygiene policy.

zizmor flags these uses: references as unpinned (not pinned to a commit SHA) and notes actions/checkout doesn't set persist-credentials: false. If the repo enforces a blanket pinning policy, pin to immutable SHAs and disable credential persistence on checkout; otherwise this is consistent with existing workflows and can be deferred.

🔒 Suggested hardening
      - uses: actions/checkout@<commit-sha>  # v4
        with:
          persist-credentials: false
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/prompt-validation.yml around lines 25 - 35, The workflow
step in the prompt-validation job uses unpinned GitHub Actions and checkout
still persists credentials. If this repo follows the pinning/credential-hygiene
policy, update the actions referenced by actions/checkout, actions/setup-python,
and astral-sh/setup-uv in this job to immutable commit SHAs, and set
persist-credentials to false on the actions/checkout step; otherwise leave it
as-is if the repo intentionally allows this pattern.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@kai_mcp_solution_server/PROMPT_GOVERNANCE.md`:
- Around line 75-76: The required status-check name in PROMPT_GOVERNANCE should
match the exact workflow/job label reported by the CI system. Update the status
check entry from Validate prompt templates to the actual check name used by the
prompt validation workflow, and keep the Code Owners requirement unchanged so
the documented branch protection gate aligns with the status shown by the Prompt
Template Validation (ISO 42001 A.5.2) job.

In `@kai_mcp_solution_server/scripts/prompts_version.py`:
- Around line 46-111: `check()` currently validates template integrity but
misses the manifest↔package version contract, so add a version lockstep
validation between `manifest.yaml` and the package version in `pyproject.toml`.
Update `check()` in prompts_version.py to load/compare both versions, report a
clear problem when they differ, and fail the check alongside the existing
`problems` list; use the existing `load_manifest()` flow and extend it with a
helper or inline read of the package version so the CI gate catches drift.

---

Nitpick comments:
In @.github/workflows/prompt-validation.yml:
- Around line 25-35: The workflow step in the prompt-validation job uses
unpinned GitHub Actions and checkout still persists credentials. If this repo
follows the pinning/credential-hygiene policy, update the actions referenced by
actions/checkout, actions/setup-python, and astral-sh/setup-uv in this job to
immutable commit SHAs, and set persist-credentials to false on the
actions/checkout step; otherwise leave it as-is if the repo intentionally allows
this pattern.

In `@kai_mcp_solution_server/tests/prompts/test_semantic_regression.py`:
- Around line 69-73: The semantic regression test is only validating a subset of
the incident data rendered by the prompt. Update the assertions in
test_semantic_regression to also check code_snip, line_number, and variables for
each incident, alongside the existing uri, message, and violation_name checks,
so the prompt contract covers all fields the template depends on.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 58245fea-789e-4024-9729-d5c539b30002

📥 Commits

Reviewing files that changed from the base of the PR and between 29ae739 and 68e68e4.

⛔ Files ignored due to path filters (1)
  • kai_mcp_solution_server/uv.lock is excluded by !**/*.lock
📒 Files selected for processing (16)
  • .github/CODEOWNERS
  • .github/workflows/prompt-validation.yml
  • .trunk/trunk.yaml
  • kai_mcp_solution_server/PROMPT_GOVERNANCE.md
  • kai_mcp_solution_server/docs/ISO-42001-A5.2-evidence.md
  • kai_mcp_solution_server/pyproject.toml
  • kai_mcp_solution_server/requirements.txt
  • kai_mcp_solution_server/scripts/prompts_version.py
  • kai_mcp_solution_server/src/kai_mcp_solution_server/prompts/__init__.py
  • kai_mcp_solution_server/src/kai_mcp_solution_server/prompts/manifest.yaml
  • kai_mcp_solution_server/src/kai_mcp_solution_server/prompts/templates/generate_hint_v3.md.jinja
  • kai_mcp_solution_server/src/kai_mcp_solution_server/server.py
  • kai_mcp_solution_server/tests/prompts/__init__.py
  • kai_mcp_solution_server/tests/prompts/oracle.py
  • kai_mcp_solution_server/tests/prompts/test_parity.py
  • kai_mcp_solution_server/tests/prompts/test_semantic_regression.py

Comment on lines +75 to +76
1. **Require the status check** `Validate prompt templates`.
2. **Require review from Code Owners** so `prompts/**` edits need `@konveyor/kai-prompt-reviewers`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Align required status-check name with the actual workflow/job check.

Line 75 requires Validate prompt templates, but the workflow context is named Prompt Template Validation (ISO 42001 A.5.2). If these don’t match the actual reported check name, branch protection cannot enforce this gate as documented.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@kai_mcp_solution_server/PROMPT_GOVERNANCE.md` around lines 75 - 76, The
required status-check name in PROMPT_GOVERNANCE should match the exact
workflow/job label reported by the CI system. Update the status check entry from
Validate prompt templates to the actual check name used by the prompt validation
workflow, and keep the Code Owners requirement unchanged so the documented
branch protection gate aligns with the status shown by the Prompt Template
Validation (ISO 42001 A.5.2) job.

Comment thread kai_mcp_solution_server/scripts/prompts_version.py
From CodeRabbit's review:

- prompts_version.py: the check now fails if the prompt-set version in
  manifest.yaml drifts from the package version in pyproject.toml, enforcing the
  lockstep the governance doc documents.
- test_semantic_regression.py: also assert code_snip, line_number, and variables
  render, so the prompt contract covers every incident field the template
  depends on, not just uri/message/violation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Fabian von Feilitzsch <fabian@fabianism.us>
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