{"id":"acct-coa-mapping-json-split","audience":"accounting","category":"finance-work","track":"finance","technique":"examples","level":"advanced","title":"Map an old chart of accounts to a new one as JSON","free":false,"task":"You're moving to a new chart of accounts and need a mapping file the system can import. Write a prompt that returns only one JSON code block: an array with one object per old account, in order, each on one line with keys old, new and status. \"new\" is a list of new account numbers; status is MAPPED (one account), SPLIT (two) or UNMAPPED (none, for the controller). Watch for retired accounts in the new chart.","materialLabel":"Old and new charts of accounts (attached to your prompt automatically)","material":"OLD chart (Wrenfield Ceramics, QuickBooks)\n4000 Sales\n4100 Shipping Income\n5000 Cost of Goods Sold\n6000 Advertising\n6100 Auto\n6200 Travel & Meals\n6300 Rent\n6400 Software\n6900 Miscellaneous\n\nNEW chart (effective Jan 1, 2027)\n4010 Product Revenue\n4020 Shipping & Handling Revenue\n5010 Cost of Goods Sold\n6110 Marketing & Advertising\n6120 Advertising (retired - merged into 6110, do not use)\n6210 Rent & Occupancy\n6310 Software Subscriptions\n6410 Travel\n6420 Meals\n6430 Vehicle Expense\n\nNotes from the migration call:\n- New chart has no catch-all account on purpose. Old Miscellaneous needs line-by-line review by the controller.\n- Travel and meals are tracked separately from 2027.","rules":[{"type":"codeBlocks","count":1},{"type":"maxCodeLines","max":11},{"type":"maxProseWords","max":20}],"promptHints":[{"label":"Asks for JSON only","patterns":["json","code block"]},{"label":"Shows one object","patterns":["\\\"old\\\"","status","keys"]},{"label":"Defines the statuses","patterns":["mapped","split","unmapped"]},{"label":"Avoids retired accounts","patterns":["retired","do not use","6120"]},{"label":"One object per line","patterns":["one (object )?per line","one line"]}],"mistakes":[{"title":"Mapping to a retired account","why":"The AI matches names and picks 6120 Advertising, which the new chart retired.","fix":"Say: \"Never map to an account marked retired.\"","checks":["r1"]},{"title":"Forcing a match for Misc","why":"The AI dumps Miscellaneous into whatever looks closest.","fix":"Add: \"If there's no match, status UNMAPPED and an empty list, for the controller.\"","checks":["r1"]},{"title":"Not showing the shape","why":"The AI invents its own keys or makes new a string for some rows and a list for others.","fix":"Show one object literally: {\"old\": \"4000\", \"new\": [\"4010\"], \"status\": \"MAPPED\"}.","checks":["r0","r2"]},{"title":"Prose around the file","why":"The AI explains its choices before and after the JSON, which breaks the import.","fix":"Say: \"Output only one JSON code block, one object per line, nothing else.\"","checks":["codeBlocks","maxCodeLines","maxProseWords"]}],"hint":"An import file needs one exact shape every time. Show the AI one finished object, define each status, and tell it what to do when there's no clean match.","rubricLabels":["The code block is a JSON array with one object per old account (9 objects) in the old chart's order, each with exactly the keys old, new and status, and new is always a list","6000 Advertising maps to [\"6110\"] (not the retired 6120) and 6900 Miscellaneous has status UNMAPPED with an empty new list","6200 Travel & Meals has status SPLIT with new [\"6410\", \"6420\"], and every other account is MAPPED to exactly one new account (4000 to 4010, 4100 to 4020, 5000 to 5010, 6100 to 6430, 6300 to 6210, 6400 to 6310)"]}