docs: add human readable specifications for stock ledger (#29308)

* docs: add human readable specifications for stock ledger

* docs: reposting technical implementation notes
diff --git a/erpnext/stock/spec/README.md b/erpnext/stock/spec/README.md
new file mode 100644
index 0000000..f5a3501
--- /dev/null
+++ b/erpnext/stock/spec/README.md
@@ -0,0 +1,103 @@
+# Implementation notes for Stock Ledger
+
+
+## Important files
+
+- `stock/stock_ledger.py`
+- `controllers/stock_controller.py`
+- `stock/valuation.py`
+
+## What is in an Stock Ledger Entry (SLE)?
+
+Stock Ledger Entry is a single row in the Stock Ledger. It signifies some
+modification of stock for a particular Item in the specified warehouse.
+
+- `item_code`: item for which ledger entry is made
+- `warehouse`: warehouse where inventory is affected
+- `actual_qty`: change in qty
+- `qty_after_transaction`: quantity available after the transaction is processed
+- `incoming_rate`: rate at which inventory was received.
+- `is_cancelled`: if 1 then stock ledger entry is cancelled and should not be used
+for any business logic except for the code that handles cancellation.
+- `posting_date` & `posting_time`: Specify the temporal ordering of stock ledger
+  entries. Ties are broken by `creation` timestamp.
+- `voucher_type`: Many transaction can create SLE, e.g. Stock Entry, Purchase
+  Invoice
+- `voucher_no`: `name` of the transaction that created SLE
+- `voucher_detail_no`: `name` of the child table row from parent transaction
+  that created the SLE.
+- `dependant_sle_voucher_detail_no`: cross-warehouse transfers need this
+  reference in order to update dependent warehouse rates in case of change in
+  rate.
+- `recalculate_rate`: if this is checked in/out rates are recomputed on
+  transactions.
+- `valuation_rate`: current average valuation rate.
+- `stock_value`: current total stock value
+- `stock_value_difference`: stock value difference made between last and current
+  entry. This value is booked in accounting ledger.
+- `stock_queue`: if FIFO/LIFO is used this represents queue/stack maintained for
+  computing incoming rate for inventory getting consumed.
+- `batch_no`: batch no for which stock entry is made; each stock entry can only
+  affect one batch number.
+- `serial_no`: newline separated list of serial numbers that were added (if
+  actual_qty > 0) or else removed. Currently multiple serial nos can have single
+  SLE but this will likely change in future.
+
+
+## Implementation of Stock Ledger
+
+Stock Ledger Entry affects stock of combinations of (item_code, warehouse) and
+optionally batch no if specified. For simplicity, lets avoid batch no. for now.
+
+
+Stock Ledger Entry table stores stock ledger for all combinations of item_code
+and warehouse. So whenever any operations are to be performed on said
+item-warehouse combination stock ledger is filtered and sorted by posting
+datetime. A typical query that will give you individual ledger looks like this:
+
+```sql
+select *
+from `tabStock Ledger Entry` as sle
+where
+    is_cancelled = 0  --- cancelled entries don't affect ledger
+    and item_code = 'item_code' and warehouse = 'warehouse_name'
+order by timestamp(posting_date, posting_time), creation
+```
+
+New entry is just an update to the last entry which is found by looking at last
+row in the filter ledger.
+
+
+### Serial nos
+
+Serial numbers do not follow any valuation method configuration and they are
+consumed at rate they were produced unless they are grouped in which case they
+are consumed at weighted average rate.
+
+
+### Batch Nos
+
+Batches are currently NOT consumed as per batch wise valuation rate, instead
+global FIFO queue for the item is used for valuation rate.
+
+
+## Creation process of SLEs
+
+- SLE creation is usually triggered by Stock Transactions using a method
+  conventionally named `update_stock_ledger()` This might not be defined for
+  stock transaction and could be specified somewhere in inheritance hierarchy of
+  controllers.
+- This method produces SLE objects which are processed by `make_sl_entries` in
+  `stock_ledger.py` which commits the SLE to database.
+- `update_entries_after` class is used to process ONLY the inserted SLE's queue
+  and valuation.
+- The change in qty is propagated to future entries immediately. Valuation and
+  queue for future entries is processed in background using repost item
+  valuation.
+
+
+## Accounting impact
+
+- Accounting impact for stock transaction is handled by `get_gl_entries()`
+  method on controllers. Each transaction has different business logic for
+  booking the accounting impact.
diff --git a/erpnext/stock/spec/reposting.md b/erpnext/stock/spec/reposting.md
new file mode 100644
index 0000000..b0d59fe
--- /dev/null
+++ b/erpnext/stock/spec/reposting.md
@@ -0,0 +1,38 @@
+# Stock Reposting
+
+Stock "reposting" is process of re-processing Stock Ledger Entry and GL Entries
+in event of backdated stock transaction.
+
+*Backdated stock transaction*: Any stock transaction for which some
+item-warehouse combination has a future transactions.
+
+## Why is this required?
+Stock Ledger is stateful, it maintains queue, qty at any
+point in time. So if you do a backdated transaction all future values change,
+queues need to be re-evaluated etc. Watch Nabin and Rohit's conference
+presentation for explanation: https://www.youtube.com/watch?v=mw3WAnekGIM
+
+## How is this implemented?
+Whenever backdated transaction is detected, instead of
+fully processing it while submitting, the processing is queued using "Repost
+Item Valuation" doctype. Every hour a scheduled job runs and processes this
+queue (for up to maximum of 25 minutes)
+
+
+## Queue implementation
+- "Repost item valuation" (RIV) is automatically submitted from backdated transactions. (check stock_controller.py)
+- Draft and cancelled RIV are ignored.
+- Keep filter of "submitted" documents when doing anything with RIVs.
+- The default status is "Queued".
+- When background job runs, it picks the oldest pending reposts and changes the status to "In Progress" and when it finishes it
+changes to "Completed"
+- There are two more status: "Failed" when reposting failed and "Skipped" when reposting is deemed not necessary so it's skipped.
+- technical detail: Entry point for whole process is "repost_entries" function in repost_item_valuation.py
+
+
+## How to identify broken stock data:
+There are 4 major reports for checking broken stock data:
+- Incorrect balance qty after the transaction - to check if the running total of qty isn't correct.
+- Incorrect stock value report - to check incorrect value books in accounts for stock transactions
+- Incorrect serial no valuation -specific to serial nos
+- Stock ledger invariant check - combined report for checking qty, running total, queue, balance value etc