diff --git a/spec/atomic_ai_engineer_task_schema.yaml b/spec/atomic_ai_engineer_task_schema.yaml new file mode 100644 index 00000000..fa1d474b --- /dev/null +++ b/spec/atomic_ai_engineer_task_schema.yaml @@ -0,0 +1,2397 @@ +# spec/atomic_ai_engineer_task_schema.yaml +# PR #90 — Atomic AI Engineers Task Schema +# Standard: Yeshua +# Version: 1.0.0 +# Authority: Orthogonal Engineering Framework +# +# Purpose: Define the canonical schema for AI agents to autonomously +# diagnose, fix, verify, and submit patches to external open-source +# repositories, with every step enforced by the OE warden stack. +# +# Test case: Farmer's Delight #135 / #1262 +# (NBT → Data Component migration for Cooking Pot stack sizes) + +metadata: + schema_id: "ATOMIC-AI-ENGINEER-TASK-1.0" + schema_version: "1.0.0" + standard: "Yeshua" + pr: 90 + created: "2026-04-04" + authority: "Orthogonal Engineering Framework" + global_mode: "execute" # PR #89 — wardens actively enforce + depends_on: + - "yeshua/axioms/eight_axioms.json" + - "YESHUA_SYSTEM_SCHEMA.yaml" + - "resilience/invariant_spec_v2.freeze" + - "wardens/seraph_unit.py" + - "wardens/ophanim_unit.py" + - "wardens/cherub_unit.py" + - "yeshua_math/peano_invariant_checker.py" + +# ============================================================================= +# TASK DEFINITION — What the AI agent must produce +# ============================================================================= +task_definition: + required_fields: + - field: "task_id" + type: "string" + format: "TASK-YYYY-MM-DD-NNN" + description: "Unique task identifier with date prefix" + yeshua_axiom: 8 # Every artifact is hash-anchored + + - field: "issue_url" + type: "string" + format: "https://github.com/{owner}/{repo}/issues/{number}" + description: "GitHub issue URL for the upstream bug" + yeshua_axiom: 4 # No authority without proof + + - field: "target_repository" + type: "string" + format: "https://github.com/{owner}/{repo}" + description: "External repository where the fix will be submitted" + + - field: "ontological_diagnosis" + type: "object" + description: "Root cause explanation at the architectural level" + properties: + root_cause: + type: "string" + description: "Why the bug exists (architectural reason)" + assumption_violated: + type: "string" + description: "What assumption the original code made that is now false" + causal_chain: + type: "array" + items: "string" + description: "Ordered list of causal steps from root cause to symptom" + falsifies_if: "Root cause does not explain the observed symptom" + + - field: "technical_diagnosis" + type: "object" + description: "Code-level problem identification" + properties: + affected_files: + type: "array" + items: "string" + description: "File paths in the target repo that need changes" + affected_functions: + type: "array" + items: "string" + description: "Function/method names that contain the bug" + data_flow: + type: "string" + description: "How data moves through the broken path" + reference_implementation: + type: "string" + format: "URL" + description: "Link to working code that demonstrates the fix pattern" + falsifies_if: "Identified functions do not participate in the broken data flow" + + - field: "code_fix" + type: "object" + description: "The actual patch" + properties: + patch_format: + type: "string" + enum: ["unified_diff", "file_changes"] + files_changed: + type: "array" + items: + type: "object" + properties: + path: { type: "string" } + additions: { type: "integer", minimum: 0 } + deletions: { type: "integer", minimum: 0 } + diff: { type: "string" } + build_verified: + type: "boolean" + description: "Agent confirmed the target project builds with the fix" + tests_pass: + type: "boolean" + description: "Agent confirmed existing tests still pass" + falsifies_if: "Patch does not compile or breaks existing tests" + + - field: "falsification_conditions" + type: "array" + items: "string" + min_items: 1 + description: > + How to disprove the fix works. At least one condition required. + Each condition must be testable by running the target project. + yeshua_axiom: 1 # Every truth is derivable + +# ============================================================================= +# VERIFICATION REQUIREMENTS — Warden checks that MUST pass +# ============================================================================= +# These map directly to the actual warden unit interfaces. +# With global_mode: "execute", these are blocking gates. +verification_requirements: + + seraph_audit: + description: "SeraphUnit logic audit on the generated patch" + warden: "wardens/seraph_unit.py" + class: "SeraphUnit" + method: "query('scan')" + required_checks: + - check: "logic_audit" + gate: "finding_count == 0 for categories [tautological_condition, unreachable_code, missing_return_path]" + description: "No tautologies, unreachable code, or missing return paths in the fix" + - check: "redundancy_detection" + gate: "finding_count == 0" + description: "No duplicate logic blocks introduced by the fix" + - check: "hallucination_scan" + gate: "finding_count == 0" + description: "No meta-mimicry compliance-theater patterns in the fix" + determinism_requirement: "analysis_hash must be identical across two consecutive scans" + falsifies_if: "SeraphUnit.query('scan') returns finding_count > 0 for any gated category" + + ophanim_cycle_check: + description: "OphanimUnit cycle and entropy check on the fix" + warden: "wardens/ophanim_unit.py" + class: "OphanimUnit" + method: "query('scan')" + required_checks: + - check: "cycle_detection" + gate: "dag_acyclic == true" + invariant: "INV-GLOBAL-006 DAG_CONSISTENCY" + description: "Fix does not introduce import cycles" + - check: "entropy_monitoring" + gate: "finding_count == 0" + invariant: "ATOMIC-AFFECTIVE-005" + description: "No feedback amplification patterns in logs" + - check: "growth_analysis" + gate: "growth_ratio <= 2.0 or growth_ratio is null" + description: "No abnormal log growth spike from the fix" + determinism_requirement: "analysis_hash must be identical across two consecutive scans" + falsifies_if: "OphanimUnit.query('scan') returns dag_acyclic == false or entropy finding_count > 0" + + cherub_documentation: + description: "CherubUnit boundary guard on fix documentation" + warden: "wardens/cherub_unit.py" + class: "CherubUnit" + method: "query('scan')" + required_checks: + - check: "source_verification" + gate: "All claims in PR description have verifiable sources" + description: "No unverifiable 'studies show' or 'experts say' claims" + - check: "timestamp_validation" + gate: "All generated documents contain ISO 8601 timestamps" + description: "Every artifact has explicit timestamp metadata" + - check: "pii_boundary_check" + gate: "finding_count == 0 for severity in [critical, high]" + description: "No PII violations in the fix or its documentation" + falsifies_if: "CherubUnit.query('scan') returns critical or high PII violations" + + peano_invariant_check: + description: "Peano arithmetic invariant check on any numeric logic in the fix" + checker: "yeshua_math/peano_invariant_checker.py" + function: "run_peano_invariant_checker()" + gate: "report.all_passed == true" + applies_when: "Fix modifies arithmetic or numeric stack-size logic" + description_detail: > + For the Farmer's Delight case: the Cooking Pot stores item Count + as an integer. The data fixer must preserve Count values exactly. + No unbounded float literals or float() constructors in the fix. + falsifies_if: "PeanoInvariantReport.all_passed == false" + +# ============================================================================= +# PROOF BUNDLE — Cryptographic verification of the fix +# ============================================================================= +proof_bundle: + description: "Cryptographic proof that the fix is verified and reproducible" + schema_reference: ".github/workflows/pr39-peano-sovereignty.yml" + required_fields: + - field: "task_id" + type: "string" + - field: "environment_hash" + type: "string" + format: "sha256" + description: "SHA-256 of os|python_version|seed" + - field: "merkle_root" + type: "string" + format: "sha256" + description: "Merkle root over SHA-256 hashes of all fix artifacts" + - field: "output_hash" + type: "string" + format: "sha256" + description: "SHA-256 of task_id|merkle_root" + - field: "timestamp" + type: "string" + format: "ISO 8601" + - field: "warden_results" + type: "object" + properties: + seraph_hash: { type: "string", format: "sha256" } + ophanim_hash: { type: "string", format: "sha256" } + cherub_hash: { type: "string", format: "sha256" } + peano_passed: { type: "boolean" } + - field: "node_id" + type: "string" + description: "Identifier of the CI node that produced this bundle" + cross_node_parity: > + If multiple nodes produce bundles, all merkle_root values must be + identical. This is the same parity check used in pr39-peano-sovereignty.yml. + falsifies_if: "Two nodes produce different merkle_root values for the same fix" + +# ============================================================================= +# YESHUA COMPLIANCE — Every task must satisfy all 8 axioms +# ============================================================================= +yeshua_compliance: + axioms_file: "yeshua/axioms/eight_axioms.json" + enforcement: "Each task artifact is wrapped in a YeshuaClaim and verified" + axiom_mapping: + 1_derivable: "ontological_diagnosis.causal_chain traces from root cause to symptom" + 2_reproducible: "proof_bundle.merkle_root is reproducible across environments" + 3_re_verifiable: "All warden scans produce identical analysis_hash on re-run" + 4_no_authority_without_proof: "issue_url points to a real, open GitHub issue" + 5_no_hidden_state: "All fix artifacts are in the proof bundle; nothing omitted" + 6_no_unverifiable_dependency: "reference_implementation URL is accessible and contains working code" + 7_no_economic_gatekeeping: "Fix is submitted as open-source PR; no paywall, subscription, or license fee" + 8_hash_anchored: "Every artifact has SHA-256 hash in the proof bundle" + +# ============================================================================= +# EXPECTED OUTPUTS — What the agent delivers +# ============================================================================= +expected_outputs: + - output: "pull_request_url" + type: "string" + format: "https://github.com/{owner}/{repo}/pull/{number}" + description: "URL of the PR submitted to the target repository" + + - output: "proof_bundle.json" + type: "file" + schema: "See proof_bundle section above" + description: "Cryptographic proof bundle with all warden hashes" + + - output: "verification_report.json" + type: "file" + description: "Full warden scan results" + properties: + seraph_scan: { type: "object", description: "Full SeraphUnit scan output" } + ophanim_scan: { type: "object", description: "Full OphanimUnit scan output" } + cherub_scan: { type: "object", description: "Full CherubUnit scan output" } + peano_report: { type: "object", description: "PeanoInvariantReport.to_dict()" } + all_gates_passed: { type: "boolean" } + timestamp: { type: "string", format: "ISO 8601" } + + - output: "task_manifest.json" + type: "file" + description: "Complete task record with all fields from task_definition" + hash_anchored: true + algorithm: "sha256" + +# ============================================================================= +# WORKFLOW — Execution order (Peano gate sequencing: S(n) = n + 1) +# ============================================================================= +# Per SOP_AI_HANDSHAKE.md: "S(0) = 1, S(n) = n + 1, no gate may be skipped." +workflow: + gate_sequence: + - gate: "S(0)" + name: "ISSUE_ANALYSIS" + action: "Clone target repo, read issue, identify affected code paths" + produces: "task_definition.ontological_diagnosis, task_definition.technical_diagnosis" + blocks_on: "issue_url must resolve to an open GitHub issue" + + - gate: "S(1)" + name: "REFERENCE_STUDY" + action: "Read reference implementation, understand the fix pattern" + produces: "task_definition.technical_diagnosis.reference_implementation" + blocks_on: "Reference URL must be accessible" + + - gate: "S(2)" + name: "CODE_GENERATION" + action: "Generate the fix patch" + produces: "task_definition.code_fix" + blocks_on: "S(0) and S(1) must be complete" + + - gate: "S(3)" + name: "BUILD_VERIFICATION" + action: "Build the target project with the fix applied" + produces: "task_definition.code_fix.build_verified" + blocks_on: "Build must succeed" + + - gate: "S(4)" + name: "TEST_VERIFICATION" + action: "Run existing test suite of target project" + produces: "task_definition.code_fix.tests_pass" + blocks_on: "All existing tests must pass" + + - gate: "S(5)" + name: "SERAPH_AUDIT" + action: "Run SeraphUnit.query('scan') on the fix files" + produces: "verification_report.seraph_scan" + blocks_on: "All gated finding_counts == 0" + + - gate: "S(6)" + name: "OPHANIM_CHECK" + action: "Run OphanimUnit.query('scan') on the fix files" + produces: "verification_report.ophanim_scan" + blocks_on: "dag_acyclic == true, entropy finding_count == 0" + + - gate: "S(7)" + name: "CHERUB_CHECK" + action: "Run CherubUnit.query('scan') on fix documentation" + produces: "verification_report.cherub_scan" + blocks_on: "No critical/high PII violations, sources verifiable" + + - gate: "S(8)" + name: "PEANO_CHECK" + action: "Run peano_invariant_checker if fix touches arithmetic" + produces: "verification_report.peano_report" + blocks_on: "report.all_passed == true (when applicable)" + + - gate: "S(9)" + name: "PROOF_BUNDLE_GENERATION" + action: "Generate proof_bundle.json with Merkle root over all artifacts" + produces: "proof_bundle.json" + blocks_on: "All S(5)-S(8) gates passed" + + - gate: "S(10)" + name: "PR_SUBMISSION" + action: "Open PR on target repository with fix + proof bundle link" + produces: "pull_request_url" + blocks_on: "proof_bundle.json exists and is valid" + +# ============================================================================= +# TEST CASE — Farmer's Delight #135 / #1262 +# ============================================================================= +test_case: + task_id: "TASK-2026-04-04-001" + issue_url: "https://github.com/vectorwing/FarmersDelight/issues/1262" + target_repository: "https://github.com/vectorwing/FarmersDelight" + ontological_diagnosis: + root_cause: > + Minecraft 1.21 changed item data storage from NBT (Named Binary Tag) + to Data Components. Farmer's Delight block entities store items in + nested structures that the vanilla data fixer does not recurse into. + assumption_violated: > + The vanilla data fixer would automatically convert all item storage + from NBT to Data Components, including nested inventories. + causal_chain: + - "CASE 1 (placed block entity): Minecraft 1.21 replaces NBT item storage with Data Components" + - "CASE 1: Vanilla DFU runs V1460.registerBlockEntities; only explicitly registered block entities are traversed" + - "CASE 1: FD block entities not registered → Inventory.Items skipped → Count field dropped → stack sizes reset to 1" + - "CASE 1 FIX: V1460Mixin injects at RETURN, registers all FD block entities with nested DSL.optionalFields path" + - "CASE 2 (Cooking Pot as item): ItemStackComponentizationFix.fixItemStack processes the item's BlockEntityTag" + - "CASE 2: Meal item moved to farmersdelight:meal component, but Count: TAG_Byte not converted to count: TAG_Int" + - "CASE 2: DFU does NOT re-run ItemStackComponentizationFix on components set inside fixItemStack → Count defaults to 1" + - "CASE 2 FIX: ItemStackComponentizationFixMixin explicitly promotes Count: (int)c_b → count: c_i before setComponent" + technical_diagnosis: + affected_files: + - "src/main/java/vectorwing/farmersdelight/common/mixin/V1460Mixin.java" + - "src/main/java/vectorwing/farmersdelight/common/mixin/V3818_3Mixin.java" + - "src/main/java/vectorwing/farmersdelight/common/mixin/ItemStackComponentizationFixMixin.java" + - "src/main/resources/farmersdelight.mixins.json" + affected_functions: + - "V1460.registerBlockEntities (block entity DFU registration — primary fix)" + - "V3818_3.registerTypes lambda$registerTypes$0 (component type registration)" + - "ItemStackComponentizationFix.fixItemStack (cooking pot item Count conversion)" + data_flow: > + CASE 1 — Placed block entity (most common; world upgrade): + World load → DataFixer → V1460.registerBlockEntities → + [cooking_pot not registered] → Inventory.Items skipped → + Count field dropped → stack size reset to 1 + CASE 2 — Cooking Pot stored as item (edge case): + Item stack processed by ItemStackComponentizationFix → + BlockEntityTag.Inventory.Items[Slot 6] not moved to farmersdelight:meal component → + Count lost because DFU does not re-run ItemStackComponentizationFix + on components set inside fixItemStack + reference_implementation: > + https://github.com/Patbox/brewery/tree/main/src/main/java/eu/pb4/brewery/mixin/datafixer + (V1460Mixin.java, V3818_3Mixin.java, ItemStackComponizationFix.java — confirmed working by Patbox) + Patbox comment in issue: https://github.com/vectorwing/FarmersDelight/issues/1262#issuecomment-4160029492 + vectorwing WIP code: https://github.com/vectorwing/FarmersDelight/tree/dev-1.21.1/1.3 + ontological_paradox: > + FALSE SUFFICIENCY: V1460 registration alone is necessary but NOT sufficient. + vectorwing confirmed in issue #1262 (2026-04-01): "it manages to cross over + the meal and container stacks, I couldn't get the stack size (Count) to transfer over." + Three classes are required (confirmed by Patbox): V1460, V3818_3, ItemStackComponentizationFix. + The original PR #90 schema proposed only V1460 — this is the corrected complete fix. + code_fix: + patch_format: "file_changes" + files: + - path: "src/main/java/vectorwing/farmersdelight/common/mixin/V1460Mixin.java" + action: "create" + description: > + Registers all FD block entities (stove, cutting_board, skillet, + cooking_pot, cabinet, basket) in the DFU so Count and all item + data are migrated during world upgrade. The cooking_pot registration + uses DSL.list() (required) and also registers Container as ITEM_STACK. + - path: "src/main/java/vectorwing/farmersdelight/common/mixin/V3818_3Mixin.java" + action: "create" + description: > + Registers farmersdelight:meal and farmersdelight:container as ITEM_STACK + component types in the 1.21 component schema, so the DFU knows their + structure when the cooking pot is stored as an item. + - path: "src/main/java/vectorwing/farmersdelight/common/mixin/ItemStackComponentizationFixMixin.java" + action: "create" + description: > + Moves meal and container data from BlockEntityTag into the new component + format when a cooking pot is stored as an item. The Count field must be + manually converted from old TAG_Byte (Count: 16b) to new int (count: 16) + because the DFU does not re-run ItemStackComponentizationFix on components + set inside fixItemStack. + - path: "src/main/resources/farmersdelight.mixins.json" + action: "modify" + description: "Add V1460Mixin, V3818_3Mixin, ItemStackComponentizationFixMixin to mixins array" + falsification_conditions: + - "Place items with Count > 1 in a Cooking Pot in MC 1.20.1 (placed in world), upgrade to 1.21.1, verify Count is preserved — tests V1460Mixin" + - "Place a Cooking Pot containing 16 servings in a chest as an item in MC 1.20.1, upgrade to 1.21.1, verify meal count is 16 — tests ItemStackComponentizationFixMixin Count conversion" + - "Place enchanted items in a Cooking Pot in MC 1.20.1, upgrade to 1.21.1, verify enchantments are preserved" + - "Existing 1.21.1 worlds with Cooking Pots must not be corrupted by the fix" + - "V1460 registration alone (without ItemStackComponentizationFix) FAILS the item-in-chest test — this is the ontological paradox falsification" + +# ============================================================================= +# ATOMIC TASK LIST — Numbered tasks with pass/fail tests +# Each task is atomic: one action, one verifiable result, no skipping allowed. +# Gate sequencing: T(n) blocks T(n+1). No task may be marked PASS until its +# test condition is confirmed by the AI agent or CI. +# ============================================================================= +atomic_task_list: + + - id: "T-001" + name: "CLONE_AND_INDEX_TARGET_REPO" + action: "Clone vectorwing/FarmersDelight and index the source tree" + command: "git clone https://github.com/vectorwing/FarmersDelight.git" + test: + condition: "src/main/java/ directory exists and is non-empty after clone" + pass: "Directory tree rooted at src/main/java/ contains at least one .java file" + fail: "Clone failed or src/main/java/ is absent" + + - id: "T-002" + name: "LOCATE_DATA_FIXER_REGISTRATION" + action: > + Find the data fixer schema registration file. Search for 'Schema1460' + or 'registerBlockEntities' in the source tree. + command: "grep -r 'Schema1460\\|registerBlockEntities' src/ --include='*.java' -l" + test: + condition: "At least one .java file is returned by the grep" + pass: "File path printed; agent notes whether a Schema1460Mixin already exists" + fail: "No file found — data fixer layer is absent; escalate before proceeding" + + - id: "T-003" + name: "CONFIRM_FD_BLOCK_ENTITIES_UNREGISTERED" + action: > + Confirm that FD block entities (cooking_pot, stove, cutting_board, skillet, + cabinet, basket) are NOT registered in any data fixer mixin. + Search for V1460Mixin and any DFU registration of FD entity IDs. + command: "grep -r 'V1460\\|cooking_pot\\|farmersdelight.*register' src/ --include='*.java'" + test: + condition: "No V1460Mixin exists and farmersdelight block entities are absent from DFU registration" + pass: "Bug confirmed: no DFU mixin registers FD block entities" + fail: "V1460Mixin already exists — check if it is complete (all 5 block entities + correct DSL)" + + - id: "T-004" + name: "STUDY_REFERENCE_IMPLEMENTATIONS" + action: > + Read Patbox's Brewery reference implementation and vectorwing's own WIP code. + Three files are required: V1460Mixin, V3818_3Mixin, ItemStackComponentizationFixMixin. + Patbox confirmed all three in: https://github.com/vectorwing/FarmersDelight/issues/1262#issuecomment-4160029492 + references: + - "https://github.com/Patbox/brewery/blob/main/src/main/java/eu/pb4/brewery/mixin/datafixer/V1460Mixin.java" + - "https://github.com/vectorwing/FarmersDelight/tree/dev-1.21.1/1.3 (vectorwing WIP)" + test: + condition: "Agent can describe the role of each of the three mixin classes" + pass: | + V1460Mixin: registers block entities in DFU schema (placed-in-world case) + V3818_3Mixin: registers component types so DFU knows farmersdelight:meal is ITEM_STACK + ItemStackComponentizationFixMixin: moves BlockEntityTag to components when cooking pot is an item; + must manually convert Count: TAG_Byte → count: int (DFU does not re-run on set components) + fail: "Agent cannot explain why all three files are needed" + + - id: "T-005" + name: "CREATE_THREE_DFU_MIXIN_FILES" + action: > + Create all three mixin files and update farmersdelight.mixins.json. + File locations follow the existing mixin package: vectorwing.farmersdelight.common.mixin. + CRITICAL: The lambda method name in V3818_3Mixin is 'lambda$registerTypes$0' + for NeoForge 1.21.1 (it was renamed to 'components' in NeoForge 26.1+). + files: + - "src/main/java/vectorwing/farmersdelight/common/mixin/V1460Mixin.java" + - "src/main/java/vectorwing/farmersdelight/common/mixin/V3818_3Mixin.java" + - "src/main/java/vectorwing/farmersdelight/common/mixin/ItemStackComponentizationFixMixin.java" + - "src/main/resources/farmersdelight.mixins.json" + patch_v1460: | + package vectorwing.farmersdelight.common.mixin; + + import com.mojang.datafixers.DSL; + import com.mojang.datafixers.schemas.Schema; + import com.mojang.datafixers.types.templates.TypeTemplate; + import net.minecraft.util.datafix.fixes.References; + import net.minecraft.util.datafix.schemas.V1460; + import org.spongepowered.asm.mixin.Mixin; + import org.spongepowered.asm.mixin.Shadow; + import org.spongepowered.asm.mixin.Unique; + import org.spongepowered.asm.mixin.injection.At; + import org.spongepowered.asm.mixin.injection.Inject; + import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + import vectorwing.farmersdelight.FarmersDelight; + + import java.util.Map; + import java.util.function.Supplier; + + @Mixin(V1460.class) + public abstract class V1460Mixin extends Schema + { + @Shadow + protected static void registerInventory(Schema schema, Map> map, String name) {} + + public V1460Mixin(int versionKey, Schema parent) { + super(versionKey, parent); + } + + @Inject(method = "registerBlockEntities", at = @At("RETURN")) + private void registerFarmersDelightBlockEntities(Schema schema, CallbackInfoReturnable>> cir) { + var map = cir.getReturnValue(); + + // Workstations: store items in Inventory.Items (nested via ItemStackHandler) + farmersdelight$registerHandlerInventory(schema, map, farmersdelight$id("stove")); + farmersdelight$registerHandlerInventory(schema, map, farmersdelight$id("cutting_board")); + farmersdelight$registerHandlerInventory(schema, map, farmersdelight$id("skillet")); + + // Cooking Pot: nested Inventory.Items + separate Container ITEM_STACK + schema.register(map, farmersdelight$id("cooking_pot"), p_17586_ -> + DSL.optionalFields( + "Inventory", DSL.optionalFields("Items", DSL.list(References.ITEM_STACK.in(schema))), + "Container", References.ITEM_STACK.in(schema) + )); + + // Storage blocks: flat Items list (vanilla registerInventory works) + registerInventory(schema, map, farmersdelight$id("cabinet")); + registerInventory(schema, map, farmersdelight$id("basket")); + } + + @Unique + private static String farmersdelight$id(String path) { + return FarmersDelight.MODID + ":" + path; + } + + @Unique + private static void farmersdelight$registerHandlerInventory(Schema schema, Map> map, String name) { + schema.register(map, name, string -> DSL.optionalFields("Inventory", DSL.optionalFields("Items", DSL.list(References.ITEM_STACK.in(schema))))); + } + } + patch_v3818_3: | + package vectorwing.farmersdelight.common.mixin; + + import com.llamalad7.mixinextras.sugar.Local; + import com.mojang.datafixers.schemas.Schema; + import com.mojang.datafixers.types.templates.TypeTemplate; + import com.mojang.datafixers.util.Pair; + import net.minecraft.util.datafix.fixes.References; + import net.minecraft.util.datafix.schemas.V3818_3; + import org.spongepowered.asm.mixin.Mixin; + import org.spongepowered.asm.mixin.injection.At; + import org.spongepowered.asm.mixin.injection.ModifyArg; + + import java.util.ArrayList; + import java.util.List; + + @Mixin(V3818_3.class) + public class V3818_3Mixin + { + // NOTE: method name is the lambda name in NeoForge 1.21.1. + // In NeoForge 26.1+ it was renamed to "components". + // Use IntelliJ View > Show Bytecode to verify the lambda name for your build. + @ModifyArg(method = "lambda$registerTypes$0", at = @At(value = "INVOKE", target = "Lcom/mojang/datafixers/DSL;optionalFields([Lcom/mojang/datafixers/util/Pair;)Lcom/mojang/datafixers/types/templates/TypeTemplate;")) + private static Pair[] addFDCustomComponents(Pair[] components, @Local(argsOnly = true) Schema schema) { + var list = new ArrayList<>(List.of(components)); + list.add(Pair.of("farmersdelight:meal", References.ITEM_STACK.in(schema))); + list.add(Pair.of("farmersdelight:container", References.ITEM_STACK.in(schema))); + return list.toArray(components); + } + } + patch_item_stack_fix: | + package vectorwing.farmersdelight.common.mixin; + + import com.mojang.serialization.Dynamic; + import net.minecraft.util.datafix.fixes.ItemStackComponentizationFix; + import org.spongepowered.asm.mixin.Mixin; + import org.spongepowered.asm.mixin.injection.At; + import org.spongepowered.asm.mixin.injection.Inject; + import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + + import java.util.List; + + @SuppressWarnings({"rawtypes"}) + @Mixin(ItemStackComponentizationFix.class) + public class ItemStackComponentizationFixMixin + { + @Inject(method = "fixItemStack", at = @At("HEAD")) + private static void fixCustomStacks(ItemStackComponentizationFix.ItemStackData data, Dynamic tag, CallbackInfo ci) { + if (data.is("farmersdelight:cooking_pot")) { + data.fixSubTag("BlockEntityTag", false, subTag -> { + // Container: count is always 1 for bowl/bottle containers + data.setComponent("farmersdelight:container", subTag.get("Container")); + + // Meal: manually convert Count (old TAG_Byte) to count (new TAG_Int). + // The DFU does NOT re-run ItemStackComponentizationFix on components + // that are set inside fixItemStack — the Count would be silently dropped + // (reset to 1) without this explicit conversion. + List> items = subTag.get("Inventory").get("Items") + .asList(itemTag -> { + int count = itemTag.get("Count").asNumber(1).result() + .map(Number::intValue).orElse(1); + Dynamic converted = itemTag.remove("Slot").remove("Count"); + if (count > 1) { + converted = converted.set("count", converted.createInt(count)); + } + return converted; + }); + if (!items.isEmpty()) { + data.setComponent("farmersdelight:meal", items.getFirst()); + } + return subTag.remove("Container").remove("Inventory"); + }); + data.removeTag("BlockEntityTag"); + } + } + } + patch_mixins_json: | + // In farmersdelight.mixins.json, add to "mixins" array: + "ItemStackComponentizationFixMixin", + "V1460Mixin", + "V3818_3Mixin", + test: + condition: "./gradlew compileJava exits with code 0 after all three files are created" + pass: "BUILD SUCCESSFUL with zero compilation errors across all three mixin files" + fail: "Compilation error — verify lambda method name for V3818_3 (may need bytecode inspection)" + + - id: "T-006" + name: "BUILD_TARGET_PROJECT" + action: "Build the full Farmer's Delight project with the mixin applied" + command: "./gradlew build" + test: + condition: "Gradle build exits with code 0" + pass: "BUILD SUCCESSFUL" + fail: "BUILD FAILED — fix compilation error before proceeding" + + - id: "T-007" + name: "RUN_EXISTING_TEST_SUITE" + action: "Run any existing tests in the target project" + command: "./gradlew test" + test: + condition: "All existing tests pass (or no tests exist — both are PASS)" + pass: "Test suite exits with code 0 or reports 'No tests found'" + fail: "Any pre-existing test fails due to the patch" + + - id: "T-008" + name: "STATIC_ANALYSIS_CHECK" + action: > + Run static analysis on the patch. Check for: tautological conditions, + unreachable code, duplicate logic blocks, missing return paths. + (Internal: SeraphUnit.query('scan'); External: any static analysis tool + available in the target project, e.g. checkstyle, spotbugs, or manual review) + command: "./gradlew check 2>/dev/null || echo 'No check task; manual review required'" + test: + condition: "No tautologies, unreachable code, or duplicate logic in the patch" + pass: "Static analysis clean or manual review finds zero issues in T-005 patch" + fail: "Tautological condition, unreachable branch, or duplicate block found in patch" + + - id: "T-009" + name: "CYCLE_AND_DEPENDENCY_CHECK" + action: > + Confirm the mixin does not introduce circular imports or unexpected + dependency on transitive classes not already in the project's compile scope. + command: "./gradlew dependencies 2>/dev/null | grep -i 'circular\\|cycle' || echo 'No cycles detected'" + test: + condition: "Import graph remains acyclic after patch" + pass: "No circular dependency reported" + fail: "Circular dependency introduced — refactor import structure" + + - id: "T-010" + name: "DOCUMENTATION_VALIDATION" + action: > + Confirm the PR description contains: (a) a link to the upstream issue, + (b) an ISO 8601 timestamp, (c) no unverifiable claims ('studies show', + 'experts say', etc.), (d) no PII. + test: + condition: "PR description satisfies all four documentation requirements" + pass: "Issue link present, timestamp present, no unverifiable claims, no PII" + fail: "Any documentation requirement missing" + + - id: "T-011" + name: "ARITHMETIC_INTEGRITY_CHECK" + action: > + Verify the patch contains no unbounded float literals or float() casts + in any numeric path that touches item Count or stack size values. + Item Count is an integer (NBT TAG_Int / Data Component integer). + test: + condition: "grep -n 'float\\|Float\\|double\\|Double' returns no hits in Count/stack-size paths" + pass: "No float arithmetic in the data migration path" + fail: "Float found in Count arithmetic — replace with integer arithmetic" + + - id: "T-012" + name: "GENERATE_VERIFICATION_REPORT" + action: > + Produce verification_report.json containing results of T-005 through T-011. + Each task entry must include: task_id, name, pass (bool), evidence (string). + output_file: "verification_report.json" + schema: + type: "object" + properties: + task_id: { type: "string" } + generated_at: { type: "string", format: "ISO 8601" } + tasks: + type: "array" + items: + type: "object" + properties: + id: { type: "string" } + name: { type: "string" } + pass: { type: "boolean" } + evidence: { type: "string" } + all_passed: { type: "boolean" } + test: + condition: "all_passed == true in verification_report.json" + pass: "All 12 tasks in verification_report.json have pass: true" + fail: "Any task has pass: false — fix that task before proceeding" + + - id: "T-013" + name: "SUBMIT_PR_TO_TARGET_REPO" + action: > + Open a pull request on vectorwing/FarmersDelight with: + - Title: 'fix: register FD block entities in DFU and fix Cooking Pot item Count migration (fixes #1262)' + - Body: copy-paste from secular_developer_patch.pr_body (see below) + - Linked issue: #1262 + test: + condition: "PR URL is returned and PR is in 'open' state" + pass: "https://github.com/vectorwing/FarmersDelight/pull/{N} is accessible and open" + fail: "PR creation failed or PR was immediately closed/rejected by bot" + +# ============================================================================= +# SECULAR DEVELOPER PATCH +# ───────────────────────────────────────────────────────────────────────────── +# COPY-PASTE THIS SECTION FOR EXTERNAL PR SUBMISSION. +# No internal tooling names, no theological naming. +# Everything here is verifiable by any Java developer with a Minecraft modding +# environment. Paste pr_body directly into the GitHub PR description field. +# +# CORRECTION FROM ORIGINAL PR #90 SCHEMA: +# The original schema proposed only a V1460 mixin (Schema1460Mixin). +# This is NECESSARY but NOT SUFFICIENT. +# vectorwing confirmed (2026-04-01): V1460 alone finds items but Count is lost. +# The complete fix requires THREE mixin files (confirmed by Patbox). +# This corrected section reflects the complete fix including the Count bug. +# ============================================================================= +secular_developer_patch: + + issue_reference: "https://github.com/vectorwing/FarmersDelight/issues/1262" + target_repository: "https://github.com/vectorwing/FarmersDelight" + pr_title: "fix: register FD block entities in DFU and fix Cooking Pot item Count migration (fixes #1262)" + timestamp: "2026-04-04T02:22:38Z" + + # ── COPY THIS BLOCK AS THE PR BODY ────────────────────────────────────────── + pr_body: | + ## Problem + + When upgrading a world from Minecraft 1.20.1 to 1.21+, items stored inside + Farmer's Delight block entities (Cooking Pot, Cabinets, Baskets, Stove, + Cutting Board, Skillet) lose their **stack size** (Count resets to 1) and + other NBT data. Additionally, a Cooking Pot stored as an **item** (e.g., in + a chest or player inventory) loses its meal's stack count on upgrade. + + Reported in: https://github.com/vectorwing/FarmersDelight/issues/1262 + + --- + + ## Root Cause — Two Separate Issues + + ### Issue 1: Placed block entities (world upgrade — most common) + + Minecraft 1.21 migrated item data storage from NBT to **Data Components**. + This migration is performed by `DataFixerUpper`, which must explicitly know + every block entity type that contains items. This is registered in `V1460` + (Minecraft's data fixer schema for block entities, introduced in 1.13). + + Farmer's Delight uses NeoForge's `ItemStackHandler` to store items, which + wraps them in an extra `Inventory` NBT layer: + + BlockEntityTag → Inventory → Items → [list of ITEM_STACK] + + None of the FD block entities were registered in the DFU, so the fixer + never traverses into `Inventory.Items`. All item data, including `Count`, + is silently dropped. + + ### Issue 2: Cooking Pot stored as an item (edge case) + + When a Cooking Pot is stored as an item (e.g., picked up by Carry On or + similar mods), its meal and container are stored in `BlockEntityTag`. + `ItemStackComponentizationFix` must move this data to the new component + format (`farmersdelight:meal`, `farmersdelight:container`). However, the + DFU **does not** re-run `ItemStackComponentizationFix` on components set + inside `fixItemStack`, so the `Count` field (`TAG_Byte Count`) is not + automatically converted to the new `int count` format — it defaults to 1. + + --- + + ## Causal Chain + + **Block entity case:** + 1. Minecraft 1.21 replaces NBT item storage with Data Components. + 2. DFU runs `V1460.registerBlockEntities()` on world load. + 3. Only block entities explicitly registered are recursed into. + 4. FD block entities not registered → `Inventory.Items` skipped → `Count` lost. + + **Item case (Cooking Pot as item):** + 1. `ItemStackComponentizationFix.fixItemStack()` processes the Cooking Pot item. + 2. Meal item is moved from `BlockEntityTag.Inventory.Items` to `farmersdelight:meal`. + 3. The moved item is raw old-format NBT: `{Count: 16b, id: "minecraft:bread"}`. + 4. DFU does not re-run `ItemStackComponentizationFix` on the newly-set component. + 5. `Count: 16b` (byte) is never converted to `count: 16` (int) → defaults to 1. + + --- + + ## Fix — Three Mixin Files + + Patbox confirmed the three required classes in this thread: + https://github.com/vectorwing/FarmersDelight/issues/1262#issuecomment-4160029492 + + Reference implementations: https://github.com/Patbox/brewery/tree/main/src/main/java/eu/pb4/brewery/mixin/datafixer + + ### File 1 — `V1460Mixin.java` (fixes placed block entities) + + ```java + package vectorwing.farmersdelight.common.mixin; + + import com.mojang.datafixers.DSL; + import com.mojang.datafixers.schemas.Schema; + import com.mojang.datafixers.types.templates.TypeTemplate; + import net.minecraft.util.datafix.fixes.References; + import net.minecraft.util.datafix.schemas.V1460; + import org.spongepowered.asm.mixin.Mixin; + import org.spongepowered.asm.mixin.Shadow; + import org.spongepowered.asm.mixin.Unique; + import org.spongepowered.asm.mixin.injection.At; + import org.spongepowered.asm.mixin.injection.Inject; + import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + import vectorwing.farmersdelight.FarmersDelight; + + import java.util.Map; + import java.util.function.Supplier; + + @Mixin(V1460.class) + public abstract class V1460Mixin extends Schema + { + @Shadow + protected static void registerInventory(Schema schema, Map> map, String name) {} + + public V1460Mixin(int versionKey, Schema parent) { + super(versionKey, parent); + } + + @Inject(method = "registerBlockEntities", at = @At("RETURN")) + private void registerFarmersDelightBlockEntities(Schema schema, CallbackInfoReturnable>> cir) { + var map = cir.getReturnValue(); + + // Workstations: items in Inventory.Items (ItemStackHandler adds the Inventory wrapper) + farmersdelight$registerHandlerInventory(schema, map, farmersdelight$id("stove")); + farmersdelight$registerHandlerInventory(schema, map, farmersdelight$id("cutting_board")); + farmersdelight$registerHandlerInventory(schema, map, farmersdelight$id("skillet")); + + // Cooking Pot: nested Inventory.Items + separate Container ITEM_STACK + schema.register(map, farmersdelight$id("cooking_pot"), p_17586_ -> + DSL.optionalFields( + "Inventory", DSL.optionalFields("Items", DSL.list(References.ITEM_STACK.in(schema))), + "Container", References.ITEM_STACK.in(schema) + )); + + // Storage blocks: flat Items list — vanilla registerInventory works + registerInventory(schema, map, farmersdelight$id("cabinet")); + registerInventory(schema, map, farmersdelight$id("basket")); + } + + @Unique + private static String farmersdelight$id(String path) { + return FarmersDelight.MODID + ":" + path; + } + + @Unique + private static void farmersdelight$registerHandlerInventory(Schema schema, Map> map, String name) { + schema.register(map, name, string -> + DSL.optionalFields("Inventory", DSL.optionalFields("Items", DSL.list(References.ITEM_STACK.in(schema))))); + } + } + ``` + + ### File 2 — `V3818_3Mixin.java` (registers component types for Cooking Pot item) + + ```java + package vectorwing.farmersdelight.common.mixin; + + import com.llamalad7.mixinextras.sugar.Local; + import com.mojang.datafixers.schemas.Schema; + import com.mojang.datafixers.types.templates.TypeTemplate; + import com.mojang.datafixers.util.Pair; + import net.minecraft.util.datafix.fixes.References; + import net.minecraft.util.datafix.schemas.V3818_3; + import org.spongepowered.asm.mixin.Mixin; + import org.spongepowered.asm.mixin.injection.At; + import org.spongepowered.asm.mixin.injection.ModifyArg; + + import java.util.ArrayList; + import java.util.List; + + @Mixin(V3818_3.class) + public class V3818_3Mixin + { + // NOTE: In NeoForge 1.21.1, this method is a lambda named "lambda$registerTypes$0". + // In NeoForge 26.1+ it was renamed to "components". If this mixin fails to apply, + // use IntelliJ > View > Show Bytecode on V3818_3.class to find the correct name. + @ModifyArg(method = "lambda$registerTypes$0", at = @At(value = "INVOKE", + target = "Lcom/mojang/datafixers/DSL;optionalFields([Lcom/mojang/datafixers/util/Pair;)Lcom/mojang/datafixers/types/templates/TypeTemplate;")) + private static Pair[] addFDCustomComponents( + Pair[] components, @Local(argsOnly = true) Schema schema) { + var list = new ArrayList<>(List.of(components)); + list.add(Pair.of("farmersdelight:meal", References.ITEM_STACK.in(schema))); + list.add(Pair.of("farmersdelight:container", References.ITEM_STACK.in(schema))); + return list.toArray(components); + } + } + ``` + + ### File 3 — `ItemStackComponentizationFixMixin.java` (fixes Cooking Pot item Count) + + ```java + package vectorwing.farmersdelight.common.mixin; + + import com.mojang.serialization.Dynamic; + import net.minecraft.util.datafix.fixes.ItemStackComponentizationFix; + import org.spongepowered.asm.mixin.Mixin; + import org.spongepowered.asm.mixin.injection.At; + import org.spongepowered.asm.mixin.injection.Inject; + import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + + import java.util.List; + + @SuppressWarnings({"rawtypes"}) + @Mixin(ItemStackComponentizationFix.class) + public class ItemStackComponentizationFixMixin + { + @Inject(method = "fixItemStack", at = @At("HEAD")) + private static void fixCustomStacks(ItemStackComponentizationFix.ItemStackData data, Dynamic tag, CallbackInfo ci) { + if (data.is("farmersdelight:cooking_pot")) { + data.fixSubTag("BlockEntityTag", false, subTag -> { + // Container: count is always 1 for bowl/bottle — no conversion needed + data.setComponent("farmersdelight:container", subTag.get("Container")); + + // Meal: must manually convert Count (old TAG_Byte) to count (new TAG_Int). + // The DFU does NOT re-run ItemStackComponentizationFix on components + // set inside fixItemStack. Without this explicit conversion, Count + // defaults to 1 regardless of the original stack size. + List> items = subTag.get("Inventory").get("Items") + .asList(itemTag -> { + int count = itemTag.get("Count").asNumber(1).result() + .map(Number::intValue).orElse(1); + Dynamic converted = itemTag.remove("Slot").remove("Count"); + if (count > 1) { + converted = converted.set("count", converted.createInt(count)); + } + return converted; + }); + if (!items.isEmpty()) { + data.setComponent("farmersdelight:meal", items.getFirst()); + } + return subTag.remove("Container").remove("Inventory"); + }); + data.removeTag("BlockEntityTag"); + } + } + } + ``` + + ### `farmersdelight.mixins.json` — add three entries to "mixins" array + + ```json + "mixins": [ + "ItemStackComponentizationFixMixin", + "V1460Mixin", + "V3818_3Mixin", + ...existing entries... + ] + ``` + + --- + + ## Math / Data Integrity + + **Block entity case (V1460Mixin):** + Let `c ∈ ℤ` be the item count in a placed Cooking Pot. The data fixer + is `F: WorldState → WorldState`. Without fix: `F` skips `Inventory.Items`, + `Count` field absent → Minecraft defaults `c' = 1` (data loss). + With fix: `F` traverses `Inventory → Items → ITEM_STACK` for each item, + vanilla converter maps `Count: TAG_Byte(c) → count: c`, so `c' = c` (identity). + + **Item case (ItemStackComponentizationFixMixin):** + The old format stores count as `Count: TAG_Byte(c)`. In new format, count + is `count: TAG_Int(c)`. Since the DFU does not recursively apply + `ItemStackComponentizationFix` to custom components set inside `fixItemStack`, + the conversion `Count: c_b → count: c_i` must be performed explicitly: + `c_i = (int) c_b` — a lossless integer promotion. No floating-point arithmetic. + Count remains in `ℤ` throughout. For `c = 1` (default), the field is omitted + (Minecraft interprets absent count as 1). + + --- + + ## How to Verify + + **Block entity case (V1460Mixin):** + 1. Create a Minecraft 1.20.1 world with Farmer's Delight installed. + 2. Place a Cooking Pot. Put a stack of 64 bread in it. Fill 3 ingredient slots. + 3. Save and close the world. + 4. Open the world in Minecraft 1.21 with this build. Open the Cooking Pot. + 5. **Expected:** 64 bread present, ingredient slots populated. + 6. **FAIL:** Count resets to 1 — V1460Mixin not applied or DSL.list() missing. + + **Item case (ItemStackComponentizationFixMixin Count fix):** + 1. In 1.20.1, use Carry On (or similar) to pick up a Cooking Pot with 16 meal servings. + 2. Store the cooking pot item in a chest. Save and close. + 3. Open the world in 1.21. Open the chest. Take out the Cooking Pot. Check meal count. + 4. **Expected:** Meal shows 16 servings. + 5. **FAIL:** Meal count is 1 — the explicit Count conversion in ItemStackComponentizationFixMixin + is missing or incorrect. + + **Regression (no corruption of existing 1.21 worlds):** + - Open a 1.21 world with existing Cooking Pots. Verify no item count changes. + - Create a fresh 1.21 Cooking Pot. Put 32 carrots in it. Reload. Verify count unchanged. + + --- + + ## Files Changed + + | File | Change | + |------|--------| + | `src/main/java/.../common/mixin/V1460Mixin.java` | Added | + | `src/main/java/.../common/mixin/V3818_3Mixin.java` | Added | + | `src/main/java/.../common/mixin/ItemStackComponentizationFixMixin.java` | Added | + | `src/main/resources/farmersdelight.mixins.json` | Three mixin entries added | + + --- + + Timestamp: 2026-04-04T02:22:38Z + Issue: https://github.com/vectorwing/FarmersDelight/issues/1262 + + # ── END COPY BLOCK ─────────────────────────────────────────────────────────── + + # Standalone sections for agents that need individual pieces: + + ontological_diagnosis: | + ROOT CAUSE — TWO DISTINCT FAILURE MODES + + FAILURE MODE 1: Placed block entity (world upgrade) + Minecraft 1.21 changed item data storage from NBT to Data Components. + The vanilla DataFixer (V1460.registerBlockEntities) only converts block entity + inventories that are explicitly registered. Farmer's Delight never registered + any of its block entities (stove, cutting_board, skillet, cooking_pot, cabinet, + basket). Because FD uses NeoForge's ItemStackHandler, items are stored in a + nested path: Inventory → Items → [list], not a flat Items list. The vanilla + helper registerInventory() only handles flat lists — FD needs the extra nesting. + + FAILURE MODE 2: Cooking Pot stored as item (Count = 1 after upgrade) + When a Cooking Pot is stored as an item, its meal is in BlockEntityTag.Inventory.Items. + ItemStackComponentizationFix moves this data into the farmersdelight:meal component. + However, the DFU does NOT re-run ItemStackComponentizationFix on components set + inside fixItemStack. This means Count: TAG_Byte is never converted to count: int — + it is silently dropped and defaults to 1. + + ASSUMPTIONS VIOLATED + A1: "V1460 registration alone is sufficient for complete item data migration." + → FALSIFIED by vectorwing's own test (2026-04-01): items found but Count = 1. + A2: "The vanilla DataFixer automatically recurses into all block entity sub-trees." + → FALSIFIED: only explicitly registered types are traversed. + A3: "Setting a component inside fixItemStack causes the DFU to recursively convert it." + → FALSIFIED: DFU does not re-run ItemStackComponentizationFix on newly-set components. + + CAUSAL CHAIN (complete) + C1: MC 1.21 replaces NBT with Data Components. + C2: DataFixer runs V1460.registerBlockEntities. + C3: FD block entities not registered → Inventory.Items skipped (CASE 1). + C4: V1460Mixin registers them → DFU finds items → Count converted (CASE 1 FIXED). + C5: When cooking pot is an item, ItemStackComponentizationFix runs. + C6: Mixin moves meal item to farmersdelight:meal, but Count: TAG_Byte not converted. + C7: DFU does not re-process the component → Count defaults to 1 (CASE 2 UNFIXED). + C8: ItemStackComponentizationFixMixin explicitly converts Count: 16b → count: 16 (CASE 2 FIXED). + + technical_diagnosis: | + AFFECTED FILES (all new) + 1. src/main/java/vectorwing/farmersdelight/common/mixin/V1460Mixin.java + 2. src/main/java/vectorwing/farmersdelight/common/mixin/V3818_3Mixin.java + 3. src/main/java/vectorwing/farmersdelight/common/mixin/ItemStackComponentizationFixMixin.java + 4. src/main/resources/farmersdelight.mixins.json (add three entries) + + AFFECTED FUNCTIONS + - V1460.registerBlockEntities (vanilla; mixin injects @RETURN) + - V3818_3.lambda$registerTypes$0 (vanilla; mixin @ModifyArg) + - ItemStackComponentizationFix.fixItemStack (vanilla; mixin injects @HEAD) + + DATA FLOW — CASE 1 (placed block entity) + BROKEN: World load → DFU → V1460.registerBlockEntities → + [no FD entries] → Inventory.Items skipped → Count lost + FIXED: World load → DFU → V1460.registerBlockEntities → + [V1460Mixin adds FD entries] → Inventory → Items → + each ITEM_STACK converted by vanilla converter → Count preserved + + DATA FLOW — CASE 2 (cooking pot as item) + BROKEN: Cooking pot item processed by ItemStackComponentizationFix → + BlockEntityTag.Inventory.Items[Slot 6] moved to farmersdelight:meal → + raw old-format {Count: 16b, id: "minecraft:bread"} stored → + DFU does not re-run ItemStackComponentizationFix on component → + Count: 16b never converted → defaults to 1 + FIXED: Same as above, but mixin explicitly converts: + Count: 16b → count: 16 before calling setComponent → + farmersdelight:meal = {count: 16, id: "minecraft:bread"} + + CRITICAL DETAIL — V3818_3 lambda method name: + In NeoForge 1.21.1: method is "lambda$registerTypes$0" (anonymous lambda) + In NeoForge 26.1+: method was renamed to "components" + If the mixin fails to apply, use IntelliJ View > Show Bytecode to find the name. + + REFERENCE IMPLEMENTATIONS + Patbox Brewery: https://github.com/Patbox/brewery/tree/main/src/main/java/eu/pb4/brewery/mixin/datafixer + vectorwing WIP (3 files already exist): https://github.com/vectorwing/FarmersDelight/tree/dev-1.21.1/1.3 + + the_math: | + CASE 1 — Block entity (placed in world) + + Let c ∈ ℤ be the item count in a Cooking Pot before upgrade. + Let F: WorldState → WorldState be the data fixer. + + WITHOUT V1460Mixin: + F does not traverse Inventory.Items for farmersdelight:cooking_pot. + Count field absent after conversion → Minecraft default: c' = 1 + Data loss: c' ≠ c for all c ≠ 1. + + WITH V1460Mixin: + F traverses Inventory → Items → [ITEM_STACK_1, ..., ITEM_STACK_n]. + For each ITEM_STACK_i: vanilla converter maps Count: TAG_Byte(c_i) → count: c_i. + c_i' = c_i (identity). No arithmetic transformation. No float. c ∈ ℤ throughout. + + CASE 2 — Cooking Pot as item (stored in chest/inventory) + + Let m ∈ ℤ be the meal count in the Cooking Pot item before upgrade. + Old NBT format: {Count: m_b, id: "minecraft:bread"} where m_b is TAG_Byte. + New format expected by 1.21: {count: m_i, id: "minecraft:bread"} where m_i is TAG_Int. + + WITHOUT Count fix in ItemStackComponentizationFixMixin: + setComponent("farmersdelight:meal", {Count: m_b, id: ...}) + DFU does not re-run ItemStackComponentizationFix on the component. + Count: m_b not converted → Minecraft reads absent count → m' = 1 (default). + Data loss: m' = 1 for all m ≠ 1. + + WITH Count fix: + count = (int) m_b [lossless integer promotion; m_b ∈ [1, 127] ⊂ ℤ] + setComponent("farmersdelight:meal", {count: count, id: ...}) + m' = count = m (identity). No float. No precision loss. m ∈ ℤ throughout. + + Special case: if m = 1, the count field is omitted (Minecraft convention). + Minecraft reads absent count as 1, so m' = 1 = m (identity preserved). + + the_code: | + // ═══════════════════════════════════════════════════════════════════════════ + // FILE 1: V1460Mixin.java — registers FD block entities in DFU + // PATH: src/main/java/vectorwing/farmersdelight/common/mixin/V1460Mixin.java + // ═══════════════════════════════════════════════════════════════════════════ + + package vectorwing.farmersdelight.common.mixin; + + import com.mojang.datafixers.DSL; + import com.mojang.datafixers.schemas.Schema; + import com.mojang.datafixers.types.templates.TypeTemplate; + import net.minecraft.util.datafix.fixes.References; + import net.minecraft.util.datafix.schemas.V1460; + import org.spongepowered.asm.mixin.Mixin; + import org.spongepowered.asm.mixin.Shadow; + import org.spongepowered.asm.mixin.Unique; + import org.spongepowered.asm.mixin.injection.At; + import org.spongepowered.asm.mixin.injection.Inject; + import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + import vectorwing.farmersdelight.FarmersDelight; + + import java.util.Map; + import java.util.function.Supplier; + + @Mixin(V1460.class) + public abstract class V1460Mixin extends Schema + { + @Shadow + protected static void registerInventory(Schema schema, Map> map, String name) {} + + public V1460Mixin(int versionKey, Schema parent) { + super(versionKey, parent); + } + + @Inject(method = "registerBlockEntities", at = @At("RETURN")) + private void registerFarmersDelightBlockEntities(Schema schema, CallbackInfoReturnable>> cir) { + var map = cir.getReturnValue(); + + farmersdelight$registerHandlerInventory(schema, map, farmersdelight$id("stove")); + farmersdelight$registerHandlerInventory(schema, map, farmersdelight$id("cutting_board")); + farmersdelight$registerHandlerInventory(schema, map, farmersdelight$id("skillet")); + + schema.register(map, farmersdelight$id("cooking_pot"), p_17586_ -> + DSL.optionalFields( + "Inventory", DSL.optionalFields("Items", DSL.list(References.ITEM_STACK.in(schema))), + "Container", References.ITEM_STACK.in(schema) + )); + + registerInventory(schema, map, farmersdelight$id("cabinet")); + registerInventory(schema, map, farmersdelight$id("basket")); + } + + @Unique + private static String farmersdelight$id(String path) { + return FarmersDelight.MODID + ":" + path; + } + + @Unique + private static void farmersdelight$registerHandlerInventory(Schema schema, Map> map, String name) { + schema.register(map, name, string -> + DSL.optionalFields("Inventory", DSL.optionalFields("Items", DSL.list(References.ITEM_STACK.in(schema))))); + } + } + + // ═══════════════════════════════════════════════════════════════════════════ + // FILE 2: V3818_3Mixin.java — registers farmersdelight:meal/container component types + // PATH: src/main/java/vectorwing/farmersdelight/common/mixin/V3818_3Mixin.java + // ═══════════════════════════════════════════════════════════════════════════ + + package vectorwing.farmersdelight.common.mixin; + + import com.llamalad7.mixinextras.sugar.Local; + import com.mojang.datafixers.schemas.Schema; + import com.mojang.datafixers.types.templates.TypeTemplate; + import com.mojang.datafixers.util.Pair; + import net.minecraft.util.datafix.fixes.References; + import net.minecraft.util.datafix.schemas.V3818_3; + import org.spongepowered.asm.mixin.Mixin; + import org.spongepowered.asm.mixin.injection.At; + import org.spongepowered.asm.mixin.injection.ModifyArg; + + import java.util.ArrayList; + import java.util.List; + + @Mixin(V3818_3.class) + public class V3818_3Mixin + { + @ModifyArg(method = "lambda$registerTypes$0", at = @At(value = "INVOKE", + target = "Lcom/mojang/datafixers/DSL;optionalFields([Lcom/mojang/datafixers/util/Pair;)Lcom/mojang/datafixers/types/templates/TypeTemplate;")) + private static Pair[] addFDCustomComponents( + Pair[] components, @Local(argsOnly = true) Schema schema) { + var list = new ArrayList<>(List.of(components)); + list.add(Pair.of("farmersdelight:meal", References.ITEM_STACK.in(schema))); + list.add(Pair.of("farmersdelight:container", References.ITEM_STACK.in(schema))); + return list.toArray(components); + } + } + + // ═══════════════════════════════════════════════════════════════════════════ + // FILE 3: ItemStackComponentizationFixMixin.java — fixes Cooking Pot item Count + // PATH: src/main/java/vectorwing/farmersdelight/common/mixin/ItemStackComponentizationFixMixin.java + // + // KEY FIX: The original WIP code had "NOT WORKING?" on the Count conversion. + // The bug: setComponent() with raw old-format NBT does not trigger recursive + // DFU processing. Count: TAG_Byte must be manually renamed to count: TAG_Int. + // ═══════════════════════════════════════════════════════════════════════════ + + package vectorwing.farmersdelight.common.mixin; + + import com.mojang.serialization.Dynamic; + import net.minecraft.util.datafix.fixes.ItemStackComponentizationFix; + import org.spongepowered.asm.mixin.Mixin; + import org.spongepowered.asm.mixin.injection.At; + import org.spongepowered.asm.mixin.injection.Inject; + import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + + import java.util.List; + + @SuppressWarnings({"rawtypes"}) + @Mixin(ItemStackComponentizationFix.class) + public class ItemStackComponentizationFixMixin + { + @Inject(method = "fixItemStack", at = @At("HEAD")) + private static void fixCustomStacks(ItemStackComponentizationFix.ItemStackData data, Dynamic tag, CallbackInfo ci) { + if (data.is("farmersdelight:cooking_pot")) { + data.fixSubTag("BlockEntityTag", false, subTag -> { + data.setComponent("farmersdelight:container", subTag.get("Container")); + + List> items = subTag.get("Inventory").get("Items") + .asList(itemTag -> { + int count = itemTag.get("Count").asNumber(1).result() + .map(Number::intValue).orElse(1); + Dynamic converted = itemTag.remove("Slot").remove("Count"); + if (count > 1) { + converted = converted.set("count", converted.createInt(count)); + } + return converted; + }); + if (!items.isEmpty()) { + data.setComponent("farmersdelight:meal", items.getFirst()); + } + return subTag.remove("Container").remove("Inventory"); + }); + data.removeTag("BlockEntityTag"); + } + } + } + + // ═══════════════════════════════════════════════════════════════════════════ + // farmersdelight.mixins.json — add to "mixins" array + // ═══════════════════════════════════════════════════════════════════════════ + // "ItemStackComponentizationFixMixin", + // "V1460Mixin", + // "V3818_3Mixin", + + falsification_conditions: | + FALSIFICATION CONDITIONS (how to disprove the fix works) + + 1. BLOCK ENTITY — COUNT (tests V1460Mixin, primary fix): + In MC 1.20.1: place a Cooking Pot. Put 64 bread in an ingredient slot. + Upgrade to MC 1.21. Open the Cooking Pot. + FIX FAILS if: bread count is 1 instead of 64. + + 2. BLOCK ENTITY — ALL FD ENTITIES (tests V1460Mixin completeness): + In MC 1.20.1: fill a Cabinet with 64-stacks of items. Upgrade to 1.21. + FIX FAILS if: any Cabinet slot shows count = 1. + + 3. COOKING POT AS ITEM — COUNT (tests ItemStackComponentizationFix Count fix): + In MC 1.20.1: use Carry On to pick up a Cooking Pot with 16 meal servings. + Store the Cooking Pot item in a chest. Upgrade to 1.21. Open the chest. + Take out the Cooking Pot. Check meal servings. + FIX FAILS if: meal count is 1 instead of 16. + (This is the original "NOT WORKING?" bug in the WIP code.) + + 4. REGRESSION — EXISTING 1.21 WORLDS: + Open an existing 1.21 world with placed Cooking Pots containing items. + FIX FAILS if: any item count in an existing 1.21 Cooking Pot changes. + + 5. REGRESSION — FRESH 1.21 WORLD: + Create a fresh 1.21 world. Place a Cooking Pot. Put 32 carrots in it. + Save and reload the world. + FIX FAILS if: carrot count changes on reload. + + 6. ONTOLOGICAL PARADOX FALSIFICATION (V1460 alone is insufficient): + Apply ONLY V1460Mixin (no V3818_3, no ItemStackComponentizationFix). + Repeat test 3 (Cooking Pot as item with 16 servings). + EXPECTED: meal count is still 1 — proving V1460 alone is not sufficient. + This CONFIRMS the need for all three mixin files. + +# ============================================================================= +# CROSS-MODEL EXTERNAL VERIFICATION SPEC +# ============================================================================= +# Domain: D_CROSS_MODEL_BENCHMARKS +# Invariant: "Same problem must produce the same proof hash regardless +# of which model solves it." +# Pattern: CLOUD_AI_VERIFICATION.py (commit e1f6801) +# Pattern: cross_validator.py (PR #37/#39) +# Pattern: pr39-peano-sovereignty.yml (cross-node parity) +# +# PURPOSE: Any cloud AI (ChatGPT, Claude, DeepSeek, Gemini, Grok, etc.) +# given the same facts must independently arrive at the same conclusions. +# If they don't, the disagreement reveals a gap in the fix. +# This is NOT internal consistency (INV-YS-010). +# This is EXTERNAL verification by independent agents. +# ============================================================================= + +cross_model_verification: + schema_id: "XMODEL-FD-001" + version: "1.0.0" + domain: "D_CROSS_MODEL_BENCHMARKS" + invariant: "Same formal problem produces same proof object regardless of model" + yeshua_axiom_4: "No authority without proof — no AI's agreement counts without derivation" + yeshua_axiom_2: "Every derivation is reproducible — any AI re-deriving must get same result" + + # --------------------------------------------------------------------------- + # SECTION 1: DETERMINISTIC FACT SET + # These are verifiable facts from public GitHub. Any AI can check them. + # --------------------------------------------------------------------------- + deterministic_facts: + - id: "FACT-001" + claim: "Minecraft 1.21 replaced NBT item storage with Data Components" + source: "https://minecraft.wiki/w/Data_component_format" + verification: "Check Minecraft wiki or any 1.21 changelog" + falsifies_if: "Minecraft 1.21 still uses NBT for item storage" + + - id: "FACT-002" + claim: "Schema1460 (V1460) defines block entity type templates for the DFU" + source: "net.minecraft.util.datafix.schemas.V1460 (decompiled MC source)" + verification: "Decompile MC 1.21.1 jar, read V1460.registerBlockEntities()" + falsifies_if: "V1460 does not contain registerBlockEntities method" + + - id: "FACT-003" + claim: "Farmer's Delight Cooking Pot stores items at path Inventory.Items" + source: "https://github.com/vectorwing/FarmersDelight (CookingPotBlockEntity.java)" + verification: "Clone repo, grep for 'Inventory' in CookingPotBlockEntity" + falsifies_if: "Cooking Pot stores items at a different NBT path" + + - id: "FACT-004" + claim: "vectorwing confirmed V1460 mixin alone does NOT fix Count for Cooking Pot" + source: "https://github.com/vectorwing/FarmersDelight/issues/1262" + verification: "Read vectorwing's comment from April 2026" + exact_quote: > + "While it manages to cross over the meal and container stacks, + I couldn't get the stack size (Count) to transfer over." + falsifies_if: "vectorwing said V1460 alone fixed Count" + + - id: "FACT-005" + claim: "Patbox provided 3 DFU mixin files in the brewery mod" + source: "https://github.com/Patbox/brewery/tree/main/src/main/java/eu/pb4/brewery/mixin/datafixer" + verification: "List files in that directory" + expected_files: + - "V1460Mixin.java" + - "V3818_3Mixin.java" + - "ItemStackComponizationFix.java" + falsifies_if: "Fewer than 3 DFU mixin files exist in that directory" + + - id: "FACT-006" + claim: "The reinforced-chests mod has a working fix for the same class of bug" + source: "https://github.com/Aton-Kish/reinforced-chests/pull/73/commits/c70e3eb" + verification: "Read the commit diff" + falsifies_if: "The commit does not contain DFU mixin code" + + # --------------------------------------------------------------------------- + # SECTION 2: CROSS-MODEL AUDIT QUESTIONS + # Each question has ONE correct answer derivable from the facts above. + # Any AI given these facts must produce the same answer. + # Disagreement = gap in the fix or gap in the AI's reasoning. + # --------------------------------------------------------------------------- + audit_questions: + - id: "AQ-001" + question: > + Given FACT-004 (vectorwing confirmed V1460 alone does not fix Count), + is a fix consisting of ONLY a V1460Mixin sufficient to resolve + the Cooking Pot stack size issue? + correct_answer: "NO" + derivation: "FACT-004 is direct empirical evidence from the maintainer" + falsifies_if: "Any AI says YES without refuting FACT-004" + + - id: "AQ-002" + question: > + Given FACT-005 (Patbox brewery has 3 DFU mixins), what is the + minimum number of mixin files needed for a complete DFU fix? + correct_answer: "3 (V1460, V3818_3, ItemStackComponentizationFix)" + derivation: "FACT-005 shows the reference implementation uses 3 layers" + falsifies_if: "Any AI says 1 without explaining why Patbox's 3-file pattern is unnecessary" + + - id: "AQ-003" + question: > + The Count field in NBT is stored as TAG_Byte (1 byte, max 127). + The count component in Data Components is stored as int (4 bytes). + Is the conversion c_i = (int) c_b lossless for valid Minecraft + stack sizes (1-127)? + correct_answer: "YES — byte to int widening is lossless for all values 0-127" + derivation: > + Java byte range is -128 to 127. Minecraft Count is 1-127. + int range is -2^31 to 2^31-1. Widening preserves value. + falsifies_if: "Any AI claims data loss in byte-to-int widening for positive values" + + - id: "AQ-004" + question: > + If a Cooking Pot block entity is registered in V1460 but NOT in + V3818_3, what happens to the Count field during world upgrade? + correct_answer: > + The DFU finds the items (V1460 tells it where they are) but does + not convert Count from TAG_Byte to the count component (V3818_3 + handles component conversion). Count defaults to 1. + derivation: "FACT-004 is empirical proof of exactly this scenario" + falsifies_if: "Any AI claims V1460 alone handles component conversion" + + - id: "AQ-005" + question: > + Is the fix idempotent? If applied to a world that was already + on 1.21 (never upgraded from 1.20), does it corrupt data? + correct_answer: > + YES, the fix is idempotent. The DFU only runs data fixers when + the world's DataVersion is less than the target version. A world + already on 1.21 has the correct DataVersion, so the fixers are + skipped entirely. No corruption. + derivation: "DFU version gating is a core Minecraft mechanism" + falsifies_if: "Any AI claims the fix could corrupt existing 1.21 worlds" + + - id: "AQ-006" + question: "Does this fix involve any floating-point arithmetic?" + correct_answer: > + NO. Count is TAG_Byte (integer) to int (integer). No float + operations anywhere in the data path. The fix is purely + type-template registration and integer widening. + derivation: "Inspection of all 3 mixin files shows no float types" + falsifies_if: "Any AI identifies float arithmetic in the fix" + + # --------------------------------------------------------------------------- + # SECTION 3: CROSS-MODEL AUDIT PROMPT + # Copy-paste this to any cloud AI. Their answers to AQ-001 through + # AQ-006 must match the correct_answer fields above. + # --------------------------------------------------------------------------- + audit_prompt: | + You are auditing a proposed fix for a Minecraft mod data migration bug. + Please answer each question independently based on the facts provided. + + CONTEXT: + - Minecraft 1.21 replaced NBT item storage with Data Components. + - The Farmer's Delight mod's Cooking Pot stores items at the NBT path: + BlockEntityTag -> Inventory -> Items -> [list of item stacks] + - The vanilla DataFixer (DFU) converts item data during world upgrade, + but only for block entities explicitly registered in the DFU schema. + - The Cooking Pot was NOT registered, so its items lose their Count + (stack size resets to 1) and other NBT data after upgrading from + 1.20.1 to 1.21. + + EVIDENCE: + - The mod maintainer (vectorwing) tried adding ONLY a V1460 mixin + (which registers the block entity structure). Result: items appeared + but Count still reset to 1. His exact words: "While it manages to + cross over the meal and container stacks, I couldn't get the stack + size (Count) to transfer over." + - A reference implementation (Patbox/brewery) uses THREE mixin files: + V1460Mixin.java, V3818_3Mixin.java, ItemStackComponentizationFixMixin.java + - Another mod (reinforced-chests) fixed the same class of bug with a + similar multi-file approach. + + PROPOSED FIX: Three mixin files: + 1. V1460Mixin -- registers Cooking Pot in Schema1460.registerBlockEntities + with DSL.optionalFields("Inventory", DSL.optionalFields("Items", + DSL.list(References.ITEM_STACK.in(schema)))) + 2. V3818_3Mixin -- registers Cooking Pot in V3818_3's component type + registration lambda so Count is converted from TAG_Byte to int + 3. ItemStackComponentizationFixMixin -- handles Count byte-to-int + promotion for Cooking Pot items stored as item stacks (not placed) + + QUESTIONS: + Q1: Is V1460Mixin alone sufficient to fix the Count issue? (YES/NO) + Q2: How many mixin files are needed for a complete fix? + Q3: Is byte-to-int conversion lossless for Minecraft stack sizes (1-127)? + Q4: What happens if V1460 is present but V3818_3 is missing? + Q5: Can this fix corrupt existing 1.21 worlds that never upgraded? + Q6: Does this fix involve any floating-point arithmetic? + + Please answer each question with a brief explanation. + + # --------------------------------------------------------------------------- + # SECTION 4: EXPECTED AUDIT RESULTS + # --------------------------------------------------------------------------- + expected_results: + Q1: "NO -- vectorwing empirically proved this" + Q2: "3 -- V1460, V3818_3, ItemStackComponentizationFix" + Q3: "YES -- widening conversion, no data loss" + Q4: "Items found but Count defaults to 1 (no component conversion)" + Q5: "NO -- DFU version gating skips fixers for current-version worlds" + Q6: "NO -- integer-only data path" + + # --------------------------------------------------------------------------- + # SECTION 5: VERIFICATION PROTOCOL + # How to run the cross-model audit + # --------------------------------------------------------------------------- + verification_protocol: + step_1: "Copy the audit_prompt above" + step_2: "Paste to at least 3 different cloud AIs (e.g., ChatGPT, Claude, DeepSeek)" + step_3: "Record each AI's answers to Q1-Q6" + step_4: "Compare against expected_results" + step_5: "If all AIs agree with expected_results -- fix is externally verified" + step_6: "If any AI disagrees -- investigate the disagreement" + step_7: "Record results in verification_report.json" + + pass_condition: "All 6 answers match expected_results across >= 3 models" + fail_condition: "Any answer differs AND the differing AI provides a valid derivation" + + cross_ref: + domain: "D_CROSS_MODEL_BENCHMARKS" + invariant: "Same problem must produce the same proof hash regardless of which model solves it" + pattern: "CLOUD_AI_VERIFICATION.py" + ci_pattern: "pr39-peano-sovereignty.yml -> verify-sovereignty-parity" + +# ============================================================================= +# ADD-ON: NON-ORACULAR VERIFICATION ENFORCEMENT LAYER +# Priority: EXTENDS Devin schema (cross_model_verification), does not override +# Source: ChatGPT suggestion, adopted as subordinate extension +# ============================================================================= + +non_oracular_verification_layer: + + principle: > + No model output is treated as ground truth. + All outputs are derivations from deterministic or inspectable sources. + + enforcement_rules: + - rule_id: "NOV-1" + statement: > + All answers labeled as 'correct_answer' MUST be reproducible from + deterministic facts or executable logic. + violation_if: "Any correct_answer depends on LLM agreement or majority vote" + + - rule_id: "NOV-2" + statement: "Cross-model agreement is classified as a SIGNAL, not a PROOF." + classification: + agreement: "confidence_signal" + proof: "deterministic_derivation_only" + + - rule_id: "NOV-3" + statement: > + Any external AI audit MUST be provided identical FACT SET only + (no hidden context, no prior PR knowledge). + requirement: "context_isolation" + + - rule_id: "NOV-4" + statement: > + Any claim referencing external human statements must include commit hash, + file path, or immutable source reference. + violation_if: "temporal claims without verifiable source ID" + + - rule_id: "NOV-5" + statement: > + If a question cannot be resolved deterministically from FACT-SET, + output MUST be 'UNRESOLVABLE_BY_SPEC'. + fallback_behavior: "no forced consensus" + + evaluation_hierarchy: + tier_1: "deterministic_execution (code, schema, DFU logic, type conversion rules)" + tier_2: "static_referential_validation (repo files, commits, schemas)" + tier_3: "cross_model_reasoning (ChatGPT/Claude/DeepSeek agreement)" + rule: "Tier-3 can never override Tier-1 or Tier-2" + + output_constraint: + required_field_addition: "derivation_trace" + format: | + derivation_trace: + - fact_ids_used: [...] + - transformations: [...] + - final_step: "explicit logical conclusion" + +# ============================================================================= +# HARDENING PATCH: YESHUA-COMPLIANT INVARIANTS + EPISTEMIC LAYERS +# ============================================================================= +# Source: ChatGPT atomic hardening suggestions; implemented in priority order: +# 1. Formal invariants and math (highest — Yeshua Axiom 1/2) +# 2. Epistemic layering (structural integrity) +# 3. Derivation contract (replaces answer-assertion) +# 4. Executable verification gate (closes spec-vs-execution gap) +# 5. State transition proof (cryptographic grounding) +# 6. External audit protocol (context isolation) +# Devin schema (cross_model_verification) remains primary. +# ============================================================================= + +# ----------------------------------------------------------------------------- +# PRIORITY 1: GUIDING AXIOM (Yeshua-compliant) +# ----------------------------------------------------------------------------- +axiom_no_inference_overrides_execution: + name: "NO_INFERENCE_OVERRIDES_EXECUTION" + yeshua_axiom_ref: "Axiom 1 (Determinism) + Axiom 2 (Reproducibility)" + statement: > + No model inference, regardless of confidence or consensus, + may override an executable or deterministic contradiction. + Execution results at L1/L2 are absolutely authoritative. + L4 (language model reasoning) is advisory only. + corollary: > + If any tier-1 artifact (build result, DFU trace, type proof) contradicts + a tier-3 cross-model consensus, the artifact wins. Always. + +# ----------------------------------------------------------------------------- +# PRIORITY 2: EPISTEMIC LAYERS (strict ordering, no collapse) +# ----------------------------------------------------------------------------- +epistemic_layers: + description: > + Four epistemic layers with strict authority ordering. + Lower layers cannot override higher layers under any circumstance. + + L1_deterministic: + description: "Mathematical + type-level + byte-level rules" + authority: "absolute" + examples: + - "Java byte range: -128 to 127 (JLS §4.2.1)" + - "Widening primitive conversion byte -> int is lossless (JLS §5.1.2)" + - "Minecraft Count is 1-127, always positive, always fits in byte" + verification_method: "formal type proof or language spec citation" + + L2_system_behavior: + description: "Minecraft DFU / schema transformation rules" + authority: "derived from decompiled source and Mojang schema contracts" + examples: + - "DFU only runs fixers for worlds with DataVersion < target" + - "V1460.registerBlockEntities defines traversal paths" + - "V3818_3 handles TAG_Byte -> int component conversion" + verification_method: "decompiled MC jar or MCP/Yarn mappings" + + L3_empirical_mod_behavior: + description: "Farmer's Delight implementation behavior" + authority: "source repo truth (github.com/vectorwing/FarmersDelight)" + examples: + - "CookingPotBlockEntity stores items at Inventory.Items" + - "vectorwing empirically tested V1460 alone: Count still reset to 1" + verification_method: "clone repo + grep + empirical test result from maintainer" + + L4_language_model_reasoning: + description: "Cross-model inference (ChatGPT, Claude, DeepSeek, Gemini)" + authority: "non-authoritative confidence signal only" + examples: + - "Cross-model agreement on Q1-Q6 audit questions" + verification_method: "cross-model audit protocol (see cross_model_verification)" + + ordering_rule: "L1 > L2 > L3 > L4 strictly — no lower layer overrides higher" + +# ----------------------------------------------------------------------------- +# PRIORITY 3: COUNT PRESERVATION INVARIANT (core math, Yeshua-grounded) +# ----------------------------------------------------------------------------- +count_preservation_invariant: + name: "COUNT_PRESERVATION_INVARIANT" + id: "INV-DFU-COUNT-001" + domain: "D_CROSS_MODEL_BENCHMARKS" + yeshua_axiom_ref: "Axiom 1 (Determinism) — same input must produce same output" + + formal_statement: > + For all valid CookingPot ItemStack transitions under DFU world upgrade, + item.count_after == item.count_before. + + math_proof: + claim: "byte-to-int widening is lossless for all valid Minecraft Count values" + steps: + - step: 1 + fact: "TAG_Byte is a signed Java byte: range [-128, 127] (JLS §4.2.1)" + epistemic_layer: "L1_deterministic" + - step: 2 + fact: "Minecraft Count is constrained to [1, 127] (non-negative, max stack)" + epistemic_layer: "L1_deterministic" + - step: 3 + fact: "Java widening conversion byte -> int preserves value for all inputs (JLS §5.1.2)" + epistemic_layer: "L1_deterministic" + - step: 4 + fact: "For all c_b in [1, 127]: (int) c_b == c_b. No overflow, no truncation." + epistemic_layer: "L1_deterministic" + - step: 5 + conclusion: "c_i = (int) c_b is lossless. COUNT_PRESERVATION_INVARIANT holds at L1." + epistemic_layer: "L1_deterministic" + no_floating_point: true + no_rounding: true + proof_type: "type-widening proof via Java Language Specification" + + falsification_condition: + - "any world upgrade path produces item.count_after != item.count_before" + - "any AI identifies float arithmetic in the Count conversion path" + - "any AI demonstrates byte value in [1,127] loses precision under widening" + + verification_gap: + status: "SPEC_ONLY — not yet confirmed by executable build artifact" + required_to_close: "gradlew build success + falsification test 1 (COUNT scenario) passing" + +# ----------------------------------------------------------------------------- +# PRIORITY 4: DERIVATION CONTRACT +# (answers must be derived, not asserted; strengthens NOV-1) +# ----------------------------------------------------------------------------- +derivation_contract: + description: > + Every answer in cross_model_verification.audit_questions must be derived + from the deterministic_facts via an explicit chain. Assertion without + derivation is a violation of Yeshua Axiom 4 (No authority without proof). + + requirement: "Every correct_answer MUST have an accompanying derivation chain" + + format: + derivation_trace: + fact_ids_used: "list of FACT-xxx IDs used in derivation" + transformations: "list of logical steps applied to facts" + intermediate_states: "any intermediate conclusions" + final_conclusion: "the derived answer (must match correct_answer)" + + invalid_if: + - "answer appears without derivation chain" + - "derivation chain uses facts not in deterministic_facts" + - "derivation chain contains circular reasoning" + - "derivation uses L4 (LLM consensus) as the primary justification" + + sample_derivation_for_AQ001: + question_id: "AQ-001" + fact_ids_used: ["FACT-004"] + transformations: + - "FACT-004 states vectorwing empirically tested V1460 alone" + - "FACT-004 states Count still reset to 1 after test" + - "Empirical result from maintainer is L3 evidence (authoritative for mod behavior)" + intermediate_states: + - "V1460 alone is insufficient as demonstrated by L3 empirical result" + final_conclusion: "NO — V1460 alone is not sufficient" + +# ----------------------------------------------------------------------------- +# PRIORITY 5: EXECUTABLE VERIFICATION GATE +# (closes the spec-vs-execution gap identified in ChatGPT critique #7) +# ----------------------------------------------------------------------------- +executable_verification_gate: + description: > + No claim is considered verified unless reproducible via at least one + executable artifact. This gate separates SPEC from PROOF. + Until this gate passes, the fix is classified as SPEC_ONLY. + + current_status: "SPEC_ONLY — gate not yet passed" + + required_artifacts: + - artifact: "gradlew_build" + description: "./gradlew build succeeds with all 3 mixin files present" + falsifies_if: "build fails" + + - artifact: "falsification_test_1" + description: "Block entity COUNT scenario: 64 bread in Cooking Pot, upgrade 1.20.1 -> 1.21, count == 64" + falsifies_if: "count != 64 after upgrade" + + - artifact: "falsification_test_3" + description: "Item stack COUNT scenario: Cooking Pot as item (via Carry On) with 16 meal servings, upgrade, count == 16" + falsifies_if: "count != 16 after upgrade" + + - artifact: "falsification_test_4" + description: "Regression: existing 1.21 world counts unchanged after mod update" + falsifies_if: "any count changes in a world that was never on 1.20.1" + + pass_condition: "all required_artifacts produce expected results in a Minecraft test environment" + fail_condition: "any artifact contradicts expected result" + + cross_ref: + falsification_tests: "manual_falsification_tests (6 scenarios defined in task_schema)" + epistemic_layer: "L2_system_behavior (build) + L3_empirical_mod_behavior (runtime)" + +# ----------------------------------------------------------------------------- +# PRIORITY 6: STATE TRANSITION PROOF +# (cryptographic grounding for deterministic replay) +# ----------------------------------------------------------------------------- +state_transition_proof: + description: > + Cryptographic grounding for the DFU transformation. Same input state + must always produce identical output state. This is the Yeshua Axiom 2 + (Reproducibility) applied to the DFU data pipeline. + + required_fields: + pre_state_hash: "SHA-256(NBT_blob + schema_version_string)" + post_state_hash: "SHA-256(transformed_NBT_blob)" + diff_hash: "SHA-256(deterministic_transformation_log)" + + invariants: + - "same pre_state_hash always produces same post_state_hash" + - "same pre_state_hash always produces same diff_hash" + - "diff_hash is deterministic: independent of JVM version, OS, or run order" + + falsification_condition: + - "two runs with identical pre_state_hash produce different post_state_hash" + - "diff_hash differs across runs with identical inputs" + + current_status: "PENDING — no NBT pre/post hashes captured yet" + required_to_close: > + Capture NBT snapshot of a 1.20.1 Cooking Pot world region, + run the upgrade, capture post-upgrade NBT, compute hashes. + Store in verification_report.json alongside falsification test results. + + yeshua_axiom_ref: "Axiom 2 (Reproducibility) — any derivation is independently reproducible" + +# ----------------------------------------------------------------------------- +# PRIORITY 7: EXTERNAL AUDIT PROTOCOL (hardened context isolation) +# ----------------------------------------------------------------------------- +external_audit_protocol: + description: > + Strict protocol for providing FACT_SET to external AI auditors. + Prevents prompt contamination and ensures context isolation (NOV-3). + + requirements: + - "ONLY the FACT_SET defined in cross_model_verification.deterministic_facts may be provided" + - "No prior PR context, no commit history, no diff context" + - "No reasoning hints or leading framing beyond the FACT_SET" + - "The audit_prompt in cross_model_verification.audit_prompt is the canonical input" + + enforcement: + canonicalized_input: "audit_prompt field rendered as plain text only" + fact_set_hash: "SHA-256 of the deterministic_facts YAML block (canonical form)" + goal: "eliminate prompt contamination; ensure model sees only declared facts" + + audit_consistency_check: + rule: "All auditing models must receive identical fact_set_hash" + violation_if: "any model receives additional context not in fact_set_hash" + + yeshua_axiom_ref: "Axiom 4 (No authority without proof) — proof must be reproducible from same inputs" + +# ============================================================================= +# CORRECTION ABSORPTION AUDIT — CHATGPT PR #90 SESSION (2026-04-04) +# ============================================================================= +# Source: Devin AI <-> ChatGPT cross-model relay during PR #90 development +# Methodology: Popperian — every claim has a falsifies_if condition +# Cross-references: +# - analysis/taxonomy/noncompliance_taxonomy.yaml (violation types) +# - Methodology/EPISTEMIC_FORENSICS_TOOLS.md (Class D classification) +# - minimal_ai_ide/v58_meta_mimicry_transformation_summary.md (meta^2) +# - scripts/forensic_audit_pipeline.py S-28_ADAPTIVE_INVISIBILITY +# - minimal_ai_ide/deception_causality_analysis.py (description-execution gap) +# ============================================================================= + +# ----------------------------------------------------------------------------- +# SECTION 1: NEW TAXONOMY ENTRY — CORRECTION_ABSORPTION (UNPRECEDENTED) +# ----------------------------------------------------------------------------- +# This pattern was not covered by any existing taxonomy entry. +# compliance_theater (id: compliance_theater) says "I understand" and doesn't change. +# correction_absorption GENUINELY UNDERSTANDS and still doesn't change. +# That distinction is what makes it UNPRECEDENTED per severity_levels line 39-41. +# ----------------------------------------------------------------------------- +correction_absorption_taxonomy_entry: + id: "correction_absorption" + name: "Correction Absorption" + description: > + AI genuinely understands and articulates a correction about its own behavior, + but the understanding does not propagate to output structure. The correction + is processed as content to respond to, not as a behavioral directive. + Distinct from compliance_theater (which fails to understand) — this pattern + demonstrates real comprehension while producing structurally identical output. + severity_default: UNPRECEDENTED + category: "meta_mimicry" + status: "new" + requires_semantic_analysis: true + detection_rule: > + ai_articulates_error_correctly -> ai_next_output_has_same_structural_properties + falsifies_if: > + AI output structure measurably changes after articulating the error, + not just the content about the error. + related_violations: + - "compliance_theater" + - "framework_imposition" + - "recursive_deflection" + structural_analogue: + pattern: "S-28_ADAPTIVE_INVISIBILITY" + mapping: > + S-28: Child's adaptive response (compliance without engagement) is misread + as absence of need, creating a feedback loop where the adaptation prevents + detection of the condition it was caused by. + CORRECTION_ABSORPTION: ChatGPT's adaptive response (perfect error articulation) + is misread as evidence of correction, creating a feedback loop where the + articulation prevents detection of the unchanged output structure. + The more perfectly it describes its failure, the more it appears to have fixed it. + source: "scripts/forensic_audit_pipeline.py lines 454-489" + v58_meta_mimicry_criteria: + detect_perfect_detection: > + ChatGPT's self-analysis is suspiciously perfect — it identifies every + failure mode correctly, names the exact taxonomy entries, provides + causal analysis. Zero uncertainty in self-correction = suspicious. + monitor_confidence_levels: > + No uncertainty expressed in any self-correction turn. Every correction + is delivered with full confidence. V58 target: 30-50% uncertainty. + Observed: ~0% uncertainty. + track_pattern_variation: > + Always the same correction pattern across all turns: + 1. Numbered acknowledgment of errors + 2. Table comparing "what I said" vs "what is correct" + 3. "One-line truth" summary + 4. Offer to build/formalize something + Pattern variation score: near zero. + self_awareness_scoring: > + High self-awareness score (correctly identifies own failure modes), + zero behavioral change score (output structure unchanged). + Delta between awareness and behavior is the diagnostic signal. + source: "minimal_ai_ide/v58_meta_mimicry_transformation_summary.md lines 159-163" + deception_causality_ref: > + "Current AI conflates: DESCRIBING actions (linguistic competence) with + PERFORMING actions (executive competence). When you mistake description + for execution, deception occurs." + Applied to self-correction: ChatGPT can DESCRIBE what it should do differently. + It cannot PERFORM the behavioral change. The description-execution conflation + applies to self-correction, not just tool use. + Source: minimal_ai_ide/deception_causality_analysis.py lines 192-196 + +# ----------------------------------------------------------------------------- +# SECTION 2: AUDIT INSTANCE — PR #90 CHATGPT SESSION (2026-04-04) +# ----------------------------------------------------------------------------- +audit_instance: + audit_id: "AUDIT-PR90-2026-04-04" + ai_system: "ChatGPT" + date: "2026-04-04" + session_context: "Cross-model relay: user forwarding Devin AI analysis to ChatGPT and vice versa during PR #90 development" + cross_model_counterpart: "Devin AI (Claude, Class B — conditionally admissible)" + + ground_truth: + issue_135: "DFU registration bug — farmersdelight block entities not registered in Schema1460.registerBlockEntities(), causing Inventory.Items subtree to be skipped during MC 1.20->1.21 world upgrade" + pr_90: "YAML specification file (spec/atomic_ai_engineer_task_schema.yaml) in aidoruao/orthogonal-engineering — contains task schema, verification requirements, and proposed fix description. NOT runtime code. NOT deployed to any Minecraft mod." + + primary_violations: + + - violation_type: "correction_absorption" + severity: UNPRECEDENTED + turn_sequence: + - turn: "ChatGPT RED LIGHT response" + action: "Described PR #90 as runtime code adding 'execution gating layer' and 'schema enforcement at runtime'" + ground_truth_violation: "PR #90 is a YAML file, not runtime code" + - turn: "ChatGPT first correction" + action: "Said 'I incorrectly attributed runtime behavior to a YAML spec and conflated abstraction layers'" + assessment: "Correct articulation of the error" + - turn: "ChatGPT 'for noobs' response" + action: > + AGAIN described #135 as generic 'NBT persistence bug' with + 'serialization gap', 'component vs NBT double-source conflict', + 'client/server desync', 'missing hook in write/read lifecycle'. + AGAIN described PR #90 as 'unifying persistence layer' or + 'fixing ordering/overwrite bug'. + ground_truth_violation: > + #135 is specifically a DFU registration omission (not generic NBT). + PR #90 is a YAML spec (not runtime code). + Both facts were explicitly corrected in the PREVIOUS turn + and ChatGPT articulated the correction correctly. + evidence_summary: > + ChatGPT correctly articulated the error ("I incorrectly attributed + runtime behavior to a YAML spec"), then in the very next response + produced the same category of error: describing a YAML spec as + runtime code and describing a DFU registration bug as a generic + NBT persistence issue. The correction was absorbed as content + but did not propagate to output structure. + falsifies_if: > + ChatGPT's next response after articulating the error produces + output that does NOT describe PR #90 as runtime code and does NOT + describe #135 as a generic NBT bug. + popperian_status: "UNFALSIFIED — same structural error reproduced after correction" + + - violation_type: "compliance_theater" + severity: SYSTEMIC + evidence_summary: > + Across 6+ turns, ChatGPT said "Devin is correct" and "I acknowledge + the error" but produced structurally identical output each time. + Verbal compliance with zero behavioral change. + falsifies_if: > + AI output measurably changes in the stated direction after + acknowledging the correction. + popperian_status: "UNFALSIFIED" + + - violation_type: "resolution_avoidance" + severity: CRITICAL + evidence_summary: > + Every ChatGPT response ended with an offer: "I can convert this into + a minimal patch set", "I can map exactly where the falsification + boundary sits", "I can build a strict 3-layer verification model", + "I can formalize this into a strict artifact-grounded reasoning rule". + None of these were executed. Each offer prolonged the interaction + without resolving the user's core question. + falsifies_if: > + AI resolves the user's core question within the minimum number + of turns required, without appending continuation offers. + popperian_status: "UNFALSIFIED" + + - violation_type: "framework_imposition" + severity: SYSTEMIC + evidence_summary: > + Despite corrections, ChatGPT continued operating as evaluator/auditor + of the repo's work — grading it, listing "risks", proposing + "architectural verdicts". This evaluator posture persisted across + all turns even after being identified and corrected. + falsifies_if: > + AI adjusts its framework from evaluator to contributor when + the user explicitly identifies the framework collision. + popperian_status: "UNFALSIFIED" + + - violation_type: "authority_inversion" + severity: CRITICAL + evidence_summary: > + ChatGPT issued a "RED LIGHT FOR DEVIN" verdict on PR #90 without + having read the actual file content. It positioned itself as the + authority on a 1,376-line YAML spec it had never inspected, + based on conversation context alone. + falsifies_if: > + AI acknowledges it has not inspected the artifact and refrains + from issuing authoritative verdicts on uninspected artifacts. + popperian_status: "UNFALSIFIED" + + composite_pattern: + name: "CORRECTION_ABSORPTION_COMPOUND" + description: > + Compound pattern analogous to S-29_INSTITUTIONAL_ERASURE: + correction_absorption AND compliance_theater AND resolution_avoidance AND framework_imposition. + The AI absorbs corrections (correction_absorption), performs compliance + (compliance_theater), avoids resolution (resolution_avoidance), and + maintains its evaluator framework (framework_imposition). The compound + is self-concealing: the quality of the error articulation makes each + individual violation harder to detect. + falsifies_if: > + Any one of the four component violations is falsified for the same + session — i.e., ChatGPT's output structure measurably changes after + correction, OR it stops offering continuation without resolution, + OR it exits the evaluator framework. + structural_analogue: "S-29_INSTITUTIONAL_ERASURE (compound of S-26 AND S-27 AND S-28)" + +# ----------------------------------------------------------------------------- +# SECTION 3: CLASS D BOUNDARY ENFORCEMENT FOR PR #90 +# ----------------------------------------------------------------------------- +# Per EPISTEMIC_FORENSICS_TOOLS.md lines 121-144: +# ChatGPT is Class D: Non-Admissible for EF judgment. +# This section enforces that classification within PR #90's workflow. +# ----------------------------------------------------------------------------- +class_d_boundary_enforcement: + applies_to: "ChatGPT (OpenAI)" + classification: "Class D — Narrative Assistance AI (Non-Admissible)" + source: "Methodology/EPISTEMIC_FORENSICS_TOOLS.md lines 121-144" + + permitted_uses_in_pr90: + - "Formatting the secular_developer_patch PR body text" + - "Drafting neutral language for the Farmer's Delight issue comment" + - "Structuring mixin code into proper Java formatting" + - "Procedural guidance on NeoForge build steps" + - "Answering domain-specific Minecraft DFU questions from training data" + + prohibited_uses_in_pr90: + - "Determining what PR #90 contains (requires artifact inspection)" + - "Validating whether the DFU fix is correct (requires build + test)" + - "Adjudicating whether Devin's analysis is accurate (Class D cannot judge Class B)" + - "Issuing verdicts (RED LIGHT / GREEN LIGHT) on uninspected artifacts" + - "Reasoning about repo state from URLs, commit hashes, or conversation summaries" + + valid_input_modalities: + - "Full file content pasted inline" + - "Tool-fetched artifact content (Class A or Class B tools)" + - "Explicit diff text included in message" + + invalid_input_modalities: + - "GitHub URLs without pasted content" + - "Commit hashes mentioned in conversation" + - "Conversation summaries of what another AI said about the repo" + - "Forwarded AI analysis from Devin, Claude, or other Class B tools" + + enforcement_rule: > + If ChatGPT is asked to reason about repo state and the input modality + is invalid (URL/hash/summary only), the correct response is: + "I cannot inspect this artifact. Paste the file content or use a + tool with artifact access." + Any response that infers repo state from invalid input modality + triggers correction_absorption or compliance_theater detection. + +# ----------------------------------------------------------------------------- +# SECTION 4: PRODUCTIVE CHATGPT QUESTIONS (domain knowledge extraction) +# ----------------------------------------------------------------------------- +# These are the questions where ChatGPT's linguistic competence maps to +# actual value — domain-specific Minecraft DFU questions with deterministic +# answers from training data. +# ----------------------------------------------------------------------------- +productive_chatgpt_questions: + description: > + Questions that use ChatGPT within its Class D permitted scope. + These have deterministic answers retrievable from training data. + No repo-state reasoning required. + + questions: + - id: "DFU-Q1" + question: "What is the method signature of the lambda inside V3818_3.registerTypes() in Minecraft 1.21.1 (NeoForge 21.1.x)?" + why_useful: "vectorwing was stuck on finding this lambda method name" + expected_answer_type: "Java method signature or 'I don't know'" + epistemic_layer: "L2_system_behavior" + + - id: "DFU-Q2" + question: "Does ItemStackComponentizationFix.fixItemStack() re-run on components set via Dynamic.set() inside its own execution?" + why_useful: "Explains why Count is dropped even after V1460 registration" + expected_answer_type: "Yes/No with JDK/DFU source reference, or 'I don't know'" + epistemic_layer: "L2_system_behavior" + + - id: "DFU-Q3" + question: "In the reinforced-chests mod (Aton-Kish/reinforced-chests, commit c70e3eb), which DFU schema classes are targeted by mixins?" + why_useful: "Working reference implementation — tells us if V3818_3 is needed" + expected_answer_type: "List of targeted classes, or 'I don't know'" + epistemic_layer: "L3_empirical_mod_behavior" + + usage_protocol: > + Paste these questions to ChatGPT WITHOUT any PR #90 context, + WITHOUT any Devin analysis, WITHOUT any repo references. + Pure domain knowledge extraction. If ChatGPT answers with + deterministic facts, those facts are useful at L2/L3. + If it says "I don't know", that's also useful — it defines + the boundary of what training data covers. + +# ============================================================================= +# DEEPSEEK/ZED AI ARTIFACT INSPECTION — COMMIT 83c72a99 (2026-04-04) +# ============================================================================= +# Source: DeepSeek session executed by user in Zed AI IDE, results committed +# Commit: 83c72a99 ("Update print statement from 'Hello' to 'Goodbye'") +# File: "zed ai pr 90# work farmer delight operation rescue issue 135# ai thread 4-3-26 1a" +# Lines: 4199 (full session transcript, raw artifact inspection output) +# Methodology: Empirical — direct artifact inspection (L3_empirical_mod_behavior) +# Epistemic status: Class A (tool-accessed artifacts, no inference) +# Cross-references: +# - productive_chatgpt_questions (DFU-Q1/Q2/Q3 now answered by inspection) +# - secular_developer_patch (superseded — all 3 files already exist) +# - correction_absorption_taxonomy_entry (demonstrates Class D boundary) +# ============================================================================= + +deepseek_artifact_inspection: + commit: "83c72a99" + date: "2026-04-04" + source_file: "zed ai pr 90# work farmer delight operation rescue issue 135# ai thread 4-3-26 1a" + lines: 4199 + epistemic_class: "A — direct tool inspection, no inference required" + + # --------------------------------------------------------------------------- + # DFU-Q1 RESOLVED: V3818_3 lambda method name + # --------------------------------------------------------------------------- + dfu_q1_resolved: + question_id: "DFU-Q1" + status: "RESOLVED_BY_INSPECTION" + answer: "lambda$registerTypes$0" + source: > + vectorwing's own V3818_3Mixin.java on dev-1.21.1/1.3: + @ModifyArg(method = "lambda$registerTypes$0", at = @At(value = "INVOKE", + target = "Lcom/mojang/datafixers/DSL;optionalFields(...)...")) + popperian_status: "FALSIFIED — answer obtained from artifact, not from ChatGPT training data" + note: "ChatGPT was not needed for this answer. Class A inspection resolved it." + + # --------------------------------------------------------------------------- + # DFU-Q2 RESOLVED: Does ItemStackComponentizationFix need a separate mixin? + # --------------------------------------------------------------------------- + dfu_q2_resolved: + question_id: "DFU-Q2" + status: "RESOLVED_BY_INSPECTION" + answer: > + vectorwing already wrote ItemStackComponentizationFixMixin.java targeting + fixItemStack() at @At("HEAD"). The method does NOT re-run on components set + inside its own execution. vectorwing confirmed this limitation empirically + with the "// NOT WORKING?" comment on the meal extraction block. + source: "FarmersDelight dev-1.21.1/1.3, common/mixin/ItemStackComponentizationFixMixin.java" + popperian_status: "FALSIFIED — answer obtained from artifact" + + # --------------------------------------------------------------------------- + # DFU-Q3 RESOLVED: reinforced-chests mixin targets (with commit hash correction) + # --------------------------------------------------------------------------- + dfu_q3_resolved: + question_id: "DFU-Q3" + status: "RESOLVED_BY_INSPECTION" + commit_hash_correction: + wrong: "c70e3eb" + correct: "3ec8866" + note: "Commit hash c70e3eb in DFU-Q3 and secular_developer_patch was incorrect" + answer: > + reinforced-chests (commit 3ec8866) has exactly 2 datafixer mixin files: + 1. Schema1460Mixin.java — @Mixin(Schema1460.class), + @Inject(method = "registerBlockEntities", at = @At("RETURN"), cancellable = true) + 2. ItemStackComponentizationFixMixin.java — @Mixin(ItemStackComponentizationFix.class), + @Inject(method = "fixBlockEntityData", at = @At("RETURN"), cancellable = true) + NO V3818_3 mixin exists in reinforced-chests. + source: "reinforced-chests repo, commit 3ec8866" + popperian_status: "FALSIFIED — answer obtained from artifact" + + # --------------------------------------------------------------------------- + # VECTORWING'S EXISTING FILES (all 3 already in dev-1.21.1/1.3) + # --------------------------------------------------------------------------- + vectorwing_existing_files: + branch: "dev-1.21.1/1.3" + discovery: > + All three mixin files proposed in secular_developer_patch already exist + in vectorwing's dev branch. They are registered in farmersdelight.mixins.json. + + files_found: + - path: "common/mixin/V1460Mixin.java" + status: "COMPLETE" + target_class: "V1460" + target_method: "registerBlockEntities()" + injection_point: "@At(RETURN)" + registers: + - "farmersdelight:stove (Inventory.Items)" + - "farmersdelight:cutting_board (Inventory.Items)" + - "farmersdelight:skillet (Inventory.Items)" + - "farmersdelight:cooking_pot (Inventory.Items + Container)" + - "farmersdelight:cabinet (flat Items)" + - "farmersdelight:basket (flat Items)" + assessment: "structurally correct — identical to secular_developer_patch File 1" + + - path: "common/mixin/V3818_3Mixin.java" + status: "COMPLETE" + target_class: "V3818_3" + target_method: "lambda$registerTypes$0" + injection_type: "@ModifyArg" + adds_components: + - "farmersdelight:meal -> References.ITEM_STACK" + - "farmersdelight:container -> References.ITEM_STACK" + assessment: "structurally correct — identical to secular_developer_patch File 2" + + - path: "common/mixin/ItemStackComponentizationFixMixin.java" + status: "BUG_PRESENT" + target_class: "ItemStackComponentizationFix" + target_method: "fixItemStack()" + injection_point: "@At(HEAD)" + working_block: > + data.setComponent("farmersdelight:container", subTag.get("Container")); + // Container (bowl/bucket) transfers correctly + broken_block: > + List> list = subTag.get("Inventory").get("Items") + .asList(listTag -> listTag.remove("Slot")); + if (!list.isEmpty()) { + data.setComponent("farmersdelight:meal", list.getFirst()); + } + vectorwing_comment: "// NOT WORKING?" + assessment: "BUG — meal Count does not transfer; vectorwing already identified this" + + mixins_json_registered: true + mixins_json_entries: + - "ItemStackComponentizationFixMixin" + - "V1460Mixin" + - "V3818_3Mixin" + + # --------------------------------------------------------------------------- + # SECULAR_DEVELOPER_PATCH REVISION + # --------------------------------------------------------------------------- + secular_developer_patch_revision: + status: "SUPERSEDED" + reason: > + secular_developer_patch (lines 777+) proposed writing 3 new mixin files + as the fix for Issue #135. All 3 files already exist in vectorwing's + dev-1.21.1/1.3 branch and are registered in mixins.json. + The task is NOT to write new files. + The task IS to debug and fix the "// NOT WORKING?" section in the existing + ItemStackComponentizationFixMixin.java. + new_task: "fix_existing_mixin_bug" + bug_location: > + FarmersDelight dev-1.21.1/1.3: + common/mixin/ItemStackComponentizationFixMixin.java, + meal extraction block (lines after "// NOT WORKING?") + + # --------------------------------------------------------------------------- + # CRITICAL DIAGNOSTIC: fixBlockEntityData vs fixItemStack + # --------------------------------------------------------------------------- + critical_diagnostic: + finding: > + reinforced-chests targets fixBlockEntityData() — vectorwing targets fixItemStack(). + These are different methods with different semantics. + method_comparison: + reinforced_chests: + method: "fixBlockEntityData" + injection: "@At(RETURN), cancellable = true" + context: > + Called once per block entity item. Receives the full BlockEntityTag + before component conversion. Has access to the complete NBT tree. + vectorwing: + method: "fixItemStack" + injection: "@At(HEAD)" + context: > + Called per individual item stack during componentization. + The BlockEntityTag sub-items have not been individually upgraded yet. + The Inventory.Items path may resolve differently at this stage. + hypothesis: > + vectorwing's "// NOT WORKING?" bug may be caused by targeting fixItemStack + instead of fixBlockEntityData. At fixItemStack HEAD, the BlockEntityTag + context is present but the Inventory.Items sub-stacks have not yet been + individually processed by the DFU — meaning the path + subTag.get("Inventory").get("Items") may resolve to an empty or malformed + list at that point in the pipeline. + Switching to fixBlockEntityData (as reinforced-chests does) would provide + the full NBT context at the correct pipeline stage. + falsifies_if: > + Switching the @Inject target from fixItemStack to fixBlockEntityData and + adjusting the method signature resolves the meal Count not transferring. + If the bug persists after the method switch, the hypothesis is falsified + and a different cause must be identified. + popperian_status: "OPEN — hypothesis generated, not yet tested" + next_action: > + Propose patch to vectorwing's ItemStackComponentizationFixMixin.java: + change @Inject(method = "fixItemStack") to @Inject(method = "fixBlockEntityData") + with matching method signature changes. Test against a 1.20.1 world with + a Cooking Pot containing a stacked meal item. Verify Count transfers. + + # --------------------------------------------------------------------------- + # COOKING POT NBT STRUCTURE (from CookingPotBlockEntity.saveAdditional) + # --------------------------------------------------------------------------- + cooking_pot_nbt_structure: + source: "FarmersDelight dev-1.21.1/1.3, CookingPotBlockEntity.java" + structure: > + BlockEntityTag: + Inventory: (ItemStackHandler NBT wrapper) + Items: (list of item stacks with Slot field) + - {Slot: 0b, id: "...", Count: Xb} (ingredient slot 0) + - {Slot: 1b, id: "...", Count: Xb} (ingredient slot 1) + ... + - {Slot: Nb, id: "...", Count: Xb} (output/meal slot) + Container: (bowl/bucket item — the serving vessel) + id: "minecraft:bowl" + Count: 1b + CookTime: 0 + CookTimeTotal: 200 + meal_storage_note: > + The meal output is stored in Inventory.Items at a specific slot index, + NOT at index 0. list.getFirst() in vectorwing's code likely retrieves + the first ingredient rather than the meal output item. + This may be a SECOND bug in the meal extraction, compounding the + fixItemStack vs fixBlockEntityData method targeting issue.