Skip to content

Ops: AI-native reliability OS + repro bundle contracts#45

Merged
Prekzursil merged 2 commits intomainfrom
feature/ai-native-engineering-os
Feb 18, 2026
Merged

Ops: AI-native reliability OS + repro bundle contracts#45
Prekzursil merged 2 commits intomainfrom
feature/ai-native-engineering-os

Conversation

@Prekzursil
Copy link
Owner

@Prekzursil Prekzursil commented Feb 17, 2026

User description

Summary

  • adds repository and scoped AGENTS.md operating contracts for evidence-first runtime/mod work
  • introduces repro-bundle contract (tools/schemas/repro-bundle.schema.json) with collection/validation scripts
  • upgrades tools/run-live-validation.ps1 with per-run isolation, scope selection, bundle emission, strict flags, and explicit artifact paths
  • hardens issue and PR templates to require runId, bundle links, reason codes, and classifications
  • extends CI with repro-bundle schema smoke and adds policy enforcement workflow for contracts/evidence
  • adds external audit layer scaffolding: visual compare workflow/script, SonarCloud workflow/config, and jscpd duplication workflow/config
  • updates runbooks/docs/TODO to make the reliability loop executable and enforceable

Validation

  • dotnet build SwfocTrainer.sln -c Release --nologo
  • dotnet test tests/SwfocTrainer.Tests/SwfocTrainer.Tests.csproj -c Release --no-build --filter "FullyQualifiedName!~SwfocTrainer.Tests.Profiles.Live&FullyQualifiedName!~RuntimeAttachSmokeTests" --nologo
  • powershell.exe -NoProfile -ExecutionPolicy Bypass -File "tools/validate-policy-contracts.ps1"
  • powershell.exe -NoProfile -ExecutionPolicy Bypass -File "tools/validate-repro-bundle.ps1" -BundlePath "tools/fixtures/repro_bundle_sample.json" -SchemaPath "tools/schemas/repro-bundle.schema.json" -Strict
  • powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "& './tools/run-live-validation.ps1' -Configuration Release -NoBuild -Scope TACTICAL -RunId 'smoke-20260217-7' -EmitReproBundle \$true"
  • powershell.exe -NoProfile -ExecutionPolicy Bypass -File "tools/compare-visual-pack.ps1" -BaselineDir "artifacts/visual-baselines" -CandidateDir "TestResults/runs/smoke-20260217-7" -OutputPath "TestResults/runs/smoke-20260217-7/visual-compare.json"

Linked Issues


PR Type

Enhancement, Documentation


Description

  • Introduces repro-bundle contract with collection/validation scripts for evidence-first runtime/mod work

  • Adds scoped AGENTS.md operating contracts for repository, runtime, tooling, and tests

  • Upgrades live-validation tooling with per-run isolation, scope selection, bundle emission, and strict validation

  • Extends CI with repro-bundle schema smoke test and policy enforcement workflow

  • Adds external audit layer: visual compare workflow/script, SonarCloud workflow/config, jscpd duplication detection

  • Hardens issue/PR templates to require runId, bundle links, reason codes, and classifications

  • Updates runbooks and documentation to make reliability loop executable and enforceable


Diagram Walkthrough

flowchart LR
  A["Live Validation Run"] -->|emits| B["Repro Bundle JSON/MD"]
  B -->|validated by| C["Schema + Semantic Checks"]
  C -->|classified as| D["passed/failed/blocked"]
  D -->|attached to| E["Issue/PR Evidence"]
  E -->|enforced by| F["Policy Contract Workflow"]
  A -->|generates| G["Launch Context + Process Snapshot"]
  G -->|feeds| H["Runtime Mode Detection"]
  H -->|informs| D
  I["External Audits"] -->|SonarCloud/jscpd/Visual| J["Quality Signals"]
  J -->|augments| E
Loading

File Walkthrough

Relevant files
Enhancement
14 files
collect-mod-repro-bundle.ps1
New script to collect reproducible mod/runtime bundles     
+428/-0 
compare-visual-pack.ps1
New visual artifact comparison and diff detection               
+110/-0 
run-live-validation.ps1
Enhanced with per-run isolation, scope selection, bundle emission
+220/-47
validate-policy-contracts.ps1
New policy contract validation for AGENTS.md and templates
+90/-0   
validate-repro-bundle.ps1
New schema and semantic validation for repro bundles         
+133/-0 
bug.yml
Hardened to require runId, bundle links, and classification
+47/-2   
calibration.yml
Added runId and bundle evidence fields with validation     
+30/-0   
pull_request_template.md
Added affected profiles and reliability evidence sections
+17/-0   
ci.yml
Added repro-bundle schema smoke test step                               
+5/-0     
duplication-check.yml
New jscpd duplication detection workflow                                 
+35/-0   
policy-contract.yml
New policy contract validation and PR evidence enforcement
+67/-0   
sonarcloud.yml
New SonarCloud code quality scanning workflow                       
+39/-0   
visual-audit.yml
New visual pack comparison and audit workflow                       
+72/-0   
repro-bundle.schema.json
New JSON schema for repro bundle contract validation         
+103/-0 
Configuration changes
2 files
.jscpd.json
New jscpd configuration for duplication detection               
+30/-0   
sonar-project.properties
New SonarCloud project configuration                                         
+10/-0   
Documentation
13 files
AGENTS.md
New repository-level AI-native operating contract               
+38/-0   
CONTRIBUTING.md
Added repro bundle evidence requirement for runtime changes
+1/-0     
README.md
Added repro bundle tooling section and usage examples       
+9/-0     
TODO.md
Updated with bundle evidence format and reliability rules
+6/-1     
AI_NATIVE_TEAM_OPERATING_MODEL.md
New evidence-first operating loop and decision rules         
+40/-0   
EXTERNAL_TOOLS_SETUP.md
New guide for SonarCloud and Applitools integration           
+28/-0   
LIVE_VALIDATION_RUNBOOK.md
Refactored with scope selection and bundle validation steps
+52/-17 
ROADMAP_WORKFLOW.md
Added board lane policy and bundle evidence closure rules
+8/-0     
TEST_PLAN.md
Added tooling contract tests and bundle validation examples
+18/-11 
VISUAL_AUDIT_RUNBOOK.md
New visual pack naming and comparison flow guide                 
+33/-0   
AGENTS.md
New runtime-specific agent operating contract                       
+18/-0   
AGENTS.md
New tests-specific agent operating contract                           
+17/-0   
AGENTS.md
New tooling-specific agent operating contract                       
+17/-0   
Tests
1 files
repro_bundle_sample.json
New sample repro bundle for schema validation testing       
+44/-0   

Summary by CodeRabbit

  • New Features

    • Issue and PR templates now require repro-bundle evidence, run ID, classification, and launch context.
    • CI workflows added: duplication check, SonarCloud scan, visual-audit, and policy-based PR enforcement.
    • New tooling: repro-bundle generation, repro-bundle validation, visual-pack comparison, and scoped live-validation runs.
  • Documentation

    • Operating model, runbooks, tooling setup, visual-audit, and test plan updated with repro-bundle guidance and evidence-first workflows.

Policy Evidence Tokens

Repro bundle JSON: tools/fixtures/repro_bundle_sample.json
Classification: justified skip (ops/docs/tooling slice; no new live runtime behavior in this PR)

@devloai
Copy link

devloai bot commented Feb 17, 2026

Unable to trigger custom agent "Code Reviewer". You have run out of credits 😔
Please upgrade your plan or buy additional credits from the subscription page.

@github-actions github-actions bot added area:runtime Runtime attach, memory actions, symbol resolution area:ci CI/CD and automation area:tooling Scripts and developer tooling area:docs Documentation/process related work. labels Feb 17, 2026
@coderabbitai
Copy link

coderabbitai bot commented Feb 17, 2026

📝 Walkthrough

Walkthrough

Introduces an evidence-first runtime debugging framework: repro-bundle schema, collection and validation tooling, CI/policy workflows enforcing PR evidence, updated issue/PR templates, visual-audit and duplication-check workflows, agent operating contracts, runbooks, and supporting scripts and docs.

Changes

Cohort / File(s) Summary
Issue & PR Templates
.github/ISSUE_TEMPLATE/bug.yml, .github/ISSUE_TEMPLATE/calibration.yml, .github/pull_request_template.md
Added required fields for run_id/repro-bundle paths, classification, and launch_context; updated prompts and checklists to require repro-bundle evidence.
GitHub Actions Workflows
.github/workflows/ci.yml, .github/workflows/duplication-check.yml, .github/workflows/policy-contract.yml, .github/workflows/sonarcloud.yml, .github/workflows/visual-audit.yml
Added workflows: CI step to validate repro-bundle schema, duplication-check (jscpd), policy-contract (policy validation + PR evidence enforcement), SonarCloud scan, and a Windows visual-audit workflow.
Repro Bundle Tooling & Schemas
tools/collect-mod-repro-bundle.ps1, tools/validate-repro-bundle.ps1, tools/schemas/repro-bundle.schema.json, tools/fixtures/repro_bundle_sample.json
Added collection script to assemble repro-bundle.json/.md (process snapshot, launchContext, runtimeMode, liveTests, diagnostics, classification), a schema, a validator with strict checks, and a sample fixture.
Live Validation & Visual Comparison
tools/run-live-validation.ps1, tools/compare-visual-pack.ps1, tools/fixtures/repro_bundle_sample.json
Refactored live validation to support RunId/Scope/EmitReproBundle and isolated run directories; added visual comparator to produce visual-compare JSON reports.
Policy & Static Analysis Config
tools/validate-policy-contracts.ps1, .jscpd.json, sonar-project.properties
Added policy contract validator script, jscpd configuration for duplication detection, and SonarQube project properties for .NET analysis.
Agent Contracts & Operating Model
AGENTS.md, src/.../AGENTS.md, tests/AGENTS.md, tools/AGENTS.md, docs/AI_NATIVE_TEAM_OPERATING_MODEL.md
New agent governance docs and an AI-Native operating model describing evidence requirements, lifecycle, ownership, and PR readiness criteria.
Runbooks, Docs & Guides
docs/LIVE_VALIDATION_RUNBOOK.md, docs/VISUAL_AUDIT_RUNBOOK.md, docs/EXTERNAL_TOOLS_SETUP.md, docs/TEST_PLAN.md, docs/ROADMAP_WORKFLOW.md, README.md, CONTRIBUTING.md, TODO.md
Extensive documentation updates: live validation runbook, visual audit runbook, external tools setup, testing plan, roadmap/workflow rules, README/CONTRIBUTING guidance, and TODO reliability rules.
Misc: New Helpers & Artifacts
tools/collect-mod-repro-bundle.ps1 (functions), tools/validate-repro-bundle.ps1 (helpers), tools/compare-visual-pack.ps1, tools/run-live-validation.ps1
Added robust helper functions, strict validation helpers, and integration points enabling repro bundle creation, validation, and visual comparison.

Sequence Diagram(s)

sequenceDiagram
    participant Dev as Developer (PR/Run)
    participant Run as Live Validation (run-live-validation.ps1)
    participant Collector as Collector (collect-mod-repro-bundle.ps1)
    participant Repo as Repository (repro-bundle.json/.md)
    participant CI as GitHub Actions (ci.yml / policy-contract.yml)
    participant Validator as Validator (validate-repro-bundle.ps1)
    Dev->>Run: trigger live validation (RunId, Scope, EmitReproBundle)
    Run->>Collector: assemble repro bundle (process, tests, diagnostics)
    Collector->>Repo: write repro-bundle.json and repro-bundle.md
    Dev->>CI: open PR / push
    CI->>Repo: fetch repro-bundle path from PR body or artifacts
    CI->>Validator: validate repro-bundle.json against schema (Strict optional)
    Validator-->>CI: validation result (pass/fail + errors)
    CI-->>Dev: enforce policy (fail PR if required evidence missing/invalid)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related issues

Poem

🐰 I stitched a bundle, tidy and neat,

JSON and MD for every test beat.
Validators hum, workflows take flight—
Evidence first keeps the runtime bright. 🥕✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: introducing an AI-native reliability OS with repro bundle contracts.
Description check ✅ Passed The description is comprehensive with clear Summary, Scope (marked CI/Tooling and Docs only), detailed Validation Evidence with commands, and Linked Issues. However, Runtime Safety Checklist and Metadata/Contract Changes sections are not explicitly completed.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/ai-native-engineering-os

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 and usage tips.

@qodo-code-review
Copy link

qodo-code-review bot commented Feb 17, 2026

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
Sensitive artifact upload

Description: The workflow uploads ${{ steps.paths.outputs.candidate }} (the full visual pack directory)
as an artifact, which could unintentionally exfiltrate sensitive
on-screen/user/environment data if captures include PII or secrets from the runner or game
environment. visual-audit.yml [65-72]

Referred Code
- name: Upload visual compare report
  if: always()
  uses: actions/upload-artifact@v4
  with:
    name: visual-compare
    path: |
      ${{ steps.paths.outputs.output }}
      ${{ steps.paths.outputs.candidate }}
Ticket Compliance
🟡
🎫 #44
🟢 Configure `sonar-project.properties` for the repository.
Add `.github/workflows/sonarcloud.yml` and guard execution on presence of `SONAR_TOKEN`.
Add .jscpd.json and a .github/workflows/duplication-check.yml workflow that uploads
duplication reports.
Document external tool secrets and operational usage in `docs/EXTERNAL_TOOLS_SETUP.md`.
Provide evidence via a SonarCloud workflow run (when secret is configured).
Provide evidence via a duplication-check artifact named `jscpd-report`.
🟡
🎫 #43
🟢 Add `docs/VISUAL_AUDIT_RUNBOOK.md` defining visual-pack naming and baseline contract.
Add tools/compare-visual-pack.ps1 that generates a compare report JSON with
changed/new/missing breakdown.
Add .github/workflows/visual-audit.yml supporting manual run by run_id and uploading
compare artifacts.
Provide evidence that pwsh ./tools/compare-visual-pack.ps1 -BaselineDir -CandidateDir
-OutputPath works as documented.
🟡
🎫 #41
🟢 Add `tools/schemas/repro-bundle.schema.json` with required fields and enums.
Add tools/collect-mod-repro-bundle.ps1 that emits repro-bundle.json and repro-bundle.md.
Add tools/validate-repro-bundle.ps1 that validates schema/semantic rules and returns
nonzero on failure.
Update tools/run-live-validation.ps1 to support RunId, Scope, EmitReproBundle,
FailOnMissingArtifacts, Strict.
Provide evidence that pwsh ./tools/validate-repro-bundle.ps1 -BundlePath
tools/fixtures/repro_bundle_sample.json -SchemaPath tools/schemas/repro-bundle.schema.json
-Strict succeeds.
🟡
🎫 #40
🟢 Add root and scoped AGENTS.md files and ensure they pass
tools/validate-policy-contracts.ps1.
Add docs/AI_NATIVE_TEAM_OPERATING_MODEL.md defining the
intake->bundle->classify->fix->evidence->close loop.
Update `docs/ROADMAP_WORKFLOW.md` with lane policy and runtime closure evidence rule.
Provide evidence by running `pwsh ./tools/validate-policy-contracts.ps1`.
🟢
🎫 #39
🟢 Require a repro bundle contract (repro-bundle.json and repro-bundle.md) for runtime/mod
issue readiness.
Enforce PR policy requiring reliability evidence for runtime/tooling/tests surfaces.
Add AGENTS contracts at root and scoped locations.
Ensure CI validates launch-context and repro-bundle fixture contracts.
Integrate external quality signals (visual compare, SonarCloud, duplication) and link them
to actionable issues.
🟡
🎫 #42
🟢 Update CI to validate repro-bundle fixture sample in addition to launch-context fixture.
Add a `policy-contract.yml` check validating AGENTS/templates contracts.
Add PR evidence enforcement that fails when runtime/tooling/tests changes lack reliability
evidence fields.
Update PR template to include affected profile and reason-code evidence sections.
Provide evidence via a CI run with `build-test` and `policy-contract` checks green.
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Swallowed exception context: Launch-context detection failures are caught and converted into a generic reason code
without preserving actionable failure detail, which may hinder debugging and root-cause
analysis.

Referred Code
catch {
    return [PSCustomObject]@{
        profileId = $null
        reasonCode = "launch_context_detection_failed"
        confidence = 0.0
        launchKind = "Unknown"
    }
}

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status:
Verbose warning detail: The warning emitted on repro-bundle generation/validation failure includes raw exception
messages that could expose environment/internal tool details depending on upstream errors.

Referred Code
catch {
    Write-Warning ("Repro bundle generation/validation failed: {0}" -f $_.Exception.Message)
    $fatalError = $_.Exception
}

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status:
Potential sensitive data: The repro bundle and markdown summary persist full process commandLine and path values
which can contain usernames, tokens, or other sensitive arguments depending on the runtime
environment.

Referred Code
$snapshot.Add([PSCustomObject]@{
    pid = [int]$proc.ProcessId
    name = [string]$proc.Name
    path = [string]$proc.ExecutablePath
    commandLine = [string]$proc.CommandLine
    steamModIds = $steamIds

Learn more about managing compliance generic rules or creating your own custom rules

  • Update
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@codacy-production
Copy link

codacy-production bot commented Feb 17, 2026

Codacy's Analysis Summary

39 new issues (≤ 0 issue)
0 new security issue

Review Pull Request in Codacy →

AI Reviewer available: add the codacy-review label to get contextual insights without leaving GitHub.

@qodo-code-review
Copy link

qodo-code-review bot commented Feb 17, 2026

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Consider a simpler, more robust implementation

The new reliability process relies on a complex system of PowerShell scripts for
tasks that could be simplified. Consider consolidating this logic into a single,
more powerful language like Python and using standard libraries to reduce
complexity and improve maintainability.

Examples:

tools/validate-repro-bundle.ps1 [1-133]
param(
    [Parameter(Mandatory = $true)][string]$BundlePath,
    [string]$SchemaPath = "tools/schemas/repro-bundle.schema.json",
    [switch]$Strict
)

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

if (-not (Test-Path -Path $BundlePath)) {

 ... (clipped 123 lines)
tools/collect-mod-repro-bundle.ps1 [1-428]
param(
    [Parameter(Mandatory = $true)][string]$RunId,
    [Parameter(Mandatory = $true)][string]$RunDirectory,
    [Parameter(Mandatory = $true)][string]$SummaryPath,
    [Parameter(Mandatory = $true)][ValidateSet("AOTR", "ROE", "TACTICAL", "FULL")][string]$Scope,
    [string]$ProfileRoot = "profiles/default",
    [string]$StartedAtUtc = ""
)

Set-StrictMode -Version Latest

 ... (clipped 418 lines)

Solution Walkthrough:

Before:

# In tools/run-live-validation.ps1 (PowerShell)
# ... run dotnet tests and collect TRX summaries ...

# Call another PowerShell script to assemble the data
& (Join-Path $PSScriptRoot "collect-mod-repro-bundle.ps1") `
    -RunId $RunId `
    -RunDirectory $runResultsDirectory `
    -SummaryPath $summaryPath `
    -Scope $Scope

# Call a third PowerShell script to validate the generated JSON
# This script manually re-implements schema validation logic
& (Join-Path $PSScriptRoot "validate-repro-bundle.ps1") `
    -BundlePath $bundlePath `
    -SchemaPath "tools/schemas/repro-bundle.schema.json" `
    -Strict:$Strict

After:

# In a hypothetical run_validation.py (Python)
# ... run dotnet tests and collect TRX summaries ...

# Business logic to assemble the bundle is now in Python
bundle_data = collect_repro_bundle(run_id, summaries, scope)

# Use a standard library for JSON schema validation
# instead of a custom script
with open("tools/schemas/repro-bundle.schema.json") as f:
    schema = json.load(f)

try:
    jsonschema.validate(instance=bundle_data, schema=schema)
    # Perform stricter semantic checks if needed
    if strict:
        validate_strict_rules(bundle_data)
except jsonschema.ValidationError as e:
    print(f"Bundle validation failed: {e.message}")
Suggestion importance[1-10]: 9

__

Why: This is a high-impact architectural suggestion that correctly identifies significant complexity and maintainability issues in the new tooling, which spans multiple files and forms the core of the PR.

High
General
Fix dropdown validations indent

Fix the indentation of the validations block for the classification dropdown in
the bug report template. This ensures the field is correctly marked as required.

.github/ISSUE_TEMPLATE/bug.yml [41-52]

 - type: dropdown
   id: classification
   attributes:
     label: Bundle classification
     options:
       - passed
       - skipped
       - failed
       - blocked_environment
       - blocked_profile_mismatch
-   validations:
-     required: true
+  validations:
+    required: true
  • Apply / Chat
Suggestion importance[1-10]: 8

__

Why: This suggestion correctly identifies and fixes a YAML indentation error that would prevent the required: true validation from being applied to the classification dropdown. This is a critical fix to ensure the issue template functions as intended.

Medium
Refine strict validation for passed classification

Refine the -Strict validation logic for a passed classification. Instead of
requiring at least one Passed test, the check should verify that there are no
Failed tests, which more accurately reflects a successful run.

tools/validate-repro-bundle.ps1 [114-123]

 if ($Strict) {
-    $hasPassed = (@($liveTests | Where-Object { $_.outcome -eq "Passed" })).Count -gt 0
-    if ($bundle.classification -eq "passed" -and -not $hasPassed) {
-        Add-Error "classification=passed requires at least one passed live test"
+    $hasFailed = (@($liveTests | Where-Object { $_.outcome -eq "Failed" })).Count -gt 0
+    if ($bundle.classification -eq "passed" -and $hasFailed) {
+        Add-Error "classification=passed requires no failed live tests"
     }
 
     if ($bundle.classification -eq "blocked_environment" -and (@($bundle.processSnapshot)).Count -gt 0) {
         Add-Error "classification=blocked_environment requires empty processSnapshot"
     }
 }
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies a potential logic issue in the -Strict validation where a passed classification could be incorrectly flagged as an error. Changing the check to ensure no tests have Failed is a more robust and accurate way to determine a successful run, improving the validation logic.

Medium
Case-insensitive policy text search

Update the Require-Contains function to perform a case-insensitive search. This
prevents validation failures due to casing differences in policy files.

tools/validate-policy-contracts.ps1 [21-38]

 function Require-Contains {
     param(
         [string]$Path,
         [string[]]$Needles
     )
 
     if (-not (Test-Path -Path $Path)) {
         Add-Error "missing file: $Path"
         return
     }
 
-    $content = Get-Content -Raw -Path $Path
+    $content = (Get-Content -Raw -Path $Path).ToLower()
     foreach ($needle in $Needles) {
-        if (-not $content.Contains($needle)) {
+        if (-not $content.Contains($needle.ToLower())) {
             Add-Error "$Path missing required text: $needle"
         }
     }
 }
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: This suggestion correctly points out that the policy contract validation is case-sensitive, which could lead to false negatives. Making the check case-insensitive improves the robustness and reliability of this important new validation script.

Medium
Preserve error details on script failure

In Detect-LaunchContext, enhance the catch block to include the exception
message in the returned object. This will provide more detailed diagnostics when
the Python script fails, aiding in debugging.

tools/collect-mod-repro-bundle.ps1 [120-185]

 function Detect-LaunchContext {
     param(
         [object]$Process,
         [string]$ProfileRootPath
     )
 ...
     try {
         $output = & $pythonCmd[0] @args 2>&1
         if ($LASTEXITCODE -ne 0) {
-            throw "detect-launch-context.py exited with $LASTEXITCODE"
+            throw "detect-launch-context.py exited with $LASTEXITCODE. Output: $($output | Out-String)"
         }
 ...
     }
     catch {
         return [PSCustomObject]@{
             profileId = $null
             reasonCode = "launch_context_detection_failed"
             confidence = 0.0
             launchKind = "Unknown"
+            detail = $_.Exception.Message
         }
     }
 }

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 6

__

Why: This is a good suggestion for improving the debuggability of the Detect-LaunchContext function. Capturing the exception message in the output object provides valuable context for diagnosing failures in the Python script execution, which is a key part of the new tooling.

Low
Possible issue
Avoid non-deterministic process selection fallback

In Get-PreferredProcess, replace the non-deterministic fallback of returning the
first process with returning $null when no preferred process is found. This
improves reliability as the calling logic already handles a null value.

tools/collect-mod-repro-bundle.ps1 [74-118]

 function Get-PreferredProcess {
     param([System.Collections.IEnumerable]$Snapshot)
 ...
     $swfoc = $items | Where-Object { (Get-ProcessNameValue $_) -ieq "swfoc.exe" } | Select-Object -First 1
     if ($null -ne $swfoc) {
         return $swfoc
     }
 
-    return $items[0]
+    return $null
 }

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 7

__

Why: This is a valid suggestion that correctly identifies a non-deterministic fallback in Get-PreferredProcess. Returning $null as proposed makes the script more robust and prevents potential hard-to-debug errors where the wrong game process is selected for analysis.

Medium
Immediately exit on bundle errors

Modify the repro bundle generation logic to fail fast. On error, use Write-Error
and exit 1 to immediately stop the script instead of continuing to generate
issue templates.

tools/run-live-validation.ps1 [351-380]

 if ($EmitReproBundle) {
     try {
         & (Join-Path $PSScriptRoot "collect-mod-repro-bundle.ps1") `
             -RunId $RunId `
             -RunDirectory $runResultsDirectory `
             -SummaryPath $summaryPath `
             -Scope $Scope `
             -ProfileRoot $ProfileRoot `
             -StartedAtUtc $runStartedUtc
 
-        $collectExitCode = if (Get-Variable -Name LASTEXITCODE -Scope Global -ErrorAction SilentlyContinue) { [int]$global:LASTEXITCODE } else { 0 }
+        $collectExitCode = $LASTEXITCODE
         if ($collectExitCode -ne 0) {
-            throw "collect-mod-repro-bundle.ps1 failed with exit code $collectExitCode"
+            Write-Error "collect-mod-repro-bundle.ps1 failed with exit code $collectExitCode"
+            exit 1
         }
 
         & (Join-Path $PSScriptRoot "validate-repro-bundle.ps1") `
             -BundlePath $bundlePath `
             -SchemaPath "tools/schemas/repro-bundle.schema.json" `
             -Strict:$Strict
 
-        $validateExitCode = if (Get-Variable -Name LASTEXITCODE -Scope Global -ErrorAction SilentlyContinue) { [int]$global:LASTEXITCODE } else { 0 }
+        $validateExitCode = $LASTEXITCODE
         if ($validateExitCode -ne 0) {
-            throw "validate-repro-bundle.ps1 failed with exit code $validateExitCode"
+            Write-Error "validate-repro-bundle.ps1 failed with exit code $validateExitCode"
+            exit 1
         }
     }
     catch {
-        Write-Warning ("Repro bundle generation/validation failed: {0}" -f $_.Exception.Message)
-        $fatalError = $_.Exception
+        Write-Error ("Repro bundle generation/validation failed: {0}" -f $_.Exception.Message)
+        exit 1
     }
 }
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies that the script continues execution after a bundle generation failure. Proposing a fail-fast mechanism with Write-Error and exit 1 is a significant improvement, making the script's behavior in CI more immediate and clear, and preventing subsequent steps from running unnecessarily.

Medium
  • Update

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tools/run-live-validation.ps1 (1)

116-127: ⚠️ Potential issue | 🟡 Minor

Assigning to $args shadows PowerShell's automatic variable.

$args is a built-in automatic variable in PowerShell that holds unbound arguments. Overwriting it can cause unexpected behavior if this function ever needs to access unbound parameters or is called in certain contexts.

🛠️ Rename to avoid shadowing
-    $args = @(
+    $dotnetArgs = @(
         "test",
         "tests/SwfocTrainer.Tests/SwfocTrainer.Tests.csproj",
         "-c", $Configuration,
         "--filter", $Filter,
         "--logger", "trx;LogFileName=$TrxName",
         "--results-directory", $runResultsDirectory
     )

     if ($NoBuild) {
-        $args += "--no-build"
+        $dotnetArgs += "--no-build"
     }

-    & $dotnetExe `@args`
+    & $dotnetExe `@dotnetArgs`
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/run-live-validation.ps1` around lines 116 - 127, The script currently
assigns to the automatic PowerShell variable $args which shadows built-in
unbound-argument behavior; rename that variable (e.g., $testArgs or $dotnetArgs)
wherever it's defined and used (the array that contains "test", the csproj path,
configuration, filter, logger, results-directory and the conditional append of
"--no-build") and update all subsequent references to the new name so the script
no longer overwrites the automatic $args variable.
🧹 Nitpick comments (4)
.github/workflows/duplication-check.yml (1)

29-35: Consider adding if-no-files-found handling for artifact upload robustness.

The .jscpd.json correctly configures output to jscpd-report, which matches the upload path. However, adding explicit handling improves workflow resilience against unexpected edge cases.

Suggested improvement
       - name: Upload jscpd report
         if: always()
         uses: actions/upload-artifact@v4
         with:
           name: jscpd-report
           path: |
             jscpd-report
+          if-no-files-found: warn
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/duplication-check.yml around lines 29 - 35, The artifact
upload step "Upload jscpd report" using actions/upload-artifact@v4 should handle
missing files to avoid failing the workflow; update that step (the step named
"Upload jscpd report", which currently uploads path "jscpd-report") to include
the upload-artifact input if-no-files-found (e.g., "warn" or "ignore") under its
with: block so the action won't hard-fail when the jscpd-report directory/file
is absent.
tools/compare-visual-pack.ps1 (1)

109-110: Consider Write-Information for better compatibility (optional).

PSScriptAnalyzer flags Write-Host usage. For CI scripts this is generally acceptable since the output is intended for console display. However, Write-Information with -InformationAction Continue provides better compatibility across different PowerShell hosts if needed in the future.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/compare-visual-pack.ps1` around lines 109 - 110, Replace the two
Write-Host calls with Write-Information to satisfy PSScriptAnalyzer and improve
host compatibility: emit the same messages using Write-Information and include
-InformationAction Continue so the output appears in console-host and CI
environments; locate the lines that reference the OutputPath and status
variables and change those invocations (the current Write-Host "visual compare
report: $OutputPath" and Write-Host "status: $status") to use Write-Information
with a descriptive message and -InformationAction Continue.
tools/validate-repro-bundle.ps1 (1)

76-93: Redundant trxPath empty check.

Line 82 calls Require-Field -Object $test -Field "trxPath" (without -AllowNull), which already validates that trxPath is non-null and non-empty. Lines 90-92 then redundantly check for empty trxPath again.

♻️ Remove redundant validation
     if ($allowedOutcomes -notcontains [string]$test.outcome) {
         Add-Error "liveTests[$($test.name)] outcome invalid: $($test.outcome)"
     }
-
-    if ([string]::IsNullOrWhiteSpace([string]$test.trxPath)) {
-        Add-Error "liveTests[$($test.name)] trxPath is empty"
-    }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/validate-repro-bundle.ps1` around lines 76 - 93, The trxPath emptiness
check is redundant because Require-Field -Object $test -Field "trxPath" already
enforces non-null/non-empty; remove the extra block that calls
[string]::IsNullOrWhiteSpace([string]$test.trxPath) and its Add-Error call so
only Require-Field validates trxPath for items in liveTests, leaving the other
validations (Require-Field for name/outcome/message and outcome membership
check) intact.
tools/collect-mod-repro-bundle.ps1 (1)

16-33: Consider extracting shared Resolve-PythonCommand function.

This function is duplicated between collect-mod-repro-bundle.ps1 and run-live-validation.ps1. Consider extracting it to a shared module (e.g., tools/lib/resolve-commands.ps1) and dot-sourcing it from both scripts to reduce duplication and simplify maintenance.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/collect-mod-repro-bundle.ps1` around lines 16 - 33, Extract the
duplicated Resolve-PythonCommand function into a single shared script module
(e.g., resolve-commands.ps1) and remove the local copies from both scripts; then
dot-source the new module from each script so they call the centralized
Resolve-PythonCommand implementation. Ensure the new module exports the same
function name (Resolve-PythonCommand), keep the exact return shape (arrays for
command + args), and update both calling scripts to rely on the shared function
instead of their inline copies.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/ISSUE_TEMPLATE/bug.yml:
- Around line 71-84: The YAML descriptions for the fields with id
"launch_context" and "diagnostics" are not quoted, which can break YAML parsing;
update the attributes.description values for launch_context and diagnostics to
be wrapped in quotes (e.g., "Include launchKind, reasonCode, confidence, and
detected STEAMMOD/MODPATH data." and "Include
runtimeModeHint/runtimeModeEffective/runtimeModeReasonCode, dependency state,
helper readiness, symbol health summary.") so the strings are valid YAML while
preserving the existing text.
- Around line 21-40: The YAML in the issue template uses raw backticks in the
description fields which breaks parsing; update the three description values
(the ones for the fields with id repro_bundle_json and repro_bundle_md and the
earlier description at line 21) to be valid YAML strings by quoting them (single
or double quotes) or escaping the backticks so the literal text like
`TestResults/runs/<runId>/repro-bundle.json` and
`TestResults/runs/<runId>/repro-bundle.md` are wrapped in quotes; ensure all
three description placeholders/values are changed consistently so the template
parses correctly.

In @.github/workflows/visual-audit.yml:
- Around line 59-63: The step "Applitools availability note" uses a step-level
if with the secrets context which is not allowed; change to export the secret
into an env var (e.g., set env: APPLITOOLS_API_KEY: ${{
secrets.APPLITOOLS_API_KEY }} at the job or step level) and remove the
step-level if, or keep the env mapping and replace the if with a runtime check
inside the pwsh script (use $env:APPLITOOLS_API_KEY in the "run" block) so the
availability message only prints when the variable is present.

In `@tools/collect-mod-repro-bundle.ps1`:
- Around line 42-51: The variable $matches shadows PowerShell's automatic
$matches and should be renamed to avoid confusion; update the call to
[regex]::Matches($CommandLine, "STEAMMOD\s*=\s*([0-9]{4,})", ...) to assign to a
new name (e.g., $regexMatches) and update the foreach loop to iterate over that
new variable (change foreach ($match in $matches) to foreach ($match in
$regexMatches)) while leaving all other logic (the HashSet $ids, $match.Groups
usage, and the return) unchanged.
- Around line 145-156: The script is assigning to the automatic PowerShell
variable $args which causes shadowing; rename that variable (e.g. $pythonArgs)
and update all uses in this block so you build the argument array into
$pythonArgs instead of $args (modify the $args += lines and any later invocation
that consumes it), keeping the logic that appends $pythonCmd[1..] and the
tools/detect-launch-context.py arguments that use $Process and $ProfileRootPath.
- Around line 397-425: The here-string written to $bundleMdPath currently
escapes nine variables (e.g., `$RunId`, `$Scope`, `$classification`,
`$($launchContext.profileId)`, `$($launchContext.reasonCode)`,
`$($launchContext.confidence)`, `$($launchContext.launchKind)`,
`$($runtimeMode.effective)`, `$($runtimeMode.reasonCode)`) with backticks which
prevents PowerShell interpolation; remove the backticks so the here-string
interpolates those expressions directly (leave the surrounding @"..."@
here-string intact) so the generated repro-bundle.md contains the actual runtime
values instead of literal variable names.

In `@tools/run-live-validation.ps1`:
- Line 5: The [switch] parameter $NoBuild currently defaults to $true which
makes the flag unusable; rename the parameter to [switch]$Build (default $false)
or change $NoBuild to default $false, then update all usages where the script
checks $NoBuild (or where you previously skipped the build) to use the new
$Build logic (invert the conditional: run the build when $Build is true, or
replace checks like "if (-not $NoBuild)" with "if ($Build)") so callers can
simply pass -Build to opt into building.

---

Outside diff comments:
In `@tools/run-live-validation.ps1`:
- Around line 116-127: The script currently assigns to the automatic PowerShell
variable $args which shadows built-in unbound-argument behavior; rename that
variable (e.g., $testArgs or $dotnetArgs) wherever it's defined and used (the
array that contains "test", the csproj path, configuration, filter, logger,
results-directory and the conditional append of "--no-build") and update all
subsequent references to the new name so the script no longer overwrites the
automatic $args variable.

---

Nitpick comments:
In @.github/workflows/duplication-check.yml:
- Around line 29-35: The artifact upload step "Upload jscpd report" using
actions/upload-artifact@v4 should handle missing files to avoid failing the
workflow; update that step (the step named "Upload jscpd report", which
currently uploads path "jscpd-report") to include the upload-artifact input
if-no-files-found (e.g., "warn" or "ignore") under its with: block so the action
won't hard-fail when the jscpd-report directory/file is absent.

In `@tools/collect-mod-repro-bundle.ps1`:
- Around line 16-33: Extract the duplicated Resolve-PythonCommand function into
a single shared script module (e.g., resolve-commands.ps1) and remove the local
copies from both scripts; then dot-source the new module from each script so
they call the centralized Resolve-PythonCommand implementation. Ensure the new
module exports the same function name (Resolve-PythonCommand), keep the exact
return shape (arrays for command + args), and update both calling scripts to
rely on the shared function instead of their inline copies.

In `@tools/compare-visual-pack.ps1`:
- Around line 109-110: Replace the two Write-Host calls with Write-Information
to satisfy PSScriptAnalyzer and improve host compatibility: emit the same
messages using Write-Information and include -InformationAction Continue so the
output appears in console-host and CI environments; locate the lines that
reference the OutputPath and status variables and change those invocations (the
current Write-Host "visual compare report: $OutputPath" and Write-Host "status:
$status") to use Write-Information with a descriptive message and
-InformationAction Continue.

In `@tools/validate-repro-bundle.ps1`:
- Around line 76-93: The trxPath emptiness check is redundant because
Require-Field -Object $test -Field "trxPath" already enforces
non-null/non-empty; remove the extra block that calls
[string]::IsNullOrWhiteSpace([string]$test.trxPath) and its Add-Error call so
only Require-Field validates trxPath for items in liveTests, leaving the other
validations (Require-Field for name/outcome/message and outcome membership
check) intact.

Comment on lines +21 to +40
description: Value from `tools/run-live-validation.ps1 -RunId ...`
placeholder: 20260217-010203
validations:
required: true
- type: input
id: repro_bundle_json
attributes:
label: Repro bundle JSON path/link
description: `TestResults/runs/<runId>/repro-bundle.json` or uploaded artifact URL
placeholder: TestResults/runs/20260217-010203/repro-bundle.json
validations:
required: true
- type: input
id: repro_bundle_md
attributes:
label: Repro bundle markdown path/link
description: `TestResults/runs/<runId>/repro-bundle.md`
placeholder: TestResults/runs/20260217-010203/repro-bundle.md
validations:
required: true
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

YAML syntax error: backtick characters break template parsing.

The backtick characters () in the description` fields on lines 21, 29, and 37 are invalid YAML syntax. GitHub Actions issue templates require valid YAML, and these will cause parsing failures when users try to create bug reports.

Wrap these values in quotes or use single quotes to escape the content properly.

🐛 Proposed fix
   - type: input
     id: run_id
     attributes:
       label: Run ID
-      description: Value from `tools/run-live-validation.ps1 -RunId ...`
+      description: "Value from tools/run-live-validation.ps1 -RunId ..."
       placeholder: 20260217-010203
     validations:
       required: true
   - type: input
     id: repro_bundle_json
     attributes:
       label: Repro bundle JSON path/link
-      description: `TestResults/runs/<runId>/repro-bundle.json` or uploaded artifact URL
+      description: "TestResults/runs/<runId>/repro-bundle.json or uploaded artifact URL"
       placeholder: TestResults/runs/20260217-010203/repro-bundle.json
     validations:
       required: true
   - type: input
     id: repro_bundle_md
     attributes:
       label: Repro bundle markdown path/link
-      description: `TestResults/runs/<runId>/repro-bundle.md`
+      description: "TestResults/runs/<runId>/repro-bundle.md"
       placeholder: TestResults/runs/20260217-010203/repro-bundle.md
📝 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
description: Value from `tools/run-live-validation.ps1 -RunId ...`
placeholder: 20260217-010203
validations:
required: true
- type: input
id: repro_bundle_json
attributes:
label: Repro bundle JSON path/link
description: `TestResults/runs/<runId>/repro-bundle.json` or uploaded artifact URL
placeholder: TestResults/runs/20260217-010203/repro-bundle.json
validations:
required: true
- type: input
id: repro_bundle_md
attributes:
label: Repro bundle markdown path/link
description: `TestResults/runs/<runId>/repro-bundle.md`
placeholder: TestResults/runs/20260217-010203/repro-bundle.md
validations:
required: true
description: "Value from tools/run-live-validation.ps1 -RunId ..."
placeholder: 20260217-010203
validations:
required: true
- type: input
id: repro_bundle_json
attributes:
label: Repro bundle JSON path/link
description: "TestResults/runs/<runId>/repro-bundle.json or uploaded artifact URL"
placeholder: TestResults/runs/20260217-010203/repro-bundle.json
validations:
required: true
- type: input
id: repro_bundle_md
attributes:
label: Repro bundle markdown path/link
description: "TestResults/runs/<runId>/repro-bundle.md"
placeholder: TestResults/runs/20260217-010203/repro-bundle.md
validations:
required: true
🧰 Tools
🪛 YAMLlint (1.38.0)

[error] 29-29: syntax error: found character '`' that cannot start any token

(syntax)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/ISSUE_TEMPLATE/bug.yml around lines 21 - 40, The YAML in the issue
template uses raw backticks in the description fields which breaks parsing;
update the three description values (the ones for the fields with id
repro_bundle_json and repro_bundle_md and the earlier description at line 21) to
be valid YAML strings by quoting them (single or double quotes) or escaping the
backticks so the literal text like `TestResults/runs/<runId>/repro-bundle.json`
and `TestResults/runs/<runId>/repro-bundle.md` are wrapped in quotes; ensure all
three description placeholders/values are changed consistently so the template
parses correctly.

Comment on lines +71 to +84
- type: textarea
id: launch_context
attributes:
label: Launch context diagnostics
description: Include launchKind, reasonCode, confidence, and detected STEAMMOD/MODPATH data.
validations:
required: true
- type: textarea
id: diagnostics
attributes:
label: Diagnostics / logs
description: Include launchKind, reasonCode, confidence, dependencyValidation if available.
description: Include runtimeModeHint/runtimeModeEffective/runtimeModeReasonCode, dependency state, helper readiness, symbol health summary.
validations:
required: true
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Same YAML syntax issue in launch_context and diagnostics descriptions.

The description on line 75 and 82 should also be quoted to ensure valid YAML.

🐛 Proposed fix
   - type: textarea
     id: launch_context
     attributes:
       label: Launch context diagnostics
-      description: Include launchKind, reasonCode, confidence, and detected STEAMMOD/MODPATH data.
+      description: "Include launchKind, reasonCode, confidence, and detected STEAMMOD/MODPATH data."
     validations:
       required: true
   - type: textarea
     id: diagnostics
     attributes:
       label: Diagnostics / logs
-      description: Include runtimeModeHint/runtimeModeEffective/runtimeModeReasonCode, dependency state, helper readiness, symbol health summary.
+      description: "Include runtimeModeHint/runtimeModeEffective/runtimeModeReasonCode, dependency state, helper readiness, symbol health summary."
📝 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
- type: textarea
id: launch_context
attributes:
label: Launch context diagnostics
description: Include launchKind, reasonCode, confidence, and detected STEAMMOD/MODPATH data.
validations:
required: true
- type: textarea
id: diagnostics
attributes:
label: Diagnostics / logs
description: Include launchKind, reasonCode, confidence, dependencyValidation if available.
description: Include runtimeModeHint/runtimeModeEffective/runtimeModeReasonCode, dependency state, helper readiness, symbol health summary.
validations:
required: true
- type: textarea
id: launch_context
attributes:
label: Launch context diagnostics
description: "Include launchKind, reasonCode, confidence, and detected STEAMMOD/MODPATH data."
validations:
required: true
- type: textarea
id: diagnostics
attributes:
label: Diagnostics / logs
description: "Include runtimeModeHint/runtimeModeEffective/runtimeModeReasonCode, dependency state, helper readiness, symbol health summary."
validations:
required: true
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/ISSUE_TEMPLATE/bug.yml around lines 71 - 84, The YAML descriptions
for the fields with id "launch_context" and "diagnostics" are not quoted, which
can break YAML parsing; update the attributes.description values for
launch_context and diagnostics to be wrapped in quotes (e.g., "Include
launchKind, reasonCode, confidence, and detected STEAMMOD/MODPATH data." and
"Include runtimeModeHint/runtimeModeEffective/runtimeModeReasonCode, dependency
state, helper readiness, symbol health summary.") so the strings are valid YAML
while preserving the existing text.

Comment on lines +59 to +63
- name: Applitools availability note
if: ${{ secrets.APPLITOOLS_API_KEY != '' }}
shell: pwsh
run: |
Write-Host "APPLITOOLS_API_KEY is configured. Visual pack can be uploaded for external review."
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

secrets context is not available in step-level if expressions.

The secrets context cannot be used directly in step if conditions. This will cause the workflow to fail. Use an environment variable approach instead.

🐛 Proposed fix using environment variable
       - name: Applitools availability note
-        if: ${{ secrets.APPLITOOLS_API_KEY != '' }}
+        if: ${{ env.HAS_APPLITOOLS_KEY == 'true' }}
         shell: pwsh
+        env:
+          HAS_APPLITOOLS_KEY: ${{ secrets.APPLITOOLS_API_KEY != '' }}
         run: |
           Write-Host "APPLITOOLS_API_KEY is configured. Visual pack can be uploaded for external review."

Alternative: Check the secret as an env var inside the script:

       - name: Applitools availability note
-        if: ${{ secrets.APPLITOOLS_API_KEY != '' }}
         shell: pwsh
+        env:
+          APPLITOOLS_API_KEY: ${{ secrets.APPLITOOLS_API_KEY }}
         run: |
-          Write-Host "APPLITOOLS_API_KEY is configured. Visual pack can be uploaded for external review."
+          if ($env:APPLITOOLS_API_KEY) {
+            Write-Host "APPLITOOLS_API_KEY is configured. Visual pack can be uploaded for external review."
+          }
🧰 Tools
🪛 actionlint (1.7.10)

[error] 60-60: context "secrets" is not allowed here. available contexts are "env", "github", "inputs", "job", "matrix", "needs", "runner", "steps", "strategy", "vars". see https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability for more details

(expression)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/visual-audit.yml around lines 59 - 63, The step
"Applitools availability note" uses a step-level if with the secrets context
which is not allowed; change to export the secret into an env var (e.g., set
env: APPLITOOLS_API_KEY: ${{ secrets.APPLITOOLS_API_KEY }} at the job or step
level) and remove the step-level if, or keep the env mapping and replace the if
with a runtime check inside the pwsh script (use $env:APPLITOOLS_API_KEY in the
"run" block) so the availability message only prints when the variable is
present.

Comment on lines +42 to +51
$matches = [regex]::Matches($CommandLine, "STEAMMOD\s*=\s*([0-9]{4,})", [System.Text.RegularExpressions.RegexOptions]::IgnoreCase)
$ids = New-Object System.Collections.Generic.HashSet[string]([StringComparer]::OrdinalIgnoreCase)
foreach ($match in $matches) {
if ($match.Groups.Count -gt 1) {
[void]$ids.Add($match.Groups[1].Value)
}
}

return @($ids)
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Assigning to $matches shadows PowerShell's automatic variable.

$matches is a built-in automatic variable populated by the -match operator. While this code uses [regex]::Matches() (the .NET method), shadowing the automatic variable can cause confusion and unexpected behavior if any downstream code uses the -match operator.

🛠️ Rename to avoid shadowing
-    $matches = [regex]::Matches($CommandLine, "STEAMMOD\s*=\s*([0-9]{4,})", [System.Text.RegularExpressions.RegexOptions]::IgnoreCase)
+    $regexMatches = [regex]::Matches($CommandLine, "STEAMMOD\s*=\s*([0-9]{4,})", [System.Text.RegularExpressions.RegexOptions]::IgnoreCase)
     $ids = New-Object System.Collections.Generic.HashSet[string]([StringComparer]::OrdinalIgnoreCase)
-    foreach ($match in $matches) {
+    foreach ($match in $regexMatches) {
         if ($match.Groups.Count -gt 1) {
             [void]$ids.Add($match.Groups[1].Value)
         }
     }
📝 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
$matches = [regex]::Matches($CommandLine, "STEAMMOD\s*=\s*([0-9]{4,})", [System.Text.RegularExpressions.RegexOptions]::IgnoreCase)
$ids = New-Object System.Collections.Generic.HashSet[string]([StringComparer]::OrdinalIgnoreCase)
foreach ($match in $matches) {
if ($match.Groups.Count -gt 1) {
[void]$ids.Add($match.Groups[1].Value)
}
}
return @($ids)
}
$regexMatches = [regex]::Matches($CommandLine, "STEAMMOD\s*=\s*([0-9]{4,})", [System.Text.RegularExpressions.RegexOptions]::IgnoreCase)
$ids = New-Object System.Collections.Generic.HashSet[string]([StringComparer]::OrdinalIgnoreCase)
foreach ($match in $regexMatches) {
if ($match.Groups.Count -gt 1) {
[void]$ids.Add($match.Groups[1].Value)
}
}
return @($ids)
}
🧰 Tools
🪛 PSScriptAnalyzer (1.23.0)

[warning] 42-42: The Variable 'matches' is an automatic variable that is built into PowerShell, assigning to it might have undesired side effects. If assignment is not by design, please use a different name.

(PSAvoidAssignmentToAutomaticVariable)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/collect-mod-repro-bundle.ps1` around lines 42 - 51, The variable
$matches shadows PowerShell's automatic $matches and should be renamed to avoid
confusion; update the call to [regex]::Matches($CommandLine,
"STEAMMOD\s*=\s*([0-9]{4,})", ...) to assign to a new name (e.g., $regexMatches)
and update the foreach loop to iterate over that new variable (change foreach
($match in $matches) to foreach ($match in $regexMatches)) while leaving all
other logic (the HashSet $ids, $match.Groups usage, and the return) unchanged.

Comment on lines +145 to +156
$args = @()
if ($pythonCmd.Count -gt 1) {
$args += $pythonCmd[1..($pythonCmd.Count - 1)]
}
$args += @(
"tools/detect-launch-context.py",
"--command-line", $Process.commandLine,
"--process-name", $Process.name,
"--process-path", $Process.path,
"--profile-root", $ProfileRootPath,
"--pretty"
)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Assigning to $args shadows PowerShell's automatic variable.

Same issue as in run-live-validation.ps1. Rename to $pythonArgs or similar.

🛠️ Rename to avoid shadowing
-    $args = @()
+    $pythonArgs = @()
     if ($pythonCmd.Count -gt 1) {
-        $args += $pythonCmd[1..($pythonCmd.Count - 1)]
+        $pythonArgs += $pythonCmd[1..($pythonCmd.Count - 1)]
     }
-    $args += @(
+    $pythonArgs += @(
         "tools/detect-launch-context.py",
         "--command-line", $Process.commandLine,
         "--process-name", $Process.name,
         "--process-path", $Process.path,
         "--profile-root", $ProfileRootPath,
         "--pretty"
     )

     try {
-        $output = & $pythonCmd[0] `@args` 2>&1
+        $output = & $pythonCmd[0] `@pythonArgs` 2>&1
🧰 Tools
🪛 PSScriptAnalyzer (1.23.0)

[warning] 145-145: The Variable 'args' is an automatic variable that is built into PowerShell, assigning to it might have undesired side effects. If assignment is not by design, please use a different name.

(PSAvoidAssignmentToAutomaticVariable)


[warning] 147-147: The Variable 'args' is an automatic variable that is built into PowerShell, assigning to it might have undesired side effects. If assignment is not by design, please use a different name.

(PSAvoidAssignmentToAutomaticVariable)


[warning] 149-149: The Variable 'args' is an automatic variable that is built into PowerShell, assigning to it might have undesired side effects. If assignment is not by design, please use a different name.

(PSAvoidAssignmentToAutomaticVariable)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/collect-mod-repro-bundle.ps1` around lines 145 - 156, The script is
assigning to the automatic PowerShell variable $args which causes shadowing;
rename that variable (e.g. $pythonArgs) and update all uses in this block so you
build the argument array into $pythonArgs instead of $args (modify the $args +=
lines and any later invocation that consumes it), keeping the logic that appends
$pythonCmd[1..] and the tools/detect-launch-context.py arguments that use
$Process and $ProfileRootPath.

Comment on lines +397 to +425
@"
# Repro Bundle Summary

- runId: `$RunId`
- scope: `$Scope`
- classification: `$classification`
- launch profile: `$($launchContext.profileId)`
- launch reason: `$($launchContext.reasonCode)`
- confidence: `$($launchContext.confidence)`
- launch kind: `$($launchContext.launchKind)`
- runtime mode effective: `$($runtimeMode.effective)`
- runtime mode reason: `$($runtimeMode.reasonCode)`

## Process Snapshot

| PID | Name | SteamModIds | Command Line |
|---|---|---|---|
$((@($processSnapshot | ForEach-Object { "| $($_.pid) | $($_.name) | $(@($_.steamModIds) -join ',') | $([string]$_.commandLine).Replace('|','/') |" }) -join "`n"))

## Live Tests

| Test | Outcome | Pass/Fail/Skip | TRX | Message |
|---|---|---|---|---|
$($liveRows -join "`n")

## Next Action

$nextAction
"@ | Set-Content -Path $bundleMdPath
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's see the file size and context around the disputed lines
wc -l tools/collect-mod-repro-bundle.ps1

Repository: Prekzursil/SWFOC-Mod-Menu

Length of output: 107


🏁 Script executed:

# View the context around lines 397-425
sed -n '380,430p' tools/collect-mod-repro-bundle.ps1 | cat -n

Repository: Prekzursil/SWFOC-Mod-Menu

Length of output: 1979


🏁 Script executed:

# Search for any test fixtures or sample output related to repro bundle
fd -t f "repro" --search-path . | grep -E "\.(md|txt|json)$|fixture|sample|test"

Repository: Prekzursil/SWFOC-Mod-Menu

Length of output: 151


🏁 Script executed:

# Look at the broader context to see how bundleMdPath is used
rg "bundleMdPath" -B 5 -A 5 tools/collect-mod-repro-bundle.ps1

Repository: Prekzursil/SWFOC-Mod-Menu

Length of output: 664


🏁 Script executed:

# View the repro bundle sample fixture
cat tools/fixtures/repro_bundle_sample.json

Repository: Prekzursil/SWFOC-Mod-Menu

Length of output: 1229


🏁 Script executed:

# Also check if there are any markdown samples or tests
fd -t f "\.(md|test)" tools/ | head -20

Repository: Prekzursil/SWFOC-Mod-Menu

Length of output: 84


🏁 Script executed:

# Search for documentation about the repro bundle structure
rg "repro.bundle|repro-bundle" -A 3 --max-count 10 README.md docs/ 2>/dev/null || echo "No docs found"

Repository: Prekzursil/SWFOC-Mod-Menu

Length of output: 3234


🏁 Script executed:

# Extract just the here-string content to see all variable references
sed -n '397,425p' tools/collect-mod-repro-bundle.ps1 | grep -E '^\s*-|^\$'

Repository: Prekzursil/SWFOC-Mod-Menu

Length of output: 644


🏁 Script executed:

# Count backtick escapes in the here-string
sed -n '397,425p' tools/collect-mod-repro-bundle.ps1 | grep -c '`\$'

Repository: Prekzursil/SWFOC-Mod-Menu

Length of output: 70


Remove backticks from all 9 variable references to enable interpolation in markdown output.

The here-string uses backtick escaping on 9 variables which prevents PowerShell from interpolating them:

  • $RunId, $Scope, $classification
  • $($launchContext.profileId), $($launchContext.reasonCode), $($launchContext.confidence), $($launchContext.launchKind)
  • $($runtimeMode.effective), $($runtimeMode.reasonCode)

This causes the generated repro-bundle.md to contain literal variable names (e.g., $RunId) instead of actual runtime values. Since this markdown is critical evidence for issue tracking, remove the backticks from these lines to allow proper interpolation. The fixture sample confirms that values should be interpolated (e.g., runId: sample-20260217, not runId: $RunId).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/collect-mod-repro-bundle.ps1` around lines 397 - 425, The here-string
written to $bundleMdPath currently escapes nine variables (e.g., `$RunId`,
`$Scope`, `$classification`, `$($launchContext.profileId)`,
`$($launchContext.reasonCode)`, `$($launchContext.confidence)`,
`$($launchContext.launchKind)`, `$($runtimeMode.effective)`,
`$($runtimeMode.reasonCode)`) with backticks which prevents PowerShell
interpolation; remove the backticks so the here-string interpolates those
expressions directly (leave the surrounding @"..."@ here-string intact) so the
generated repro-bundle.md contains the actual runtime values instead of literal
variable names.

[string]$ResultsDirectory = "TestResults",
[string]$ProfileRoot = "profiles/default",
[switch]$NoBuild = $true
[switch]$NoBuild = $true,
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Switch parameter defaulting to $true causes usability issues.

A [switch] parameter that defaults to $true is problematic because:

  1. Specifying -NoBuild has no effect (it's already true)
  2. Users cannot easily disable it; they must use -NoBuild:$false

If the intent is "no build by default, opt-in to build," consider renaming to [switch]$Build (defaults to $false), then invert the logic at usage.

🛠️ Suggested fix
-    [switch]$NoBuild = $true,
+    [switch]$Build,

Then at line 125-127:

-    if ($NoBuild) {
+    if (-not $Build) {
         $args += "--no-build"
     }
🧰 Tools
🪛 PSScriptAnalyzer (1.23.0)

[warning] 5-5: File 'run-live-validation.ps1' has a switch parameter default to true.

(PSAvoidDefaultValueSwitchParameter)


[warning] 5-5: The parameter 'NoBuild' has been declared but not used.

(PSReviewUnusedParameter)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/run-live-validation.ps1` at line 5, The [switch] parameter $NoBuild
currently defaults to $true which makes the flag unusable; rename the parameter
to [switch]$Build (default $false) or change $NoBuild to default $false, then
update all usages where the script checks $NoBuild (or where you previously
skipped the build) to use the new $Build logic (invert the conditional: run the
build when $Build is true, or replace checks like "if (-not $NoBuild)" with "if
($Build)") so callers can simply pass -Build to opt into building.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d3a380d269

ℹ️ 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +305 to +307
if ($processItems.Count -eq 0) {
return "blocked_environment"
}

Choose a reason for hiding this comment

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

P1 Badge Evaluate live outcomes before declaring blocked environment

Get-Classification returns blocked_environment as soon as processSnapshot is empty, before it checks whether relevant live tests already passed. If the game process exits between test execution and bundle collection, a run with passing TRX results is misclassified as environment-blocked, which sends triage down the wrong path and can hide real pass/fail status in repro bundles.

Useful? React with 👍 / 👎.

Comment on lines +38 to +39
$candidate = "TestResults/runs/$runId/visual-pack"
}

Choose a reason for hiding this comment

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

P2 Badge Download candidate visual-pack artifacts before compare

The workflow defaults candidate to TestResults/runs/<run_id>/visual-pack, but on a fresh Actions runner only repository files exist after checkout and this path is not created anywhere in the job. Because compare-visual-pack.ps1 throws when CandidateDir is missing, the default workflow path fails unless callers manually override candidate_dir to an existing directory.

Useful? React with 👍 / 👎.


## Required Evidence
1. Runtime/tooling/test changes must include deterministic test evidence or an explicit justified skip.
2. Mod/runtime bugfixes must include a reproducible bundle:

Choose a reason for hiding this comment

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

Codacy has a fix for the issue: Lists should be surrounded by blank lines

Suggested change
2. Mod/runtime bugfixes must include a reproducible bundle:
2. Mod/runtime bugfixes must include a reproducible bundle:

- `TestResults/runs/<runId>/visual-pack/<surface>/<checkpoint>.png`

Naming guidance:
- `<surface>`: `live-ops`, `runtime-tab`, `attach-dialog`, `tactical`, `galactic`

Choose a reason for hiding this comment

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

Codacy has a fix for the issue: Lists should be surrounded by blank lines

Suggested change
- `<surface>`: `live-ops`, `runtime-tab`, `attach-dialog`, `tactical`, `galactic`
- `<surface>`: `live-ops`, `runtime-tab`, `attach-dialog`, `tactical`, `galactic`

1. Intake issue with profile/build/scope context.
2. Run live validation tooling to emit `repro-bundle.json` and `repro-bundle.md`.
3. Classify using explicit failure categories:
- `passed`

Choose a reason for hiding this comment

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

Codacy has a fix for the issue: Lists should be surrounded by blank lines

Suggested change
- `passed`
- `passed`

Applies to files under `tests/`.

## Required Evidence
1. Deterministic tests for new behavior.

Choose a reason for hiding this comment

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

Codacy has a fix for the issue: Lists should be surrounded by blank lines

Suggested change
1. Deterministic tests for new behavior.
1. Deterministic tests for new behavior.


## PR Readiness
A PR touching runtime/tooling/tests must include:
1. affected profile IDs

Choose a reason for hiding this comment

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

Codacy has a fix for the issue: Lists should be surrounded by blank lines

Suggested change
1. affected profile IDs
1. affected profile IDs

6. Close issue only when linked evidence confirms acceptance criteria.

## Safety Rules
1. No blind fixed-address runtime actions.

Choose a reason for hiding this comment

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

Codacy has a fix for the issue: Lists should be surrounded by blank lines

Suggested change
1. No blind fixed-address runtime actions.
1. No blind fixed-address runtime actions.

Applies to files under `tools/`.

## Required Evidence
1. Every tooling script change must include a deterministic fixture or smoke command.

Choose a reason for hiding this comment

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

Codacy has a fix for the issue: Lists should be surrounded by blank lines

Suggested change
1. Every tooling script change must include a deterministic fixture or smoke command.
1. Every tooling script change must include a deterministic fixture or smoke command.

- `failed`
- `blocked_environment`
- `blocked_profile_mismatch`
4. Implement fix on branch.

Choose a reason for hiding this comment

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

Codacy has a fix for the issue: Lists should be surrounded by blank lines

Suggested change
4. Implement fix on branch.
4. Implement fix on branch.

3. Include repro bundle evidence for live-only fixes.

## Runtime Safety Rules
1. Signature-first; never rely on blind fixed addresses.

Choose a reason for hiding this comment

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

Codacy has a fix for the issue: Lists should be surrounded by blank lines

Suggested change
1. Signature-first; never rely on blind fixed addresses.
1. Signature-first; never rely on blind fixed addresses.

## Required Evidence
1. Runtime/tooling/test changes must include deterministic test evidence or an explicit justified skip.
2. Mod/runtime bugfixes must include a reproducible bundle:
- `TestResults/runs/<runId>/repro-bundle.json`

Choose a reason for hiding this comment

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

Codacy has a fix for the issue: Lists should be surrounded by blank lines

Suggested change
- `TestResults/runs/<runId>/repro-bundle.json`
- `TestResults/runs/<runId>/repro-bundle.json`

3. No pass-by-return in live tests.

## Test Rules
1. Keep deterministic CI filter valid.

Choose a reason for hiding this comment

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

Codacy has a fix for the issue: Lists should be surrounded by blank lines

Suggested change
1. Keep deterministic CI filter valid.
1. Keep deterministic CI filter valid.

Prekzursil added a commit that referenced this pull request Feb 18, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

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 (1)
.github/workflows/sonarcloud.yml (1)

38-53: AI summary inconsistency + token exposure in CLI arguments.

Inconsistent summary: The AI-generated summary states this workflow uses SonarSource/sonarqube-scan-action; the actual implementation uses the manual dotnet-sonarscanner begin/build/end pattern, which is a materially different integration.

Token in CLI argument: ${{ secrets.SONAR_TOKEN }} is interpolated inline as /d:sonar.token="..." in both the begin and end shell commands. This exposes the token value as a command-line argument visible in process listings (ps aux) on the runner. The scanner also supports authentication via the SONAR_TOKEN environment variable, which avoids the process-list exposure. Combined with the fix proposed above (job-level env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}), the scanner picks it up automatically and the explicit /d:sonar.token= flags can be removed from both steps:

♻️ Proposed fix: use SONAR_TOKEN env var instead of CLI flag
       - name: Sonar Begin
         shell: bash
         run: |
           dotnet-sonarscanner begin \
             /k:"Prekzursil_SWFOC-Mod-Menu" \
             /o:"prekzursil" \
-            /d:sonar.token="${{ secrets.SONAR_TOKEN }}" \
             /d:sonar.host.url="https://sonarcloud.io"

       - name: Build
         run: dotnet build SwfocTrainer.sln -c Release --no-restore

       - name: Sonar End
         shell: bash
         run: |
-          dotnet-sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}"
+          dotnet-sonarscanner end

(Requires SONAR_TOKEN set at the job level as shown in the fix above.)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/sonarcloud.yml around lines 38 - 53, The workflow
currently passes the secret via CLI (/d:sonar.token="${{ secrets.SONAR_TOKEN
}}") to the dotnet-sonarscanner in both the "dotnet-sonarscanner begin" and
"dotnet-sonarscanner end" steps, which exposes the token to process listings;
remove the explicit /d:sonar.token= flags from both the begin and end
invocations and instead set SONAR_TOKEN at the job level (env: SONAR_TOKEN: ${{
secrets.SONAR_TOKEN }}) so the scanner reads the token from the environment;
also update the workflow summary/description to reflect that the manual
dotnet-sonarscanner begin/build/end pattern is used (not the
SonarSource/sonarqube-scan-action).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/sonarcloud.yml:
- Around line 11-12: The workflow currently only grants permissions: contents:
read which prevents SonarCloud PR decoration; update the permissions block to
include pull-requests: write in addition to contents: read and ensure the
GITHUB_TOKEN is provided to the scanner (either export GITHUB_TOKEN as an env
var at the job level or pass it into the SonarCloud scanner step) so SonarCloud
can post analysis results and quality-gate status back to pull requests.
- Line 16: Remove the job-level conditional that uses secrets.SONAR_TOKEN (which
is invalid at job scope) and instead expose the secret via an env variable on
the job (e.g., set env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}), then delete
the job-level if: ${{ secrets.SONAR_TOKEN != '' }} and add step-level guards on
the Sonar-related steps using if: env.SONAR_TOKEN != '' so those steps only run
when the secret is present (apply to all steps that perform Sonar analysis or
upload).

---

Nitpick comments:
In @.github/workflows/sonarcloud.yml:
- Around line 38-53: The workflow currently passes the secret via CLI
(/d:sonar.token="${{ secrets.SONAR_TOKEN }}") to the dotnet-sonarscanner in both
the "dotnet-sonarscanner begin" and "dotnet-sonarscanner end" steps, which
exposes the token to process listings; remove the explicit /d:sonar.token= flags
from both the begin and end invocations and instead set SONAR_TOKEN at the job
level (env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}) so the scanner reads the
token from the environment; also update the workflow summary/description to
reflect that the manual dotnet-sonarscanner begin/build/end pattern is used (not
the SonarSource/sonarqube-scan-action).

Comment on lines +11 to +12
permissions:
contents: read
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Missing pull-requests: write permission will break PR decoration.

With only contents: read declared, SonarCloud cannot post analysis results or quality-gate status back to pull requests. The GITHUB_TOKEN also needs to be surfaced to the scanner (or set as GITHUB_TOKEN env var at the job level) for PR decoration to work.

🔧 Proposed fix: add pull-requests: write and GITHUB_TOKEN
 permissions:
   contents: read
+  pull-requests: write

 jobs:
   sonarcloud:
     runs-on: ubuntu-latest
     env:
       SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
+      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
📝 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
permissions:
contents: read
permissions:
contents: read
pull-requests: write
jobs:
sonarcloud:
runs-on: ubuntu-latest
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/sonarcloud.yml around lines 11 - 12, The workflow
currently only grants permissions: contents: read which prevents SonarCloud PR
decoration; update the permissions block to include pull-requests: write in
addition to contents: read and ensure the GITHUB_TOKEN is provided to the
scanner (either export GITHUB_TOKEN as an env var at the job level or pass it
into the SonarCloud scanner step) so SonarCloud can post analysis results and
quality-gate status back to pull requests.


jobs:
sonarcloud:
if: ${{ secrets.SONAR_TOKEN != '' }}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Read the workflow file to confirm the code at line 16
if [ -f .github/workflows/sonarcloud.yml ]; then
  echo "=== File exists, reading content with line numbers ==="
  cat -n .github/workflows/sonarcloud.yml | head -60
else
  echo "=== File not found, checking for workflow files ==="
  find . -name "*.yml" -o -name "*.yaml" | grep -E "workflows|github" | head -20
fi

Repository: Prekzursil/SWFOC-Mod-Menu

Length of output: 1699


🌐 Web query:

GitHub Actions job level if conditional secrets context available

💡 Result:

No—the secrets context is not available in a job-level if: (e.g., jobs.<job_id>.if:), so expressions like this will fail validation:

jobs:
  build:
    if: ${{ secrets.MY_SECRET == 'true' }}  # ❌ Unrecognized named-value: 'secrets'

GitHub explicitly notes that secrets can’t be directly referenced in if: conditionals (at the job level) and recommends alternative patterns. [1]

What to do instead

  • Gate at step level (where secrets is available), and early-exit / skip the sensitive steps:
    • Put the secret into env: and use if: on steps, or compute a non-secret boolean output and branch on that. [1][2]
  • If your real goal is “turn a job on/off”, use a non-secret control like:
    • vars.* (repository/org/environment variables) or inputs.* (workflow_dispatch / reusable workflow inputs), which are allowed in job-level condition contexts per the context-availability rules. [2]

Sources: GitHub Docs on secrets + conditionals [1], and GitHub Docs context availability reference [2].

References:
[1] GitHub Docs – Using secrets in GitHub Actions (notes secrets can’t be directly referenced in if: conditionals) (docs.github.com)
[2] GitHub Docs – Contexts reference / context availability table (docs.github.com)

Citations:


Job-level if: ${{ secrets.SONAR_TOKEN != '' }} causes workflow validation failure—secrets context is unavailable at job scope.

GitHub Actions does not allow the secrets context in job-level if: conditionals. This will cause an immediate validation error ("Unrecognized named-value: 'secrets'") and the job will not run.

Move the guard to step-level conditionals via an environment variable:

🔧 Fix: move secret check to step-level with env variable
 jobs:
   sonarcloud:
-    if: ${{ secrets.SONAR_TOKEN != '' }}
     runs-on: ubuntu-latest
+    env:
+      SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
     steps:
       - name: Checkout
         uses: actions/checkout@v4

Then add if: env.SONAR_TOKEN != '' to the Sonar-specific steps:

       - name: Sonar Begin
+        if: env.SONAR_TOKEN != ''
         shell: bash
         run: |
           dotnet-sonarscanner begin ...

       - name: Sonar End
+        if: env.SONAR_TOKEN != ''
         shell: bash
         run: |
           dotnet-sonarscanner end ...
🧰 Tools
🪛 actionlint (1.7.11)

[error] 16-16: context "secrets" is not allowed here. available contexts are "github", "inputs", "needs", "vars". see https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability for more details

(expression)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/sonarcloud.yml at line 16, Remove the job-level
conditional that uses secrets.SONAR_TOKEN (which is invalid at job scope) and
instead expose the secret via an env variable on the job (e.g., set env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}), then delete the job-level if: ${{
secrets.SONAR_TOKEN != '' }} and add step-level guards on the Sonar-related
steps using if: env.SONAR_TOKEN != '' so those steps only run when the secret is
present (apply to all steps that perform Sonar analysis or upload).

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 26fdef295e

ℹ️ 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +59 to +63
const hasBundleField = body.includes('repro bundle json:');
const hasClassification = body.includes('classification:');
const hasSkipJustification = body.includes('justified skip');

if (!hasBundleField || (!hasClassification && !hasSkipJustification)) {

Choose a reason for hiding this comment

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

P1 Badge Enforce populated evidence values, not template labels

This gate currently treats evidence as present if the PR body merely contains the literal strings repro bundle json: and classification:, which are always present in the default PR template placeholders, so PRs that touch src/SwfocTrainer.Runtime/, tools/, or tests/ can pass without supplying any real artifact path or classification value. In practice this makes the new evidence policy non-enforcing for most template-based PRs and allows missing runtime/tooling validation evidence to merge unnoticed.

Useful? React with 👍 / 👎.

Prekzursil added a commit that referenced this pull request Feb 18, 2026
@Prekzursil Prekzursil merged commit 9b843c0 into main Feb 18, 2026
13 of 14 checks passed
@Prekzursil Prekzursil deleted the feature/ai-native-engineering-os branch February 18, 2026 00:10
Prekzursil added a commit that referenced this pull request Feb 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:ci CI/CD and automation area:docs Documentation/process related work. area:runtime Runtime attach, memory actions, symbol resolution area:tooling Scripts and developer tooling Review effort 4/5

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments