Skip to content

feat: add MLflow integration with postprocessing, KPIs, and PSAP payload for rhaiis - #74

Merged
MML-coder merged 8 commits into
openshift-psap:mainfrom
MML-coder:rhaiis-mlflow-integration
Jun 23, 2026
Merged

MML-coder merged 8 commits into
openshift-psap:mainfrom
MML-coder:rhaiis-mlflow-integration

Conversation

@MML-coder

@MML-coder MML-coder commented Jun 19, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Add rhaiis-specific postprocess plugin with 22 KPIs (model-furnace parity)
  • Generate PSAP-compatible payload JSON for archival and downstream compatibility
  • Wire run_and_postprocess() into test phase with MLflow tag metadata
  • Make gpu_type configurable in hardware resolver for multi-GPU-type clusters
  • Fix broken imports (caliper_export_command → caliper_export_entrypoint, create_fournos_resolve_command → create_fournos_resolve_entrypoint)

Changes

New files (projects/rhaiis/postprocess/)

  • plugin.py — rhaiis PostProcessingPlugin, reuses shared GuideLLMParser
  • kpis.py — 22 KPIs: 12 caliper baseline + 10 model-furnace extras (p99, concurrency, request counts, duration, prompt tokens)
  • parser.py — extends shared parser with p99 percentiles, request_totals, concurrency from raw benchmarks.json
  • psap_payload.py — generates model-furnace compatible PSAP_perf_*.json with experiment metadata

Modified files

  • ci.py — fix broken imports with backward-compatible try/except, configurable gpu_type in hardware resolver
  • config.yaml — add caliper.postprocess section with rhaiis plugin
  • config.d/rhaiis.yaml — add gpu_types mapping for hardware resolver
  • runtime_config.py — add get_gpu_type() accessor
  • test_phase.py — wrap with run_and_postprocess(), write __test_labels__.yaml, set MLflow tags, generate PSAP payload

KPI catalog (22 metrics)

Category KPIs
Throughput request_rate, tokens/s, input_tokens/s, output_tokens/s
Latency ttft (median, p95, p99), itl (median, p95, p99), tpot (median, p95, p99)
Request latency request_latency (median, p95)
Token efficiency input_tokens/request, output_tokens/request
Request stats concurrency, completed_requests, failed_requests
Benchmark duration, prompt_token_count_mean

MLflow tags (17)

model_key, hf_model_id, accelerator, tensor_parallel_size, vllm_image, vllm_version, workload_key, rates, max_seconds, guidellm_image, guidellm_backend_type, guidellm_rate_type, namespace, deployment_name, project

Test plan

CLI E2E (fournos-fg cluster, 2x L40S)

source ~/test_foo/python3_virt/bin/activate
KUBECONFIG=~/kubeconfigs/fournos-fg-kubeconfig \
PYTHONPATH=$PWD python3 -m projects.rhaiis.orchestration.cli test \
  --model qwen3-0_6b --workload profile1 \
  --namespace kserve-e2e-perf \
  --storage-pvc model-pvc \
  --image-pull-secret npalaska-image-pull \
  --rates 1,5,10 --max-seconds 60
  • 66 KPI records generated (22 KPIs × 3 rates)
  • PSAP payload JSON generated
  • MLflow export with 17 tags verified

Fournos E2E (fournos-fg cluster via FournosJob)

export KUBECONFIG=~/kubeconfigs/psap-automation-kubeconfig

# Submit job
cat <<YAML | oc create -n psap-automation -f -
apiVersion: fournos.dev/v1
kind: FournosJob
metadata:
  generateName: rhaiis-mlflow-test-
spec:
  owner: mehul
  displayName: rhaiis-qwen3-mlflow-l40s
  pipeline: forge-prepare-test
  cluster: fournos-fg
  priority: manual
  hardware:
    gpuType: l40s
    gpuCount: 1
  executionEngine:
    forge:
      project: rhaiis
      args: [nvidia, profile1]
      configOverrides:
        tests.rhaiis.model_key: qwen3-0_6b
        rhaiis.namespace: kserve-e2e-perf
        rhaiis.deploy.image_pull_secret: npalaska-image-pull
        rhaiis.deploy.storage_pvc: model-pvc
  env:
    PULL_PULL_SHA: "<branch-commit-sha>"
YAML

# Monitor
oc get fournosjobs -n psap-automation
oc get workloads -n psap-automation
oc get pipelineruns -n psap-automation | grep rhaiis
oc logs -f <pod-name> -n psap-automation -c step-main
  • Two FournosJobs submitted and completed (rhaiis-mlflow-test-ggmcq, rhaiis-mlflow-test-8s4zc)
  • Both exported to MLflow experiment forge-rhaiis (experiment ID 57)
  • Queue behavior verified (second job pending while first running)

MLflow verification

# Check experiment
https://mlflow.apps.aperdomo-lab.ibm.rhperfscale.org/#/experiments/57

Known limitations

  • MLflow tags not populated in Fournos-driven runs (export step re-initializes config from source, not artifact dir). Tags are available in __test_labels__.yaml artifact. Fix planned as follow-up.
  • psap-forge-notifications vault required but unused for export — can be made optional in future.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added KPI postprocessing with a KPI catalog and computed KPI results.
    • Added parsing enrichment for benchmark metrics and KPI generation via a new postprocessing plugin.
    • Introduced PSAP-compatible benchmark payload generation and writing.
    • Added MLflow metadata tags based on benchmark/model/workload/accelerator details.
    • Extended orchestration configuration with GPU type support and updated CI entrypoint wiring.
  • Bug Fixes

    • Improved hardware resolution: preserves existing gpuType and avoids overwriting when GPU type can’t be determined.
  • Documentation

    • Updated README with postprocessing/KPIs, PSAP payloads, MLflow export, and preset/config guidance.

- Create rhaiis postprocess plugin (projects/rhaiis/postprocess/) with
  22 KPIs for model-furnace parity (12 caliper baseline + 10 new:
  p99 percentiles, request counts, concurrency, duration, prompt tokens)
- Parser extends shared GuideLLMParser with p99 and request_totals
  extracted directly from benchmarks.json (no shared code changes)
- PSAP payload generator creates model-furnace compatible JSON with
  experiment metadata (model, vllm image/args, accelerator, timestamps)
- Wire run_and_postprocess() into test_phase.py with __test_labels__.yaml
- Set MLflow tags dynamically: model, accelerator, vllm image/version,
  workload, rates, guidellm config — persisted via config.set_config()
- Fix broken import: caliper_export_command → caliper_export_entrypoint
- Add caliper.postprocess config section with rhaiis plugin module

E2E tested on fournos-fg (L40S, qwen3-0.6B, rates 1,5,10, 60s max).
MLflow export verified with 17 tags and 66 KPI records at:
https://mlflow.apps.aperdomo-lab.ibm.rhperfscale.org/#/experiments/57
Handle both old (create_fournos_resolve_command) and new
(create_fournos_resolve_entrypoint) names for backward compatibility
with different forge-core container versions.
- Read gpu_type from config (rhaiis.gpu_types) instead of hardcoding h200
- Pass-through if user already set gpuType in FournosJob spec
- Return empty hardware if no gpu_type configured (exclusive cluster lock)
- Add gpu_types mapping to config.d/rhaiis.yaml
@openshift-ci

openshift-ci Bot commented Jun 19, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign ashishkamra for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@coderabbitai

coderabbitai Bot commented Jun 19, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 91976b58-bba4-42d7-ae67-abb890d57470

📥 Commits

Reviewing files that changed from the base of the PR and between c6533db and 4e8c827.

📒 Files selected for processing (1)
  • projects/rhaiis/orchestration/test_phase.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • projects/rhaiis/orchestration/test_phase.py

📝 Walkthrough

Walkthrough

Adds a Rhaiis postprocessing pipeline comprising a RhaiisParser (enriching benchmark metrics), RhaiisKpiHandler (KPI catalog and computation), PSAP payload utilities, and a RhaiisPlugin facade. Updates CI entrypoint symbols, extends resolve_hardware_request with GPU type lookup via a new get_gpu_type helper, refactors test_phase.run to invoke run_and_postprocess with post-benchmark label, PSAP, and MLflow side effects. Adds preset directive parsing for PR comments and workload/preset definitions. Config and README updated accordingly.

Changes

Rhaiis Postprocessing Pipeline and Orchestration Wiring

Layer / File(s) Summary
GPU types config, runtime lookup, and caliper postprocess config
projects/rhaiis/orchestration/config.d/rhaiis.yaml, projects/rhaiis/orchestration/runtime_config.py, projects/rhaiis/orchestration/config.yaml
gpu_types YAML mapping added for nvidia/amd/l40s; get_gpu_type helper reads it by accelerator key; caliper.postprocess block enables the plugin, parsing, and KPI output to kpis.jsonl.
CI entrypoint wiring and hardware resolution
projects/rhaiis/orchestration/ci.py
Imports updated to create_fournos_resolve_entrypoint and caliper_export_entrypoint; resolve_hardware_request early-returns when gpuType is set and otherwise resolves GPU type via runtime_config.get_gpu_type; both entrypoints registered on the main CLI group.
Postprocess parser, PSAP payload, and metric extraction
projects/rhaiis/postprocess/parser.py
RhaiisParser wraps GuideLLMParser and enriches records with percentile/request metrics from benchmarks.json; generate_psap_payload and write_psap_payload produce PSAP-compatible JSON artifacts; _split_image_tag parses image references.
KPI handler and postprocess plugin facade
projects/rhaiis/postprocess/kpis.py, projects/rhaiis/postprocess/plugin.py
RhaiisKpiHandler defines the fixed KPI catalog and compute_kpis with float coercion and timestamp emission; RhaiisPlugin implements the PostProcessingPlugin interface by delegating to the parser and handler with stubs for unused methods; get_plugin() factory provided.
Test phase lifecycle and postprocess invocation
projects/rhaiis/orchestration/test_phase.py
run refactored to return int via run_and_postprocess/do_test; _create_test_labels wired into setup; post-benchmark _generate_psap_payload and _set_mlflow_metadata helpers added with guarded try/except blocks.
Preset parsing from PR comments and workload definitions
projects/rhaiis/orchestration/pr_args.py, projects/rhaiis/orchestration/config.d/workloads.yaml, projects/rhaiis/orchestration/presets.d/presets.yaml
/test fournos rhaiis PRESET directives parsed from PR comments via parse_project_directives and _parse_test_line; ci-quick workload and preset definitions added for quick CI testing.
README documentation updates
projects/rhaiis/README.md
Config split, FournosJob YAML example with configOverrides table, updated monitoring commands, and new sections for Postprocessing/KPIs, PSAP payload, MLflow export, and Presets.

Sequence Diagram(s)

sequenceDiagram
    participant CLI
    participant do_test
    participant RhaiisParser
    participant generate_psap_payload
    participant RhaiisKpiHandler
    participant MLflow

    CLI->>do_test: run(model_key, workload_key, namespace)
    do_test->>do_test: deploy + benchmark lifecycle
    do_test->>generate_psap_payload: locate benchmarks.json, build payload
    generate_psap_payload-->>do_test: PSAP payload written to ARTIFACT_DIR
    do_test->>MLflow: _set_mlflow_metadata (guidellm_* tags, vllm_version)
    MLflow-->>do_test: config.project tags set
    Note over do_test: run_and_postprocess triggers caliper pipeline
    do_test->>RhaiisParser: parse(base_dir, nodes)
    RhaiisParser-->>do_test: enriched ParseResult
    do_test->>RhaiisKpiHandler: compute_kpis(model)
    RhaiisKpiHandler-->>do_test: KPI result dicts → kpis.jsonl
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • openshift-psap/forge#45: Introduced create_fournos_resolve_command and the hardware_resolver_func mechanism that this PR replaces with create_fournos_resolve_entrypoint and the updated resolve_hardware_request logic.
  • openshift-psap/forge#49: Main PR's test phase now uses env.NextArtifactDir("testing") for artifact isolation, which depends on the thread-local ARTIFACT_DIR mechanism added in that PR.
  • openshift-psap/forge#68: Both PRs modify the same CI orchestration and hardware resolution flow, with concurrent updates to the entrypoint symbols and GPU type resolution strategy.

Suggested labels

lgtm

Suggested reviewers

  • albertoperdomo2

Poem

🐇 Hop hop, the benchmarks are done,
KPIs shimmer, each metric hard-won!
PSAP payload lands with a thud,
MLflow tags blossom from mud.
Presets parsed from PR comments bright,
The plugin wires parser to KPI's light! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.76% 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 accurately reflects the main change: adding MLflow integration with postprocessing, KPIs, and PSAP payload generation for the rhaiis project.
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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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 `@projects/rhaiis/orchestration/ci.py`:
- Around line 29-35: The early return when hardware_spec.get("gpuType") is true
prevents the derivation and assignment of gpuCount based on tensor-parallel-size
from the vllm_args. Instead of returning immediately when gpuType is present,
continue processing to ensure both gpuType and gpuCount are properly set in the
hardware_spec before returning. Modify the logic so that the gpuCount derivation
from tp_size occurs regardless of whether gpuType was pre-specified, ensuring
the returned hardware_spec contains both values consistently.

In `@projects/rhaiis/orchestration/test_phase.py`:
- Around line 125-138: The calls to _generate_psap_payload and
_set_mlflow_metadata are post-benchmark side-effects that should not cause the
entire benchmark run to fail if they encounter errors. Wrap both function calls
in try-except blocks to catch and handle any exceptions gracefully, allowing the
benchmark to be marked as successful even if these post-processing steps fail.
Log any caught exceptions appropriately but ensure execution continues without
re-raising.

In `@projects/rhaiis/postprocess/parser.py`:
- Around line 81-83: The code always uses `benchmarks[0]` to extract metrics,
which in multi-rate runs causes all UnifiedResultRecord entries to incorrectly
use metrics from the first benchmark entry instead of their corresponding rate's
benchmark. Fix this by determining which benchmark entry corresponds to the
current record being processed (likely based on a rate index or iteration
identifier) and use that benchmark entry instead of always using `benchmarks[0]`
when assigning the bench variable and extracting metrics. Apply this same fix to
all locations where metrics are extracted from benchmarks, including the code
block mentioned at lines 95-103.
🪄 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: 5799d5ca-4111-46b2-ad25-562b6a7babe7

📥 Commits

Reviewing files that changed from the base of the PR and between 73da32b and 7f5cf02.

📒 Files selected for processing (10)
  • projects/rhaiis/orchestration/ci.py
  • projects/rhaiis/orchestration/config.d/rhaiis.yaml
  • projects/rhaiis/orchestration/config.yaml
  • projects/rhaiis/orchestration/runtime_config.py
  • projects/rhaiis/orchestration/test_phase.py
  • projects/rhaiis/postprocess/__init__.py
  • projects/rhaiis/postprocess/kpis.py
  • projects/rhaiis/postprocess/parser.py
  • projects/rhaiis/postprocess/plugin.py
  • projects/rhaiis/postprocess/psap_payload.py

Comment on lines +29 to 35
if hardware_spec.get("gpuType"):
return hardware_spec

model_key = runtime_config.get_test_model_key()
model = runtime_config.get_model(model_key)
vllm_args = model.get("vllm_args", {})
tp_size = int(vllm_args.get("tensor-parallel-size", 1))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve gpuCount when gpuType is pre-specified.

At Line 29, the early return skips the gpuCount derivation from tensor-parallel-size (Line 35). That makes the resolved hardware payload inconsistent depending on caller input and can leave an incomplete GPU request.

Suggested fix
 def resolve_hardware_request(hardware_spec: dict) -> dict:
     test_rhaiis.init()

-    if hardware_spec.get("gpuType"):
-        return hardware_spec
-
     model_key = runtime_config.get_test_model_key()
     model = runtime_config.get_model(model_key)
     vllm_args = model.get("vllm_args", {})
     tp_size = int(vllm_args.get("tensor-parallel-size", 1))
+
+    if hardware_spec.get("gpuType"):
+        hardware_spec.setdefault("gpuCount", tp_size)
+        return hardware_spec
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if hardware_spec.get("gpuType"):
return hardware_spec
model_key = runtime_config.get_test_model_key()
model = runtime_config.get_model(model_key)
vllm_args = model.get("vllm_args", {})
tp_size = int(vllm_args.get("tensor-parallel-size", 1))
model_key = runtime_config.get_test_model_key()
model = runtime_config.get_model(model_key)
vllm_args = model.get("vllm_args", {})
tp_size = int(vllm_args.get("tensor-parallel-size", 1))
if hardware_spec.get("gpuType"):
hardware_spec.setdefault("gpuCount", tp_size)
return hardware_spec
🤖 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 `@projects/rhaiis/orchestration/ci.py` around lines 29 - 35, The early return
when hardware_spec.get("gpuType") is true prevents the derivation and assignment
of gpuCount based on tensor-parallel-size from the vllm_args. Instead of
returning immediately when gpuType is present, continue processing to ensure
both gpuType and gpuCount are properly set in the hardware_spec before
returning. Modify the logic so that the gpuCount derivation from tp_size occurs
regardless of whether gpuType was pre-specified, ensuring the returned
hardware_spec contains both values consistently.

Comment thread projects/rhaiis/orchestration/test_phase.py Outdated
Comment on lines +81 to +83
bench = benchmarks[0]
metrics = bench.get("metrics", {})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Map benchmark-derived metrics to the current record, not always the first benchmark entry.

Line 81 always uses benchmarks[0]. In multi-rate runs, this copies p99/request-total fields from the first rate into every UnifiedResultRecord, producing incorrect downstream KPI values for other rates.

Also applies to: 95-103

🤖 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 `@projects/rhaiis/postprocess/parser.py` around lines 81 - 83, The code always
uses `benchmarks[0]` to extract metrics, which in multi-rate runs causes all
UnifiedResultRecord entries to incorrectly use metrics from the first benchmark
entry instead of their corresponding rate's benchmark. Fix this by determining
which benchmark entry corresponds to the current record being processed (likely
based on a rate index or iteration identifier) and use that benchmark entry
instead of always using `benchmarks[0]` when assigning the bench variable and
extracting metrics. Apply this same fix to all locations where metrics are
extracted from benchmarks, including the code block mentioned at lines 95-103.

Comment thread projects/rhaiis/orchestration/ci.py Outdated
finally:
_capture_and_cleanup(deployment_name, namespace)

_generate_psap_payload(model_cfg, accelerator, vllm_image, vllm_args, workload_key)

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.

this is already parsing/transforming the guidellm file. I think it's better to have it all in the post-processing phase, it makes it easier to share code between projects using guidellm
wdyt?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I added it because wanted have parity with how MF post processes results (and metadata). But right now only rhaiis uses it. Adding it to core is premature until llm_d also needs it. We can add it later.

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.

not to core, to projects/rhaiis/postprocess/parser.py

(nothing related to rhaiis/llmd/... should go to core, "ever")

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The parser's job is to read benchmarks.json and extract metrics. PSAP payload generation writes a new file by combining benchmarks.json with config metadata. That is why I kept it separate. Do you want me to move the implementation of _generate_psap_payload to parser.py from psap_payload?

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.

this function
is doing a parsing task (it extracts values, builds a new object, ...)

my idea is to defer that work into the post-processing step, to have a clear separation between what's the testing (=gathering data into files) and what's the post-processing (transforming data files into meaningful plots/reports/KPIs)

…-steps, move PSAP to parser

- Remove unnecessary try/except for create_fournos_resolve_entrypoint import
- Wrap _generate_psap_payload and _set_mlflow_metadata in try/except so
  post-benchmark failures don't mark the run as failed
- Move generate_psap_payload and write_psap_payload from psap_payload.py
  into parser.py, delete psap_payload.py
- Update README with postprocessing, MLflow, PSAP, Fournos, and presets docs

E2E tested on mehulvalidation (A100) and fournos-fg (L4, IBM VPC block).

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
projects/rhaiis/postprocess/parser.py (1)

179-183: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle digest-pinned image references before tag splitting.

_split_image_tag currently breaks image digests (e.g., repo/image@sha256:...) by parsing the digest suffix as a tag. This produces incorrect container_image / container_image_tag values in PSAP payloads consumed downstream.

Suggested fix
 def _split_image_tag(full_image: str) -> tuple[str, str]:
+    # Digest-pinned image: no mutable tag semantics
+    if "`@sha256`:" in full_image:
+        return full_image, "digest"
     if ":" in full_image:
         parts = full_image.rsplit(":", 1)
         return parts[0], parts[1]
     return full_image, "latest"
🤖 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 `@projects/rhaiis/postprocess/parser.py` around lines 179 - 183, The
_split_image_tag function incorrectly parses image digests (like
repo/image@sha256:abc123) by treating the digest suffix after the last colon as
a tag, producing wrong container_image and container_image_tag values. To fix
this, check for the presence of "@" symbol in the full_image string first to
detect digest-pinned references. If "@" is found, extract and remove the digest
portion before attempting to split the remaining image name by colon to find the
tag. This ensures digests are handled separately and not confused with tags.
🤖 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.

Duplicate comments:
In `@projects/rhaiis/postprocess/parser.py`:
- Around line 179-183: The _split_image_tag function incorrectly parses image
digests (like repo/image@sha256:abc123) by treating the digest suffix after the
last colon as a tag, producing wrong container_image and container_image_tag
values. To fix this, check for the presence of "@" symbol in the full_image
string first to detect digest-pinned references. If "@" is found, extract and
remove the digest portion before attempting to split the remaining image name by
colon to find the tag. This ensures digests are handled separately and not
confused with tags.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: aea3dca6-7675-4ce0-90a7-4d144cd01917

📥 Commits

Reviewing files that changed from the base of the PR and between 7f5cf02 and 9cc2eec.

📒 Files selected for processing (4)
  • projects/rhaiis/README.md
  • projects/rhaiis/orchestration/ci.py
  • projects/rhaiis/orchestration/test_phase.py
  • projects/rhaiis/postprocess/parser.py
✅ Files skipped from review due to trivial changes (1)
  • projects/rhaiis/README.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • projects/rhaiis/orchestration/ci.py
  • projects/rhaiis/orchestration/test_phase.py

@MML-coder

Copy link
Copy Markdown
Contributor Author

/test fournos rhaiis
/cluster fournos-fg
/pipeline forge-test-only

@psap-forge-bot

Copy link
Copy Markdown

🔴 Test of 'fournos_launcher submit' failed after 00 hours 22 minutes 07 seconds 🔴

• Link to the test results.

• No reports generated...

Test configuration:

/test fournos rhaiis
/cluster fournos-fg
/pipeline forge-test-only

• Failure indicator: Empty.
• Execution logs

@MML-coder

Copy link
Copy Markdown
Contributor Author

/test fournos rhaiis
/cluster forge-smoke-testing
/pipeline forge-test-only

@psap-forge-bot

Copy link
Copy Markdown

🔴 Test of 'fournos_launcher submit' failed after 00 hours 22 minutes 09 seconds 🔴

• Link to the test results.

• No reports generated...

Test configuration:

/test fournos rhaiis
/cluster forge-smoke-testing
/pipeline forge-test-only

• Failure indicator: Empty.
• Execution logs

@MML-coder

Copy link
Copy Markdown
Contributor Author

/test fournos
/cluster forge-smoke-testing
/pipeline forge-test-only
/gpu l4 1

@MML-coder

Copy link
Copy Markdown
Contributor Author

/test fournos
/cluster forge-smoke-testing
/pipeline forge-test-only
/gpu l4 1

@psap-forge-bot

Copy link
Copy Markdown

🔴 Test of 'fournos_launcher submit' failed after 00 hours 00 minutes 21 seconds 🔴

• Link to the test results.

• No reports generated...

Test configuration:

/test fournos
/cluster forge-smoke-testing
/pipeline forge-test-only
/gpu l4 1

• Failure indicator: Empty.
• Execution logs

@MML-coder

Copy link
Copy Markdown
Contributor Author

/test fournos rhaiis
/cluster forge-smoke-testing
/pipeline forge-test-only
/gpu l4 1

@psap-forge-bot

Copy link
Copy Markdown

🔴 Test of 'fournos_launcher submit' failed after 00 hours 22 minutes 10 seconds 🔴

• Link to the test results.

• No reports generated...

Test configuration:

/test fournos rhaiis
/cluster forge-smoke-testing
/pipeline forge-test-only
/gpu l4 1

• Failure indicator: Empty.
• Execution logs

@MML-coder

Copy link
Copy Markdown
Contributor Author

/test fournos rhaiis
/cluster forge-smoke-testing
/pipeline forge-test-only
/gpu l4 1

@psap-forge-bot

Copy link
Copy Markdown

🔴 Test of 'fournos_launcher submit' failed after 00 hours 22 minutes 09 seconds 🔴

• Link to the test results.

• No reports generated...

Test configuration:

/test fournos rhaiis
/cluster forge-smoke-testing
/pipeline forge-test-only
/gpu l4 1

• Failure indicator: Empty.
• Execution logs

- Add ci-quick workload profile (2 rates, 60s max, small tokens)
  to fit within CI 22-minute timeout
- Add ci-quick preset in presets.d/presets.yaml
- Add pr_args.py for parsing /test fournos rhaiis <preset> directives

Usage: /test fournos rhaiis ci-quick
@MML-coder

Copy link
Copy Markdown
Contributor Author

/test fournos rhaiis ci-quick
/cluster forge-smoke-testing
/pipeline forge-test-only
/gpu l4 1

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
projects/rhaiis/orchestration/pr_args.py (1)

48-53: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Multiple test directives overwrite each other.

If a PR comment contains multiple /test fournos rhaiis lines, only the last one's arguments will be stored in config_overrides["ci_job.args"] (line 51 overwrites on each iteration), but all matching lines are logged and added to parsed_directives. This inconsistency could confuse users who see multiple directives logged but only the last one taking effect.

Consider either:

  • Accumulating all args across multiple directives, or
  • Logging a warning when multiple directives are detected, or
  • Documenting this last-wins behavior explicitly
🤖 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 `@projects/rhaiis/orchestration/pr_args.py` around lines 48 - 53, The current
implementation overwrites config_overrides["ci_job.args"] on each loop iteration
when processing multiple test directives, meaning only the last directive's
arguments are stored even though all directives are logged and added to
parsed_directives. To fix this inconsistency, modify the code to either
accumulate all arguments from multiple directives into
config_overrides["ci_job.args"] (combining them into a list or string), or add a
warning log when multiple directives are detected to inform users that only the
last one will be used. Choose the approach based on the desired behavior:
whether multiple directives should contribute their arguments together or if
only one should be applied.
🤖 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.

Nitpick comments:
In `@projects/rhaiis/orchestration/pr_args.py`:
- Around line 48-53: The current implementation overwrites
config_overrides["ci_job.args"] on each loop iteration when processing multiple
test directives, meaning only the last directive's arguments are stored even
though all directives are logged and added to parsed_directives. To fix this
inconsistency, modify the code to either accumulate all arguments from multiple
directives into config_overrides["ci_job.args"] (combining them into a list or
string), or add a warning log when multiple directives are detected to inform
users that only the last one will be used. Choose the approach based on the
desired behavior: whether multiple directives should contribute their arguments
together or if only one should be applied.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b960488d-2902-491f-80e9-7bc9114ab5f6

📥 Commits

Reviewing files that changed from the base of the PR and between 9cc2eec and c6533db.

📒 Files selected for processing (3)
  • projects/rhaiis/orchestration/config.d/workloads.yaml
  • projects/rhaiis/orchestration/pr_args.py
  • projects/rhaiis/orchestration/presets.d/presets.yaml

@MML-coder

Copy link
Copy Markdown
Contributor Author

/test fournos rhaiis ci-quick
/cluster forge-smoke-testing
/pipeline forge-test-only
/gpu l4 1

@psap-forge-bot

Copy link
Copy Markdown

🟢 Test of 'rhaiis test' succeeded after 00 hours 03 minutes 31 seconds 🟢

• Link to the test results.

• Caliper postprocess completed but no reports generated.

Test configuration:

ci_job.cluster: forge-smoke-testing
ci_job.exclusive: true
ci_job.fjob: forge-rhaiis-20260623-030815
ci_job.hardware:
  gpuCount: 1
  gpuType: l4
ci_job.name: rhaiis ci-quick
ci_job.owner: MML-coder
project.args:
- ci-quick
project.name: rhaiis

• Execution logs

@psap-forge-bot

Copy link
Copy Markdown

🟢 Test of 'fournos_launcher submit' succeeded after 00 hours 05 minutes 02 seconds 🟢

• Link to the test results.

• No reports generated...

Test configuration:

/test fournos rhaiis ci-quick
/cluster forge-smoke-testing
/pipeline forge-test-only
/gpu l4 1
/test fournos rhaiis ci-quick

• Execution logs

Comment thread projects/rhaiis/orchestration/test_phase.py
Comment thread projects/rhaiis/orchestration/test_phase.py
- Wrap test execution with env.NextArtifactDir("testing") for scoped
  artifact directories (supports future multi-test runs)
- Add explicit return 0 after post-benchmark steps so caliper treats
  the test as successful (caliper interprets None as failure)
@MML-coder

Copy link
Copy Markdown
Contributor Author

@kpouget - can this PR be merged? CI test seems to have completed.

Comment thread projects/rhaiis/orchestration/pr_args.py Outdated
@kpouget

kpouget commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

can you please relaunch the test with the latest changes? (with the unnecessary file removed)

@MML-coder

Copy link
Copy Markdown
Contributor Author

/test fournos rhaiis ci-quick
/cluster forge-smoke-testing
/pipeline forge-test-only
/gpu l4 1
/test fournos rhaiis ci-quick

@psap-forge-bot

Copy link
Copy Markdown

🟢 Test of 'rhaiis test' succeeded after 00 hours 05 minutes 11 seconds 🟢

• Link to the test results.

• Caliper postprocess completed but no reports generated.

Test configuration:

ci_job.cluster: forge-smoke-testing
ci_job.exclusive: true
ci_job.fjob: forge-rhaiis-20260623-142943
ci_job.hardware:
  gpuCount: 1
  gpuType: l4
ci_job.name: rhaiis ci-quick
ci_job.owner: MML-coder
project.args:
- ci-quick
project.name: rhaiis

• Execution logs

@psap-forge-bot

Copy link
Copy Markdown

🟢 Test of 'fournos_launcher submit' succeeded after 00 hours 06 minutes 27 seconds 🟢

• Link to the test results.

• No reports generated...

Test configuration:

/test fournos rhaiis ci-quick
/test fournos rhaiis ci-quick
/cluster forge-smoke-testing
/pipeline forge-test-only
/gpu l4 1

• Execution logs

@MML-coder

Copy link
Copy Markdown
Contributor Author

Completed the last run

@kpouget

kpouget commented Jun 23, 2026 •

Copy link
Copy Markdown
Contributor

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label Jun 23, 2026
@MML-coder
MML-coder merged commit c4a7169 into openshift-psap:main Jun 23, 2026
6 of 7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm Indicates that a PR is ready to be merged.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants