Skip to content

feat(xtask): add generate-compat command with quirks and comprehensive tests#36

Open
EffortlessSteven wants to merge 5 commits intomainfrom
feat/compat-generator
Open

feat(xtask): add generate-compat command with quirks and comprehensive tests#36
EffortlessSteven wants to merge 5 commits intomainfrom
feat/compat-generator

Conversation

@EffortlessSteven
Copy link
Member

@EffortlessSteven EffortlessSteven commented Mar 1, 2026

Summary

Adds \xtask/src/generate_compat.rs\ module implementing \cargo xtask generate-compat\ that generates \COMPATIBILITY.md\ and \compat/compatibility.json\ from the device/game YAML manifests.

Changes

*New module: \generate_compat.rs*

  • Scans \compat/devices/\ and \compat/games/\ for all YAML manifests
  • Parses device quirks (e.g. \WARTHOG_AXES_BIPOLAR) into \DeviceEntry.quirks\
  • Generates \COMPATIBILITY.md\ with:
    • Summary stats (total devices, vendors, tier distribution)
    • Device table sorted by vendor → name, with Tier/Axes/Buttons/FFB/Quirks columns
    • Game table with integration type, features, coverage
    • Support tier legend (Tier 1 = automated + HIL, Tier 2 = automated, Tier 3 = best-effort)
  • Outputs \compat/compatibility.json\ for programmatic consumption
  • Validates required fields and tier ranges on all manifests

Shared types (\compat.rs)

  • Added \quirks: Vec\ field to \DeviceEntry\
  • Updated \parse_device()\ to extract quirk IDs from YAML

CI (\ci.yml)

  • Updated freshness check to use \cargo xtask generate-compat\
  • Now diffs both \COMPATIBILITY.md\ and \compat/compatibility.json\

Tests (11 new unit tests)

  • Device parser: valid manifest, missing optional fields, missing required fields, invalid tier
  • Game parser: valid manifest, missing features, missing required fields, invalid tier
  • Generator output: markdown structure verification, tier count accuracy, vendor→name sort order

How to test

\\�ash
cargo xtask generate-compat # Generate outputs
cargo test -p xtask generate_compat # Run the 11 new tests
\\

- Scan compat/devices/ for YAML device manifests
- Aggregate by vendor, tier, capabilities
- Generate COMPATIBILITY.md with vendor-grouped tables
- Generate compat/matrix.json for machine consumption
- Add xtask subcommand registration

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 1, 2026 01:06
@gemini-code-assist
Copy link

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@chatgpt-codex-connector
Copy link

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@coderabbitai
Copy link

coderabbitai bot commented Mar 1, 2026

Warning

Rate limit exceeded

@EffortlessSteven has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 17 minutes and 48 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between cd2e54d and e4ca080.

📒 Files selected for processing (8)
  • .github/workflows/ci.yml
  • COMPATIBILITY.md
  • compat/compatibility.json
  • compat/matrix.json
  • xtask/src/compat.rs
  • xtask/src/compat_matrix.rs
  • xtask/src/generate_compat.rs
  • xtask/src/main.rs
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/compat-generator

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-free-for-open-source-projects

Review Summary by Qodo

Add compat-matrix xtask generator with vendor aggregation

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add compat-matrix xtask subcommand to generate compatibility documentation
• Parse device and game YAML manifests from compat/ directory structure
• Aggregate devices by vendor with tier and capability statistics
• Generate vendor-grouped COMPATIBILITY.md with device and game tables
• Export machine-readable compat/matrix.json with summary and detailed metrics
• Include 5 unit tests for parsing, aggregation, and helper functions
Diagram
flowchart LR
  A["YAML Manifests<br/>devices/ games/"] -->|collect_manifests| B["Parse Device<br/>& Game Files"]
  B -->|aggregate| C["Vendor Map<br/>& Statistics"]
  C -->|generate| D["COMPATIBILITY.md"]
  C -->|serialize| E["compat/matrix.json"]
  D -->|output| F["Documentation"]
  E -->|output| G["Machine-readable"]
Loading

Grey Divider

File Changes

1. xtask/src/compat_matrix.rs ✨ Enhancement +626/-0

Core compat-matrix generator implementation

• New module implementing manifest parsing and aggregation logic
• Defines JSON output structures (MatrixJson, MatrixSummary, VendorSummary, MatrixDevice,
 MatrixGame)
• Implements run_compat_matrix() entry point that orchestrates manifest collection, parsing, and
 file generation
• Generates markdown with vendor summary table, per-vendor device tables, and game integration table
• Parses YAML device and game manifests extracting capabilities, tiers, and test coverage
• Includes 5 unit tests covering device parsing, game parsing, vendor aggregation, missing
 directories, and utility functions

xtask/src/compat_matrix.rs


2. xtask/src/main.rs ✨ Enhancement +5/-0

Register compat-matrix xtask subcommand

• Add module declaration for compat_matrix
• Register CompatMatrix command variant in Commands enum
• Add command handler in main dispatch matching CompatMatrix to
 compat_matrix::run_compat_matrix()

xtask/src/main.rs


3. COMPATIBILITY.md 📝 Documentation +4262/-2206

Generated compatibility matrix documentation

• Auto-generated file containing vendor summary table with device counts and tier distribution
• Per-vendor hardware device tables with USB IDs, capabilities, and test coverage
• Game integrations table with feature support and tier information
• Support tier legend explaining tier 1, 2, and 3 classifications

COMPATIBILITY.md


View more (1)
4. compat/matrix.json 📝 Documentation +33558/-0

Generated machine-readable compatibility matrix

• Machine-readable JSON export of compatibility matrix
• Contains summary statistics, vendor summaries, device list, and game list
• Includes capability coverage metrics and tier distributions
• Structured for programmatic consumption by tools and dashboards

compat/matrix.json


Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects
Copy link

qodo-free-for-open-source-projects bot commented Mar 1, 2026

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Action required

1. Vendor tiers hardcoded🐞 Bug ✓ Correctness
Description
Per-vendor tier counts and the vendor summary table only handle tiers 1–3, but the repo’s device
manifests contain tier 4 and tier 5 devices. This will misreport vendor statistics in both
COMPATIBILITY.md and compat/matrix.json (and makes the tier legend incomplete).
Code

xtask/src/compat_matrix.rs[R155-164]

+    let vendors: Vec<VendorSummary> = vendor_map
+        .iter()
+        .map(|(name, devs)| VendorSummary {
+            name: name.clone(),
+            device_count: devs.len(),
+            tier_1: devs.iter().filter(|d| d.tier == 1).count(),
+            tier_2: devs.iter().filter(|d| d.tier == 2).count(),
+            tier_3: devs.iter().filter(|d| d.tier == 3).count(),
+            ffb_devices: devs.iter().filter(|d| d.force_feedback).count(),
+        })
Evidence
compat-matrix hardcodes VendorSummary to tier_1/tier_2/tier_3 and counts only those tiers, while
device manifests include support tiers 4 and 5; the markdown vendor table and tier legend also only
mention tiers 1–3. As a result, vendors with tier 4/5 devices will have device_count that cannot be
reconciled with the tier columns, and higher-tier devices are effectively invisible in vendor
stats/legend.

xtask/src/compat_matrix.rs[53-61]
xtask/src/compat_matrix.rs[155-164]
xtask/src/compat_matrix.rs[280-293]
xtask/src/compat_matrix.rs[353-366]
compat/devices/skalarki/generic-mfd.yaml[54-58]
compat/devices/generic/usb-numeric-keypad.yaml[59-63]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`compat-matrix` hardcodes per-vendor tier counts to tiers 1–3, but the manifest dataset includes device tiers 4 and 5. This produces misleading vendor stats and an incomplete tier legend.
### Issue Context
- Device manifests already contain `support.tier: 4` and `support.tier: 5`.
- The generator already builds global tier distributions dynamically (`devices_by_tier`), but vendor summaries do not.
### Fix Focus Areas
- xtask/src/compat_matrix.rs[53-61]
- xtask/src/compat_matrix.rs[155-165]
- xtask/src/compat_matrix.rs[277-295]
- xtask/src/compat_matrix.rs[353-367]
### Implementation notes
- Replace `VendorSummary { tier_1, tier_2, tier_3 }` with a dynamic `tiers: BTreeMap&amp;amp;amp;amp;lt;String, usize&amp;amp;amp;amp;gt;` (or `BTreeMap&amp;amp;amp;amp;lt;u64, usize&amp;amp;amp;amp;gt;`) and update JSON + markdown generation accordingly.
- Alternatively, if tiers are known/fixed (1–5), add explicit fields for tier_4/tier_5 and update the vendor table header and legend.
- Update the tier legend section to cover all tiers that appear in data (or clearly state which tiers are defined/unsupported).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Missing field validation 🐞 Bug ⛯ Reliability
Description
compat-matrix defaults missing/invalid manifest fields to "?"/0/false without emitting warnings, so
incomplete manifests silently degrade generated outputs (e.g., tier_0 buckets and "?" vendors).
Unlike gen-compat, it does not run a required-field/tier validation pass before generating
COMPATIBILITY.md and matrix.json.
Code

xtask/src/compat_matrix.rs[R373-395]

+fn parse_device(path: &Path) -> Result<MatrixDevice> {
+    let text = fs::read_to_string(path)?;
+    let doc: serde_yaml::Value = serde_yaml::from_str(&text)?;
+
+    Ok(MatrixDevice {
+        name: doc["device"]["name"].as_str().unwrap_or("?").to_string(),
+        vendor: doc["device"]["vendor"]
+            .as_str()
+            .unwrap_or("?")
+            .to_string(),
+        vendor_id: doc["device"]["usb"]["vendor_id"]
+            .as_u64()
+            .map_or_else(|| "?".to_string(), |v| format!("0x{v:04X}")),
+        product_id: doc["device"]["usb"]["product_id"]
+            .as_u64()
+            .map_or_else(|| "?".to_string(), |v| format!("0x{v:04X}")),
+        axes: doc["capabilities"]["axes"]["count"].as_u64().unwrap_or(0),
+        buttons: doc["capabilities"]["buttons"].as_u64().unwrap_or(0),
+        force_feedback: doc["capabilities"]["force_feedback"]
+            .as_bool()
+            .unwrap_or(false),
+        tier: doc["support"]["tier"].as_u64().unwrap_or(0),
+        test_coverage: DeviceTestCoverage {
Evidence
The parser uses fallbacks ("?" and 0) for key fields like device name/vendor and support tier, but
compat-matrix only reports YAML parse failures—there’s no required-field validation phase. The
existing gen-compat command does run validation and prints warnings; meanwhile, the current repo’s
generated compat/matrix.json already shows tier_0 and a vendor named "?", which is consistent with
missing-field fallbacks being emitted into outputs without clear diagnostics.

xtask/src/compat_matrix.rs[377-395]
xtask/src/compat_matrix.rs[118-145]
xtask/src/compat.rs[105-124]
compat/matrix.json[1-14]
compat/matrix.json[69-76]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`compat-matrix` only reports YAML parse failures, but it silently defaults missing required fields to placeholders (&amp;amp;amp;amp;quot;?&amp;amp;amp;amp;quot;, 0, false). This can leak bad/partial data into generated artifacts without clear warnings.
### Issue Context
- The existing `gen-compat` command runs a validation pass that flags missing required fields and invalid tiers.
- The current repo output already shows `tier_0` and a vendor named `&amp;amp;amp;amp;quot;?&amp;amp;amp;amp;quot;`, consistent with placeholder defaults making it into matrix.json.
### Fix Focus Areas
- xtask/src/compat_matrix.rs[118-145]
- xtask/src/compat_matrix.rs[373-450]
- xtask/src/compat.rs[105-124]
### Implementation notes
- Reuse/refactor the existing validation helpers from `xtask/src/compat.rs` so both commands share the same manifest validation behavior.
- At minimum: warn when any required field is null/missing (device.name/vendor/usb ids/support tier; game.name/id/integration fields/support_tier).
- Consider treating missing `support.tier`/`support_tier` as an error (skip manifest) instead of defaulting to 0, or at least emit a targeted warning identifying the file and missing field.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds a new cargo xtask compat-matrix subcommand that generates COMPATIBILITY.md and compat/matrix.json from YAML device and game manifests. Unlike the existing gen-compat/generate-compat commands (in compat.rs), the new command adds vendor-grouped summary tables, capability coverage statistics, and a richer JSON export with vendor aggregations.

Changes:

  • New compat_matrix module added as xtask/src/compat_matrix.rs (626 lines), implementing manifest scanning, vendor aggregation, Markdown and JSON generation, and 5 unit tests.
  • xtask/src/main.rs updated to declare the new module and add the CompatMatrix CLI variant.

Reviewed changes

Copilot reviewed 2 out of 4 changed files in this pull request and generated 5 comments.

File Description
xtask/src/compat_matrix.rs New module implementing the compat-matrix command: parses device/game YAML manifests, aggregates by vendor, generates vendor-grouped COMPATIBILITY.md and compat/matrix.json
xtask/src/main.rs Registers the compat_matrix module and adds the CompatMatrix subcommand variant to the CLI enum

Comment on lines +237 to +244
fn generate_markdown(
devices: &[MatrixDevice],
games: &[MatrixGame],
vendors: &[VendorSummary],
devices_by_tier: &BTreeMap<String, usize>,
games_by_tier: &BTreeMap<String, usize>,
vendor_map: &BTreeMap<String, Vec<MatrixDevice>>,
) -> Result<String> {
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

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

The generate_markdown function accepts both a devices: &[MatrixDevice] slice (used only for computing summary counts at lines 257–266) and a vendor_map: &BTreeMap<String, Vec<MatrixDevice>> (which contains all the same device data). Since summary counts such as total devices, devices with axes, etc. can be derived directly from vendor_map by iterating its values, the devices parameter is redundant and creates confusion about the single source of truth. Consider removing devices and computing summary counts from vendor_map instead.

Copilot uses AI. Check for mistakes.
Comment on lines +373 to +480
fn parse_device(path: &Path) -> Result<MatrixDevice> {
let text = fs::read_to_string(path)?;
let doc: serde_yaml::Value = serde_yaml::from_str(&text)?;

Ok(MatrixDevice {
name: doc["device"]["name"].as_str().unwrap_or("?").to_string(),
vendor: doc["device"]["vendor"]
.as_str()
.unwrap_or("?")
.to_string(),
vendor_id: doc["device"]["usb"]["vendor_id"]
.as_u64()
.map_or_else(|| "?".to_string(), |v| format!("0x{v:04X}")),
product_id: doc["device"]["usb"]["product_id"]
.as_u64()
.map_or_else(|| "?".to_string(), |v| format!("0x{v:04X}")),
axes: doc["capabilities"]["axes"]["count"].as_u64().unwrap_or(0),
buttons: doc["capabilities"]["buttons"].as_u64().unwrap_or(0),
force_feedback: doc["capabilities"]["force_feedback"]
.as_bool()
.unwrap_or(false),
tier: doc["support"]["tier"].as_u64().unwrap_or(0),
test_coverage: DeviceTestCoverage {
simulated: doc["support"]["test_coverage"]["simulated"]
.as_bool()
.unwrap_or(false),
hil: doc["support"]["test_coverage"]["hil"]
.as_bool()
.unwrap_or(false),
},
})
}

fn parse_game(path: &Path) -> Result<MatrixGame> {
let text = fs::read_to_string(path)?;
let doc: serde_yaml::Value = serde_yaml::from_str(&text)?;

let control_injection = {
let ci = &doc["features"]["control_injection"];
let std_events = ci["standard_events"].as_bool().unwrap_or(false);
let direct = ci["direct"].as_bool().unwrap_or(false);
let dataref = ci["dataref_write"].as_bool().unwrap_or(false);
let commands = ci["commands"].as_bool().unwrap_or(false);
std_events || direct || dataref || commands
};

Ok(MatrixGame {
name: doc["game"]["name"].as_str().unwrap_or("?").to_string(),
id: doc["game"]["id"].as_str().unwrap_or("?").to_string(),
mechanism: doc["integration"]["mechanism"]
.as_str()
.unwrap_or("?")
.to_string(),
crate_name: doc["integration"]["crate"]
.as_str()
.unwrap_or("?")
.to_string(),
features: GameFeatures {
telemetry_read: doc["features"]["telemetry_read"]
.as_bool()
.unwrap_or(false),
control_injection,
force_feedback_translation: doc["features"]["force_feedback_translation"]
.as_bool()
.unwrap_or(false),
aircraft_detection: doc["features"]["aircraft_detection"]
.as_bool()
.unwrap_or(false),
},
test_coverage: GameTestCoverage {
trace_replay: doc["test_coverage"]["trace_replay"]
.as_bool()
.unwrap_or(false),
hil: doc["test_coverage"]["hil"].as_bool().unwrap_or(false),
},
tier: doc["support_tier"].as_u64().unwrap_or(0),
})
}

// ---------- helpers ----------

fn collect_manifests(dir: &Path) -> Result<Vec<PathBuf>> {
if !dir.exists() {
return Ok(Vec::new());
}
let mut paths = Vec::new();
collect_yaml(dir, &mut paths);
paths.sort();
Ok(paths)
}

fn collect_yaml(dir: &Path, out: &mut Vec<PathBuf>) {
let Ok(entries) = fs::read_dir(dir) else {
return;
};
for entry in entries.flatten() {
let p = entry.path();
if p.is_dir() {
collect_yaml(&p, out);
} else if p.extension().is_some_and(|e| e == "yaml") {
out.push(p);
}
}
}

fn bool_to_check(v: bool) -> &'static str {
if v { "✓" } else { "✗" }
}
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

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

The compat_matrix module duplicates a large amount of logic already present in compat.rs:

  • parse_device is functionally identical (same YAML field paths, same fallbacks).
  • parse_game is functionally identical.
  • collect_manifests / collect_yaml are byte-for-byte copies.
  • bool_to_check is a copy.
  • GameFeatures and GameTestCoverage are structurally identical structs; DeviceTestCoverage is a renamed copy of TestCoverage.

This means any future change to the YAML schema must be applied in two places. Consider extracting the shared parsing and helper logic into a shared internal module (e.g. compat_shared.rs) that both compat.rs and compat_matrix.rs can reuse.

Copilot uses AI. Check for mistakes.
.with_context(|| format!("Failed to write {json_path}"))?;

println!("✓ Written {md_path} ({} bytes)", md.len());
println!("✓ Written {json_path} ({} bytes)", json_out.len());
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

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

The reported byte count for matrix.json at line 219 (json_out.len()) reflects the serialized JSON string length before the trailing newline is appended on line 215. The file is actually 1 byte larger than reported. This is a minor discrepancy but may be misleading. Use the total written bytes (i.e., json_out.len() + 1) or compute the length from the format string for accuracy.

Suggested change
println!("✓ Written {json_path} ({} bytes)", json_out.len());
println!("✓ Written {json_path} ({} bytes)", json_out.len() + 1);

Copilot uses AI. Check for mistakes.
Comment on lines +72 to +80

/// Generate COMPATIBILITY.md and compat/matrix.json with vendor-grouped stats
CompatMatrix,

Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

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

The enum variant GenCompat (line 73) and GenerateCompat (line 76) both already existed and both call compat::run_gen_compat(). The new CompatMatrix (line 79) adds a third way to generate COMPATIBILITY.md. The docstring for GenerateCompat says "Generate COMPATIBILITY.md and compatibility.json from compat/ manifests" while CompatMatrix says "Generate COMPATIBILITY.md and compat/matrix.json with vendor-grouped stats" — both write to COMPATIBILITY.md but produce different content. The Commands enum now has three overlapping compatibility-generation variants. Consider either consolidating them or clearly differentiating their output file names to avoid user confusion.

Copilot uses AI. Check for mistakes.
Comment on lines +201 to +202
let md_path = "COMPATIBILITY.md";
fs::write(md_path, &md).with_context(|| format!("Failed to write {md_path}"))?;
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

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

Both CompatMatrix (new) and GenCompat/GenerateCompat (existing) write to the same COMPATIBILITY.md file. Running one command after the other will silently overwrite the previous output with no indication to the user. Either the new command should write to a distinct filename (e.g. COMPATIBILITY-MATRIX.md), or the docstrings/descriptions should make it explicit that only one command should be used and its file format takes precedence. The PR description says both generate COMPATIBILITY.md, so users have no clear way to know which output to use.

Copilot uses AI. Check for mistakes.
Comment on lines +155 to +164
let vendors: Vec<VendorSummary> = vendor_map
.iter()
.map(|(name, devs)| VendorSummary {
name: name.clone(),
device_count: devs.len(),
tier_1: devs.iter().filter(|d| d.tier == 1).count(),
tier_2: devs.iter().filter(|d| d.tier == 2).count(),
tier_3: devs.iter().filter(|d| d.tier == 3).count(),
ffb_devices: devs.iter().filter(|d| d.force_feedback).count(),
})

Choose a reason for hiding this comment

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

Action required

1. Vendor tiers hardcoded 🐞 Bug ✓ Correctness

Per-vendor tier counts and the vendor summary table only handle tiers 1–3, but the repo’s device
manifests contain tier 4 and tier 5 devices. This will misreport vendor statistics in both
COMPATIBILITY.md and compat/matrix.json (and makes the tier legend incomplete).
Agent Prompt
### Issue description
`compat-matrix` hardcodes per-vendor tier counts to tiers 1–3, but the manifest dataset includes device tiers 4 and 5. This produces misleading vendor stats and an incomplete tier legend.

### Issue Context
- Device manifests already contain `support.tier: 4` and `support.tier: 5`.
- The generator already builds global tier distributions dynamically (`devices_by_tier`), but vendor summaries do not.

### Fix Focus Areas
- xtask/src/compat_matrix.rs[53-61]
- xtask/src/compat_matrix.rs[155-165]
- xtask/src/compat_matrix.rs[277-295]
- xtask/src/compat_matrix.rs[353-367]

### Implementation notes
- Replace `VendorSummary { tier_1, tier_2, tier_3 }` with a dynamic `tiers: BTreeMap<String, usize>` (or `BTreeMap<u64, usize>`) and update JSON + markdown generation accordingly.
- Alternatively, if tiers are known/fixed (1–5), add explicit fields for tier_4/tier_5 and update the vendor table header and legend.
- Update the tier legend section to cover all tiers that appear in data (or clearly state which tiers are defined/unsupported).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

EffortlessSteven and others added 3 commits February 28, 2026 20:44
- Use dynamic tier tracking (BTreeMap<u64, usize>) instead of hardcoded 1-3
- Remove redundant devices parameter from generate_markdown
- Fix byte count for matrix.json (len + 1 for trailing newline)
- Consolidate with existing compat command (remove CompatMatrix variant)
- Reuse parsing from compat.rs (shared types and helper functions)
- Dynamic vendor table columns and tier legend based on data

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Remove redundant vendors/devices_by_tier/games_by_tier parameters from
  generate_markdown; compute summary counts from vendor_map.values().flatten()
- CompatMatrix writes to COMPATIBILITY-MATRIX.md to avoid overlap with
  existing COMPATIBILITY.md generation
- Update command descriptions and module docs to reflect new output path

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add xtask/src/generate_compat.rs module that:
- Scans compat/devices/ and compat/games/ YAML manifests
- Parses device quirks from YAML into the DeviceEntry type
- Generates COMPATIBILITY.md sorted by vendor -> name with quirks column
- Generates compat/compatibility.json for programmatic consumption
- Validates required fields and tier ranges on all manifests
- Includes 11 unit tests covering:
  - Device parser (valid, missing fields, invalid tier)
  - Game parser (valid, missing features, invalid tier)
  - Generator output (markdown structure, tier counts, sort order)

Wire Commands::GenerateCompat to the new module (gen-compat
still uses compat_matrix for backward compatibility).

Update CI to use 'cargo xtask generate-compat' and diff both
COMPATIBILITY.md and compat/compatibility.json.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@EffortlessSteven EffortlessSteven changed the title feat(xtask): add compat-matrix generator from device manifests feat(xtask): add generate-compat command with quirks and comprehensive tests Mar 1, 2026
Address review comments on PR #36:
- Remove redundant devices param from generate_compat::generate_markdown,
  derive device list and tier counts from vendors map
- Extract shared tier-counting helpers (compute_devices_by_tier,
  compute_games_by_tier) into compat.rs to eliminate duplicated logic
- Make support tier legend dynamic instead of hardcoded tiers 1-3,
  using tier_meaning() helper (supports tiers 1-5 with fallback)
- Widen tier validation from 1..=3 to 1..=5 to match manifest reality
- Clarify GenCompat vs GenerateCompat command help text to distinguish
  output filenames (COMPATIBILITY-MATRIX.md vs COMPATIBILITY.md)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants