{"record":{"id":"218c29f35e53c02d","repo":"affaan-m/ECC","slug":"metadata-reorder-detected-at-location-move-the-matching","errorCode":null,"errorMessage":"Metadata reorder detected at ${location}; move the matching sidecar entry before refreshing fingerprints","messagePattern":"Metadata reorder detected at (.+?); move the matching sidecar entry before refreshing fingerprints","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/lib/hooks-config.js","lineNumber":248,"sourceCode":"\n  // A known fingerprint at another position signals a reorder, not a command\n  // edit. Require the author to move its metadata before refreshing anything.\n  const positions = new Map();\n  for (const [event, entries] of Object.entries(events)) {\n    if (!Array.isArray(entries)) continue;\n    entries.forEach((entry, index) => {\n      const fingerprint = fingerprintHookEntry(entry);\n      const locations = positions.get(fingerprint) || [];\n      positions.set(fingerprint, [...locations, `${event}[${index}]`]);\n    });\n  }\n  for (const [event, entries] of Object.entries(entriesByEvent)) {\n    if (!Array.isArray(entries)) continue;\n    entries.forEach((entry, index) => {\n      const locations = positions.get(entry?.fingerprint);\n      const location = `${event}[${index}]`;\n      if (locations && !locations.includes(location)) {\n        throw new Error(`Metadata reorder detected at ${location}; move the matching sidecar entry before refreshing fingerprints`);\n      }\n    });\n  }\n\n  for (const [event, eventMetadata] of Object.entries(entriesByEvent)) {\n    const entries = Array.isArray(events[event]) ? events[event] : [];\n    refreshed[event] = Array.isArray(eventMetadata)\n      ? eventMetadata.map((entry, index) => (\n        entry && typeof entry === 'object' && index < entries.length\n          ? { ...entry, fingerprint: fingerprintHookEntry(entries[index]) }\n          : entry\n      ))\n      : eventMetadata;\n  }\n\n  return { ...metadata, entries: refreshed };\n}\n","sourceCodeStart":230,"sourceCodeEnd":266,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/hooks-config.js#L230-L266","documentation":"withRefreshedFingerprints() in scripts/lib/hooks-config.js cross-checks the order of hook entries in hooks.json against fingerprint positions recorded in the metadata sidecar. If an entry's fingerprint exists in the sidecar but at a different location (event[index]) than its current position, it throws a 'Metadata reorder detected' error. This is an integrity guard: fingerprints are position-sensitive, so a silent reorder would attach metadata (matchers, descriptions) to the wrong hook.","triggerScenarios":"Calling validateHooks() or refreshed() after manually reordering, inserting, or deleting entries within a hooks event array in hooks.json without moving the corresponding entries in the metadata sidecar (.hooks-metadata style file) to match.","commonSituations":"Hand-editing hooks.json to reorder matchers; a formatter or merge that reshuffled array entries; deleting an earlier hook so subsequent indexes shift while sidecar entries keep old indexes.","solutions":["Reorder the entries in the metadata sidecar to mirror the new order in hooks.json (the error names the exact location, e.g. Stop[2]).","Alternatively revert hooks.json to the order recorded in the sidecar, then re-apply changes via the ECC tooling (addJsonMergeOperation) so sidecar and hooks stay in sync.","If the reorder is intentional and metadata mapping is stale, regenerate the sidecar metadata for the new order rather than refreshing fingerprints in place."],"exampleFix":"// before: hooks.json has matcher A,B but sidecar lists fingerprints as [B,A]\nwithRefreshedFingerprints(...); // throws Metadata reorder detected at Stop[1]\n// after: reorder sidecar entries array to [fingerprintA, fingerprintB]\nmetadata.entries.Stop = [fpA, fpB]; // match hooks.json order\nwithRefreshedFingerprints(...); // ok","handlingStrategy":"validation","validationCode":"// verify hooks.json entry order matches sidecar metadata before refreshing\nconst cfg = JSON.parse(fs.readFileSync(hooksPath, 'utf8'));\nconst meta = JSON.parse(fs.readFileSync(metadataPath, 'utf8'));\nfor (const [event, entries] of Object.entries(cfg.hooks || {})) {\n  const fps = (meta.entries?.[event] || []).map(e => e.fingerprint);\n  const current = entries.map(e => fingerprintFor(e));\n  const aligned = current.every((fp, i) => fp === fps[i]);\n  if (!aligned) throw new Error(`Reorder ${event} sidecar entries before refreshing fingerprints`);\n}","typeGuard":"function isAlignedOrder(entries, metadataEntries) {\n  return Array.isArray(entries) && Array.isArray(metadataEntries) &&\n    entries.length === metadataEntries.length;\n}","tryCatchPattern":"try {\n  const result = withRefreshedFingerprints(/* ... */);\n} catch (err) {\n  if (String(err.message).startsWith('Metadata reorder detected')) {\n    const loc = err.message.match(/at (\\S+);/)?.[1];\n    console.error(`Reorder sidecar entry for ${loc} to match hooks.json, then retry.`);\n  } else throw err;\n}","preventionTips":["Never reorder hook arrays by hand — use the ECC tooling that updates the sidecar in lockstep.","When reordering is needed, move entries in both hooks.json and the metadata sidecar in the same edit.","Disable formatters/plugins that sort array entries inside hooks.json.","Treat hooks.json + sidecar as an atomic pair in backups and branch merges."],"tags":["hooks","metadata","integrity-check","ordering"],"backgroundTag":"checksum-mismatch","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}