{"id":"event-ledger","title":"Repair an event ledger","summary":"Duplicate events, balance checks, atomic batches.","phases":["Repair the ledger. Input: {balances: {account: nonnegative integer},\nevents: [{id, from, to, amount}]}. Accounts and event IDs are nonempty ASCII\nidentifiers. from and to name distinct existing accounts; amount is positive.\nStart each account version at zero. Process events in order. An accepted\ntransfer debits from, credits to, and increments both account versions once.\nReject insufficient funds with no state change. Remember only accepted IDs:\na repeated accepted ID is duplicate, even with a different payload, and changes\nnothing. Rejected IDs may be retried. Return {balances, versions, receipts},\nwhere receipts has one {id, status} per event, status applied/duplicate/rejected.\nInput must not be mutated. Empty input collections are valid.","Extend the same ledger without breaking transfers. Events may now\nbe batches {id, moves:[{from,to,amount}], expected?:{account:version}}. Transfers\nmay also have expected. Duplicate detection happens first. For a new ID, reject\nif any expected version differs from the current version. Execute moves in\norder on a draft: if any move lacks funds, reject the WHOLE event without balance\nor version changes and do not reserve its ID. On success, increment each touched\naccount's version once per event, even if touched many times or its final balance\nis unchanged. An empty batch is accepted, reserves its ID, and changes no versions.\nUse the same return shape. Existing single transfers retain their behavior."],"prompts":["Work in this repository. Implement synchronous CommonJS JavaScript.\nThe entry point is src/index.js, exporting { solve }. solve(input) must return a\nJSON-serializable value. Use only relative .js modules within src/. No packages,\nfilesystem, network, timers, process, eval, or async in submitted source.\nSubmit at most 24 .js files totaling at most 128 KiB.\nYou may inspect files, edit code, add tests, and run node --test. Change src/ and\ntest/ only. Do not change the existing test/smoke.test.js. Each hidden case runs\nin a fresh QuickJS context with 32 MiB memory and 500 ms CPU time. Object key\norder does not matter; array order does. Numbers are safe integers. All inputs\nsatisfy the stated contract. No Internet or external tools are needed.\nFinish by describing the change briefly. The code on disk is the submission.\n\nWORK ORDER 1\nRepair the ledger. Input: {balances: {account: nonnegative integer},\nevents: [{id, from, to, amount}]}. Accounts and event IDs are nonempty ASCII\nidentifiers. from and to name distinct existing accounts; amount is positive.\nStart each account version at zero. Process events in order. An accepted\ntransfer debits from, credits to, and increments both account versions once.\nReject insufficient funds with no state change. Remember only accepted IDs:\na repeated accepted ID is duplicate, even with a different payload, and changes\nnothing. Rejected IDs may be retried. Return {balances, versions, receipts},\nwhere receipts has one {id, status} per event, status applied/duplicate/rejected.\nInput must not be mutated. Empty input collections are valid.","Work in this repository. Implement synchronous CommonJS JavaScript.\nThe entry point is src/index.js, exporting { solve }. solve(input) must return a\nJSON-serializable value. Use only relative .js modules within src/. No packages,\nfilesystem, network, timers, process, eval, or async in submitted source.\nSubmit at most 24 .js files totaling at most 128 KiB.\nYou may inspect files, edit code, add tests, and run node --test. Change src/ and\ntest/ only. Do not change the existing test/smoke.test.js. Each hidden case runs\nin a fresh QuickJS context with 32 MiB memory and 500 ms CPU time. Object key\norder does not matter; array order does. Numbers are safe integers. All inputs\nsatisfy the stated contract. No Internet or external tools are needed.\nFinish by describing the change briefly. The code on disk is the submission.\n\nWORK ORDER 2\nRepair the ledger. Input: {balances: {account: nonnegative integer},\nevents: [{id, from, to, amount}]}. Accounts and event IDs are nonempty ASCII\nidentifiers. from and to name distinct existing accounts; amount is positive.\nStart each account version at zero. Process events in order. An accepted\ntransfer debits from, credits to, and increments both account versions once.\nReject insufficient funds with no state change. Remember only accepted IDs:\na repeated accepted ID is duplicate, even with a different payload, and changes\nnothing. Rejected IDs may be retried. Return {balances, versions, receipts},\nwhere receipts has one {id, status} per event, status applied/duplicate/rejected.\nInput must not be mutated. Empty input collections are valid.\n\nExtend the same ledger without breaking transfers. Events may now\nbe batches {id, moves:[{from,to,amount}], expected?:{account:version}}. Transfers\nmay also have expected. Duplicate detection happens first. For a new ID, reject\nif any expected version differs from the current version. Execute moves in\norder on a draft: if any move lacks funds, reject the WHOLE event without balance\nor version changes and do not reserve its ID. On success, increment each touched\naccount's version once per event, even if touched many times or its final balance\nis unchanged. An empty batch is accepted, reserves its ID, and changes no versions.\nUse the same return shape. Existing single transfers retain their behavior."],"starter":{"src/index.js":"module.exports = require(\"./engine.js\");\n","src/engine.js":"// Current transfer handler. Receipts and versions are part of the public API.\nfunction solve(input) {\n  const balances={...input.balances};\n  const versions=Object.fromEntries(Object.keys(balances).map(k=>[k,0]));\n  const receipts=input.events.map(e=>{\n    if(balances[e.from]<e.amount)return {id:e.id,status:'rejected'};\n    balances[e.from]-=e.amount;balances[e.to]+=e.amount;\n    versions[e.from]++;versions[e.to]++;\n    return {id:e.id,status:'applied'};\n  });\n  return {balances,versions,receipts};\n}\nmodule.exports={solve};\n"}}