Skip to content

compat: audit Productive Metalworks fail-closed boundary - #46

Merged
swear01 merged 8 commits into
mainfrom
compat/issue-42-productivemetalworks
Aug 2, 2026
Merged

compat: audit Productive Metalworks fail-closed boundary#46
swear01 merged 8 commits into
mainfrom
compat/issue-42-productivemetalworks

Conversation

@swear01

@swear01 swear01 commented Jul 31, 2026

Copy link
Copy Markdown
Owner

Summary

Closes #42.

Evidence-backed Outcome C (fail-closed) for Productive Metalworks 1.21.1-1.15.0: the current Compat Kit audit rejects all five actual Foundry/casting/alloying/entity Recipe classes because no complete multiblock/live-state simulate-then-commit contract exists. The present-mod module loads and registers zero stations, resource kinds, and recipe families through the public modular SDK. Vanilla-class recipes under the PMW namespace remain covered by Auto Storage's built-in exact families.

The GitHub issue #42 body was initially mis-templated as Oritech; the authoritative scope of this branch is Productive Metalworks per the compatibility coordinator and umbrella #33.

Rebased onto current origin/main 61aaf32f4faa263d8c3c6c6281f5ad81adc2e8b7 (Railcraft PR #58). The descriptor-owned coexistence matrix now includes Productive Metalworks without central Java/workflow lists.

Reproducible evidence

Field Value
Version 1.21.1-1.15.0
CurseForge file 7884786
Curse Maven curse.maven:productivemetalworks-1184570:7884786
Target SHA-256 1dcf9e10fc457c92d9ed466336104927169817cd509ca9ca69dec734f994d124
Official source JDKDigital/productivemetalworks @ 7c6483c51e1a9def633a939ea75e0018dd079ffa
Scanner format 16
Target classes 103
Reachable ancestry 9 exact artifacts / 8 exact coordinates
Target recipe data 1,118 declared / 1,118 effective
Actual recipe candidates 5

Migration from the legacy scanner removed 18 name-shaped false positives (datagen builders, JEI categories, serializers, RecipeHelper, CastingRecipeEvent, and ICastingRecipe). The five actual candidates are:

  • BlockCastingRecipe
  • EntityMeltingRecipe
  • FluidAlloyingRecipe
  • ItemCastingRecipe
  • ItemMeltingRecipe

All five remain explicitly rejected. No typed resources or approximate Foundry fuel/cooling behavior were introduced.

Matrix evidence

Module recipeInventory SHA-256 Count
Productive Metalworks 8519ac6300242a3bb29d02a53598c0b2ab979a05336ede8dec816faef443b8cb 583
Productive Bees 29eae13b02c34d2f44c4dd2bbc5aefe44e1dbf054c19c9c6e099f61e6b2367b9 617
AE2 387d86fe1576cf7b0f887dea819ced43dcd650f9934d89c6003160b53c010895 511
Combined Craftable catalog 14,990

The 10k matrix passed all three tests. Current local measurements stayed within the existing gates: first switch 1.209 ms, switch p95 1.312 ms, warm switch p95 0.499 ms, shared retained index 9,202,456 bytes, and per-menu retained heap 114,675 bytes.

TDD and verification

Two current-head regressions were observed before correction:

  1. the PMW audit was still legacy scanner format 7 rather than the required current format 16;
  2. the contract's matrix evidence marker referenced a removed module-specific assertion.

Both now have exact regression coverage in scripts/test_modular_compat_sdk.py.

Gate Result
Head fcf52ce8e08af1e3b503c4e666bdb28b50049322
Compat Kit bundled verification 12/12 checks across 5/5 commands
./gradlew build passed
minimum/latest compatible EMI compile passed (1.1.24+1.21.1)
./gradlew stageAe2CompatAuditAncestry passed
base GameTest passed
recipe-addon GameTest passed
descriptor fixture aggregate passed
Productive Metalworks fixture 8/8 passed
PneumaticCraft fixture 9/9 passed
compatibility matrix 3/3 passed, 14,990 recipes
PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover scripts 547/547 passed
./gradlew runData passed, zero files written
git diff --check clean

Every Gradle invocation in the shared local workspace ran through heavy_gradle.py.

Docs

  • docs/productivemetalworks-compatibility.md
  • docs/productivebees-compatibility.md
  • docs/notes.md
  • docs/plan.md
  • docs/roadmap.md

Outcome and remaining risk

C — audited, present-mod tested, fail-closed, and zero custom production families.

Melting, alloying, and casting remain unsupported until a generic contract can represent Foundry multiblock composition, live fuel temperature/speed/consumption/upgrades, casting cooling independent of mutable block-entity/config state, and optional event-injected recipes without approximating those conditions. The representative artifact is CI evidence only and is not a player-facing exact dependency pin.

Test plan

  • Current format-16 audit and reviewed contract
  • Exact artifact/source/ancestry/recipe-data regression
  • Present-mod fixture and full descriptor aggregate
  • Compatibility matrix and performance/heap gates
  • Full local CI-equivalent mechanical gate
  • First latest-head Codex review addressed one stale-roadmap finding with a RED→GREEN regression
  • Latest-head clean external GitHub review bot
  • Remote GitHub CI

Made with Cursor

@swear01
swear01 marked this pull request as ready for review July 31, 2026 19:18

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request integrates compatibility support for the "Productive Metalworks" mod (version 1.21.1-1.15.0) using the Compat Kit. Following an audit of 23 recipe-class candidates, a fail-closed boundary is established with zero registered production families due to their reliance on live multiblock or block-entity states. The changes include adding the audit, contract, compat module, and an isolated GameTest fixture with eight tests, alongside updating the compatibility matrix to lock the new 14-mod workload baseline of 12,232 recipes. The review feedback recommends improving the robustness of the registry checks in both the isolated fixture and the compatibility matrix by verifying the namespace in addition to the path prefix, and correcting a misleading error message regarding the unique recipe type count.

Comment on lines +23 to +30
if (!ModList.get().isLoaded("productivemetalworks")
|| AutoStorage.MACHINE_DESCRIPTOR_REGISTRY.keySet().stream()
.anyMatch(id -> id.getPath().startsWith("productivemetalworks_"))
|| AutoStorage.RECIPE_FAMILY_REGISTRY.keySet().stream()
.anyMatch(id -> id.getPath().startsWith("productivemetalworks_"))) {
helper.fail("Productive Metalworks unsafe foundry contract was registered");
return;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

Failing with a misleading message when the mod is not loaded makes debugging difficult. Additionally, checking only the path prefix can miss registrations under the productivemetalworks namespace. Separating the mod-loaded check and expanding the registry search to include the namespace improves test robustness.

        if (!ModList.get().isLoaded("productivemetalworks")) {
            helper.fail("Productive Metalworks mod is not loaded");
            return;
        }
        if (AutoStorage.MACHINE_DESCRIPTOR_REGISTRY.keySet().stream()
                        .anyMatch(id -> id.getNamespace().equals("productivemetalworks") || id.getPath().startsWith("productivemetalworks_"))
                || AutoStorage.RECIPE_FAMILY_REGISTRY.keySet().stream()
                        .anyMatch(id -> id.getNamespace().equals("productivemetalworks") || id.getPath().startsWith("productivemetalworks_"))) {
            helper.fail("Productive Metalworks unsafe foundry contract was registered");
            return;
        }

Comment on lines +136 to +139
if (types.size() != 4) {
helper.fail("Audited Productive Metalworks recipe type is empty");
return;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

The error message is misleading when the unique recipe type count is not equal to 4, as it incorrectly claims the recipe type is empty. Updating the message to reflect the actual mismatch improves clarity.

Suggested change
if (types.size() != 4) {
helper.fail("Audited Productive Metalworks recipe type is empty");
return;
}
if (types.size() != 4) {
helper.fail("Expected 4 unique audited Productive Metalworks recipe types, but found " + types.size());
return;
}

Comment on lines +85 to +91
if (AutoStorage.MACHINE_DESCRIPTOR_REGISTRY.keySet().stream()
.anyMatch(id -> id.getPath().startsWith("productivemetalworks_"))
|| AutoStorage.RECIPE_FAMILY_REGISTRY.keySet().stream()
.anyMatch(id -> id.getPath().startsWith("productivemetalworks_"))) {
helper.fail("Productive Metalworks fail-closed boundary changed");
return;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

Checking only the path prefix can miss descriptors or families registered under the productivemetalworks namespace. Including a namespace check prevents potential bypasses of the fail-closed boundary.

Suggested change
if (AutoStorage.MACHINE_DESCRIPTOR_REGISTRY.keySet().stream()
.anyMatch(id -> id.getPath().startsWith("productivemetalworks_"))
|| AutoStorage.RECIPE_FAMILY_REGISTRY.keySet().stream()
.anyMatch(id -> id.getPath().startsWith("productivemetalworks_"))) {
helper.fail("Productive Metalworks fail-closed boundary changed");
return;
}
if (AutoStorage.MACHINE_DESCRIPTOR_REGISTRY.keySet().stream()
.anyMatch(id -> id.getNamespace().equals("productivemetalworks") || id.getPath().startsWith("productivemetalworks_"))
|| AutoStorage.RECIPE_FAMILY_REGISTRY.keySet().stream()
.anyMatch(id -> id.getNamespace().equals("productivemetalworks") || id.getPath().startsWith("productivemetalworks_"))) {
helper.fail("Productive Metalworks fail-closed boundary changed");
return;
}

@swear01

swear01 commented Aug 1, 2026

Copy link
Copy Markdown
Owner Author

Follow-up evidence (dc8c9d1)

Validated Gemini findings on head 05332d4 and applied only the confirmed test hardening (TDD).

Finding validation

  • Namespace + path registry checks: valid. Path-prefix-only misses productivemetalworks:* DeferredRegister identities; PneumaticCraft already namespace-guards fail-closed families. Fixture + matrix now reject namespace.equals("productivemetalworks") || path.startsWith("productivemetalworks_").
  • Separate missing-mod message: valid. Previous !isLoaded || anyMatch(...) failed with “unsafe foundry contract was registered”.
  • Unique recipe-type count message: valid. types.size() != 4 previously claimed the type was empty.

Changes

  • ProductivemetalworksIntegrationGameTests
  • CompatibilityMatrixGameTests
  • Static regression: test_productivemetalworks_registry_checks_cover_namespace_and_path (RED on old code, GREEN after fix)

Verification

Check Result
Static RED→GREEN focused unittest pass
./gradlew runProductivemetalworksGameTestServer via heavy_gradle.py All 8 required tests passed
./gradlew runCompatibilityMatrixGameTestServer via heavy_gradle.py coexistence + classification passed ([++X]); craftable latency gate failed twice on unrelated craftable_prepare_ms (75.940 then 59.326; limit < 50) after one allowed retry — not caused by these assertion changes; threshold not weakened
Docs checked; no documentation update required

No merge and no review-bot trigger from this worker.

@swear01
swear01 force-pushed the compat/issue-42-productivemetalworks branch 2 times, most recently from 0d966e6 to 40cf828 Compare August 2, 2026 09:45
swear01 and others added 7 commits August 2, 2026 18:48
Audit 1.15.0 Foundry/casting candidates as unsafe without a multiblock
transaction contract (outcome C), register an empty present-mod module,
and lock the boundary with fixture, matrix, and CI gates.

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Reject namespace-owned registrations as well as path-prefixed ones, separate
the missing-mod failure message, and report the actual unique recipe-type count.

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Productive Metalworks still contributes Foundry/casting datapack recipes to
RecipeManager while remaining fail-closed for Auto Storage families, so the
combined Theurgy + PMW coexistence gate must lock 13,311 rather than 12,736.

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Preserve Outcome C fail-closed PMW on current main (Bees/Draconic/CAA/AdvAE),
move coexistence to descriptor-owned matrix digests, and lock cross-mod recipe
inventories measured with the full optional pack.

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Matrix recipe-inventory SHA updates must keep committed manifest
contract_sha256 values in sync with the reviewed contracts.

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Updating AE2's coexistence recipe-inventory digest changes the contract
SHA, so committed generation/conformance/resource plans must follow.

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@swear01
swear01 force-pushed the compat/issue-42-productivemetalworks branch from 0b21257 to f724e1c Compare August 2, 2026 11:41
@swear01 swear01 changed the title compat: add Productive Metalworks deterministic recipe integration compat: audit Productive Metalworks fail-closed boundary Aug 2, 2026
@swear01

swear01 commented Aug 2, 2026

Copy link
Copy Markdown
Owner Author

@codex review

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f724e1c41d

ℹ️ 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 thread docs/roadmap.md Outdated
via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@swear01

swear01 commented Aug 2, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Delightful!

Reviewed commit: fcf52ce8e0

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

@swear01
swear01 merged commit 9fc1aae into main Aug 2, 2026
1 check passed
@swear01
swear01 deleted the compat/issue-42-productivemetalworks branch August 2, 2026 12:13
swear01 added a commit that referenced this pull request Aug 2, 2026
Rebase onto #78/#46 keeps peer descriptors untouched; the isolated
fixture now verifies this module's own digest evidence.

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.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.

[Compatibility] Productive Metalworks deterministic recipe integration

1 participant