{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://neon-sprawl.local/schemas/resource-node-def.json", "title": "ResourceNodeDef", "description": "Single resource node row for catalogs (e.g. content/resource-nodes/*_resource_nodes.json). nodeDefId is stable forever—rename displayName only. See docs/decomposition/modules/E3_M1_ResourceNodeAndGatherLoop.md.", "type": "object", "additionalProperties": false, "required": ["nodeDefId", "displayName", "gatherLens", "maxGathers"], "properties": { "nodeDefId": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "Immutable node key; must match interactableId for prototype wiring." }, "displayName": { "type": "string", "minLength": 1, "description": "Player-facing label; safe to change without migrating state." }, "gatherLens": { "type": "string", "description": "Prototype Slice 2 gather lens (one per frozen node). CI requires exactly one row per lens.", "enum": ["consumer_salvage", "subsurface", "bio", "urban_bulk"] }, "maxGathers": { "type": "integer", "minimum": 1, "description": "Successful gathers before node instance is depleted (prototype Slice 2)." } } }