kairos-chain 3.59.0 → 3.61.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +88 -0
  3. data/lib/kairos_mcp/version.rb +1 -1
  4. data/templates/skillsets/account_manager/config/accounts.yml +115 -0
  5. data/templates/skillsets/account_manager/knowledge/account_manager_guide/account_manager_guide.md +200 -0
  6. data/templates/skillsets/account_manager/lib/account_manager/config.rb +259 -0
  7. data/templates/skillsets/account_manager/lib/account_manager/importer.rb +122 -0
  8. data/templates/skillsets/account_manager/lib/account_manager/money.rb +64 -0
  9. data/templates/skillsets/account_manager/lib/account_manager/report.rb +247 -0
  10. data/templates/skillsets/account_manager/lib/account_manager/store.rb +718 -0
  11. data/templates/skillsets/account_manager/lib/account_manager/tool_helpers.rb +54 -0
  12. data/templates/skillsets/account_manager/lib/account_manager.rb +30 -0
  13. data/templates/skillsets/account_manager/plugin/SKILL.md +96 -0
  14. data/templates/skillsets/account_manager/plugin/agents/bookkeeper.md +81 -0
  15. data/templates/skillsets/account_manager/skillset.json +33 -0
  16. data/templates/skillsets/account_manager/test/test_account_manager.rb +1319 -0
  17. data/templates/skillsets/account_manager/tools/am_close.rb +80 -0
  18. data/templates/skillsets/account_manager/tools/am_entry.rb +144 -0
  19. data/templates/skillsets/account_manager/tools/am_import.rb +70 -0
  20. data/templates/skillsets/account_manager/tools/am_query.rb +96 -0
  21. data/templates/skillsets/account_manager/tools/am_receipt.rb +69 -0
  22. data/templates/skillsets/account_manager/tools/am_report.rb +85 -0
  23. data/templates/skillsets/multi_llm_review/lib/multi_llm_review/consensus.rb +65 -5
  24. data/templates/skillsets/multi_llm_review/lib/multi_llm_review/prompt_builder.rb +35 -1
  25. data/templates/skillsets/multi_llm_review/lib/multi_llm_review/review_serializer.rb +101 -2
  26. data/templates/skillsets/multi_llm_review/lib/multi_llm_review/sanitizer.rb +137 -8
  27. data/templates/skillsets/multi_llm_review/skillset.json +2 -2
  28. data/templates/skillsets/multi_llm_review/test/test_evidence_fidelity.rb +484 -0
  29. data/templates/skillsets/multi_llm_review/tools/multi_llm_review.rb +52 -5
  30. data/templates/skillsets/multi_llm_review/tools/multi_llm_review_collect.rb +81 -11
  31. metadata +21 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 104bc21b4db1c6c438f5e18767df43571d318f5637a878e626f22433b3d46b69
4
- data.tar.gz: 57edf1d45e47e26f444e794c5b1e7be1be1e01cbbbd7ed831201265f8bfc18c1
3
+ metadata.gz: d38191ff3e513822d6183bf4fee4c92e497148978eda3bda064a01b81d0bf95b
4
+ data.tar.gz: 97999aa9377a086ea092237ad53605fec24b9e01c9691e7c92c24b6329bd565e
5
5
  SHA512:
6
- metadata.gz: 8c0e5a937839894abada8bf37ad6b226d1b5d357e4a08f2a7a50d0cfac6fbd2aa5fc0fc455729996ef090610e9a19bf7c4be3f368ded7bf44d7c86a7735e3d58
7
- data.tar.gz: 490cdba379a4c395cfd704e7e4e96f4f8ee170225afb55d5f7f2c63adbe1f904e09e6b1f5bb4c856fe6b4a44b675e2e07f80ff79294c5f719cd6b5afa5c4088d
6
+ metadata.gz: eacfebd73445ea5e6a503bb34e8978a0a6c649d34a46810140a885f235e3933b01701d45921341b6771caa64c58f4dac61f51233d2741417e8b59be111196109
7
+ data.tar.gz: bffb450e4de67e1b3c179de5bd48b86d1d6d3c2bc8e69cd6878fd6d89b6e3346fae29b09cd5ef79ddbb12f16498e0f944da84af4a62b3a36eff0db05ea5b6d96
data/CHANGELOG.md CHANGED
@@ -4,6 +4,94 @@ All notable changes to the `kairos-chain` gem will be documented in this file.
4
4
 
5
5
  This project follows [Semantic Versioning](https://semver.org/).
6
6
 
7
+ ## [3.61.0] - 2026-08-06
8
+
9
+ ### Fixed
10
+
11
+ - **`multi_llm_review` (SkillSet 0.9.0) — a finding reaches the record whole, and the record
12
+ stops claiming what it cannot know.** A downstream instance measured, across four real rounds,
13
+ that 18 of 21 aggregated findings came back at exactly 201 bytes while `reviews[].raw_text` was
14
+ empty on every row and `raw_text_length` reported the real size. Three bounds were doing it: an
15
+ inclusive Range (`issue.strip[0..200]`, hence 201) in aggregation, the 500-character display
16
+ limit applied to the record as well as the prompt, and a serializer row that carried a reply's
17
+ length but never the reply. A fourth defect discarded a distinct finding on dedup collision
18
+ without saying so.
19
+
20
+ Findings are now bounded in **bytes** at `FINDING_RECORD_MAX_LEN = 8000` for the record, with
21
+ `DEFAULT_MAX_LEN = 500` still applied by every path taking a finding into a prompt. The dedup key
22
+ is unchanged at 80 characters — widening it would stop two reviewers describing one defect from
23
+ merging, which moves the finding count and the convergence denominator — but the surviving text
24
+ is no longer arbitrary: `issue` comes from a member whose severity equals the merged severity,
25
+ and distinct texts survive in `issue_variants` (capped at `MAX_ISSUE_VARIANTS = 8`, with
26
+ `issue_variants_omitted` naming what the cap dropped). Every row now carries `raw_text_excerpt`
27
+ unconditionally at 4096 bytes, and the reply itself in `raw_text` on request
28
+ (`include_raw_text`, 65536 bytes). Findings carried into a later round's prompt are sanitised and
29
+ folded to one line — a path that previously took reviewer text into a prompt with no sanitisation
30
+ at all.
31
+
32
+ **The two evidence fields are sanitised transcriptions, not verbatim records, and the tool
33
+ schemas now say so** rather than implying otherwise. The text is byte-clamped, NFKC-normalised,
34
+ stripped of invisible characters, tag-escaped, then byte-clamped again; normalisation rewrites
35
+ compatibility forms, the strip removes five of Unicode's eight mandatory line breaks, and the tag
36
+ escape collapses unbounded whitespace. No field states whether a stored text is the whole reply.
37
+ A completeness flag was implemented for exactly that purpose and then removed: three reviewers
38
+ measured it wrong in **both** directions — a 4,010-byte reply stored as 18 bytes reported
39
+ complete, and a reply whose every readable byte survived reported truncated. "Was anything
40
+ dropped" cannot be answered by byte counts taken around a pass that also rewrites, strips and
41
+ escapes. On delegated runs the pending-state record keeps each subprocess reply as it arrived; on
42
+ single-phase runs the returned payload is the only form there is, and the schema distinguishes
43
+ the two.
44
+
45
+ Six review rounds, four pre-flight falsifier passes and forty-plus mutations. Every defect in
46
+ this change was found by adversarial reading or by mutating the code in a copy outside the
47
+ repository; **none** by the test suite passing. Known and disclosed rather than closed: the
48
+ excerpt can store a word the reviewer did not write (normalisation cannot simply be dropped —
49
+ the delimiter pattern matches ASCII angle brackets, so a fullwidth `<artifact>` would pass
50
+ straight through an escape that no longer normalises, and the escape-without-normalise entry
51
+ point `stated_text` has been waiting on since R2 does not exist yet); the measured response
52
+ ceiling of 28.9 MB against a declared 14.4 MB; and thirteen sites that survive deletion with the
53
+ suite green.
54
+
55
+ ## [3.60.0] - 2026-08-05
56
+
57
+ ### Added
58
+
59
+ - **`account_manager` (SkillSet 0.1.0) — a jurisdiction-neutral double-entry ledger for a
60
+ one-person business that is also a household cash book.** One person, two purses: the books must
61
+ separate for tax, but the money does not — the owner draws from the business and pays business
62
+ costs from a private card. Six tools (`am_entry`, `am_import`, `am_query`, `am_report`,
63
+ `am_receipt`, `am_close`), one ledger with two books, one currency, and a bookkeeper-persona
64
+ sub-agent that transcribes on the way in and reads figures on the way out but cannot post,
65
+ confirm, discard, close or bind evidence.
66
+
67
+ No country's rules appear in any code path. The chart of accounts, tax labels, fiscal year and
68
+ import profiles are configuration; adding a country means writing one YAML file. The loader has
69
+ one refusal with a closed list of causes, and a missing ledger configuration is refused rather
70
+ than substituted by the shipped example.
71
+
72
+ Three things carry the design. A **range** is one calendar month derived from the transaction
73
+ date, so ranges cannot overlap or leave a gap and the rules that would have policed that do not
74
+ exist. A **proposal** is not a figure: imported rows and transcriptions are visible, counted by
75
+ no report, and become postings only by an explicit operator call. The **annual close posts, then
76
+ seals** — it credits each book's own retained earnings dated the fiscal year's last day, then
77
+ seals every month of that year, and that entry is the one posting permitted into a
78
+ period-closed (never sealed) range, because refusing it would make the annual close unreachable
79
+ in ordinary month-by-month use.
80
+
81
+ Design review did not converge over three rounds, so the design was implemented rather than
82
+ argued further; two implementation review rounds followed. Round 1 found a ledger that lost
83
+ records — an acknowledged posting absent from disk, because each tool cached its own store and
84
+ saved a stale snapshot over it — plus a refusal idiom that never executed
85
+ (`def m(id) = h[id] or raise X` parses as `(def …) or raise`), a closing entry that credited the
86
+ wrong book, and a year sealed as year zero from `'abc'.to_i`. Twenty-seven of its twenty-eight
87
+ blocking findings are fixed, and three independent reviewers verified the fixes in round 2.
88
+ Round 2's own findings are recorded and open: twelve are missing test coverage rather than
89
+ defects, and the remainder sit at configuration edges. Known and unfixed: there is no locking,
90
+ so the store is safe for one operator on one machine and not beyond it.
91
+
92
+ Not auto-installed — `account_manager` is not in `CORE_SKILLSETS`, so it ships in the gem and is
93
+ installed explicitly, like `project_manager`.
94
+
7
95
  ## [3.59.0] - 2026-08-05
8
96
 
9
97
  ### Added
@@ -1,4 +1,4 @@
1
1
  module KairosMcp
2
- VERSION = "3.59.0"
2
+ VERSION = "3.61.0"
3
3
  CHANGELOG_URL = "https://github.com/masaomi/KairosChain_2026/blob/main/CHANGELOG.md"
4
4
  end
@@ -0,0 +1,115 @@
1
+ # account_manager — the whole jurisdiction surface, and a worked example of it.
2
+ #
3
+ # This file is a TEMPLATE, not a chart to use. Copy it to
4
+ # .kairos/accounts/<ledger>/config.yml and edit it; the copy is what the tools
5
+ # read, and this one is the fallback so a fresh instance is not dead on
6
+ # arrival. It is deliberately not any country's chart: shipping one would put
7
+ # a jurisdiction in the package by the same route that putting one in the code
8
+ # would (INV-AM-6).
9
+ #
10
+ # Every key below is read by the loader. Nothing else is.
11
+
12
+ # ISO 4217. XTS is the code reserved for testing — change it before you post
13
+ # anything, because a currency cannot change once postings exist.
14
+ currency: XTS
15
+
16
+ # One ledger, two books. A household-only ledger is this same file with one
17
+ # book, crossing: none, and tax_labels empty.
18
+ books:
19
+ - business
20
+ - private
21
+
22
+ # How a posting that crosses books is completed so each book still balances
23
+ # alone (INV-AM-2). One account per book, or `none` to refuse crossings.
24
+ crossing:
25
+ business: owner_account
26
+ private: business_claim
27
+
28
+ fiscal_year_start_month: 1
29
+
30
+ # Both must exist below with type equity. The loader refuses otherwise.
31
+ retained_earnings_account: retained_earnings
32
+ prior_period_adjustment_account: prior_period_adjustment
33
+
34
+ # `cash: true` marks an account money actually sits in — bank, cash, card.
35
+ # Reconciliation needs it, and so does the refusal of a settlement date on a
36
+ # posting where nothing moved (INV-AM-10).
37
+ chart_of_accounts:
38
+ - id: cash
39
+ name: Cash on hand
40
+ type: asset
41
+ cash: true
42
+ - id: bank
43
+ name: Business bank account
44
+ type: asset
45
+ cash: true
46
+ - id: private_card
47
+ name: Private credit card
48
+ type: liability
49
+ cash: true
50
+ - id: business_claim
51
+ name: Claim on the business (private book's side of a crossing)
52
+ type: asset
53
+ - id: receivable
54
+ name: Money owed to the business
55
+ type: asset
56
+ - id: payable
57
+ name: Money the business owes
58
+ type: liability
59
+ - id: owner_account
60
+ name: Owner's account — draws and contributions
61
+ type: equity
62
+ - id: retained_earnings
63
+ name: Retained earnings
64
+ type: equity
65
+ - id: prior_period_adjustment
66
+ name: Prior-period adjustment
67
+ type: equity
68
+ - id: income_services
69
+ name: Services rendered
70
+ type: income
71
+ default_tax_label: standard
72
+ - id: expense_supplies
73
+ name: Supplies and materials
74
+ type: expense
75
+ default_tax_label: standard
76
+ - id: expense_household
77
+ name: Household spending
78
+ type: expense
79
+
80
+ # Opaque labels. No tool derives a tax amount from one; reports group by them
81
+ # and stop there (INV-AM-8).
82
+ tax_labels:
83
+ - standard
84
+ - exempt
85
+
86
+ # One profile per source. The name is part of every key the profile produces,
87
+ # so two sources numbering their bookings from 1 do not collide (INV-AM-9).
88
+ import_profiles:
89
+ - name: example_bank
90
+ account: bank
91
+ book: business
92
+ columns:
93
+ transaction_date: Date
94
+ settlement_date: Booked
95
+ description: Text
96
+ amount: Amount
97
+ reference: Ref
98
+ # Which CSV column carries the source's own booking reference. Set it to
99
+ # nothing (omit the key) for a source with no identifier: its rows are then
100
+ # keyed by batch and position, and every re-import is reported as one.
101
+ reference_field: Ref
102
+ # positive_is_debit: a positive amount is money arriving in `account`.
103
+ sign: positive_is_debit
104
+
105
+ # Dictated lines and transcribed receipts arrive under a profile with no
106
+ # identifier, so a line dictated twice is proposed twice and the operator
107
+ # sees both.
108
+ - name: dictated
109
+ account: cash
110
+ book: private
111
+ columns:
112
+ transaction_date: date
113
+ description: description
114
+ amount: amount
115
+ sign: positive_is_debit
@@ -0,0 +1,200 @@
1
+ ---
2
+ name: account_manager_guide
3
+ description: How the account_manager ledger holds together — what a posting is, what a close freezes, why a sealed year is corrected in equity, and which decisions were made in code because prose could not settle them.
4
+ version: 0.1.0
5
+ layer: L1
6
+ author: Masaomi Hatakeyama
7
+ created: 2026-08-05
8
+ ---
9
+
10
+ # account_manager — the working guide
11
+
12
+ This is the knowledge an operator or an agent needs to use the ledger correctly and to change it
13
+ without breaking it. It is not the design draft: the draft carries five defects this
14
+ implementation fixes, and where they differ, this file and the code are right.
15
+
16
+ ## 1. What the system is
17
+
18
+ A double-entry ledger for one person with two purses — a sole proprietorship whose owner also buys
19
+ groceries. The books must separate for tax; the money does not separate at all. The owner draws
20
+ from the business and pays business costs from a private card, and a design that models these as
21
+ two unrelated datasets forces the owner to reconcile by hand, which is the work the tool exists to
22
+ remove.
23
+
24
+ It is not a tax filing engine and it knows no country's rules. It produces the figures and the
25
+ evidence a filing needs; a human or an accountant files.
26
+
27
+ ## 2. The four record types, and which ones are figures
28
+
29
+ | Record | Counted by a report? | Can it change? |
30
+ |---|---|---|
31
+ | **posting** | yes, always | only while its month is open |
32
+ | **proposal** | never | until decided; a discard can be undone |
33
+ | **closing record** | no — it *freezes* figures | append-only; a re-open appends, it does not erase |
34
+ | **evidence** | no | never removed in v0.1; there is no delete command |
35
+
36
+ The line between proposal and posting is the system's one real boundary. Everything inferential —
37
+ reading an amount off a photograph, parsing a typed sentence, guessing an account, proposing that
38
+ two rows are one transaction — happens on the proposal side, where it costs a correction. Only an
39
+ explicit operator call moves a proposal across.
40
+
41
+ ## 3. Ranges, and why there is no range table
42
+
43
+ A **range** is one calendar month of transaction dates. It is derived from the date, not declared:
44
+
45
+ ```
46
+ transaction_date 2026-03-14 ──▶ range "2026-03"
47
+ ```
48
+
49
+ Because ranges are derived, they cannot overlap and cannot leave a gap, so the refusals that would
50
+ have policed those conditions do not exist. The design draft declared ranges as spans and then had
51
+ to forbid overlaps — which made the annual close, written as closing a *year* span, permanently
52
+ refused after any monthly close. Deriving the range deletes the rule and the defect together.
53
+
54
+ A range is in one of three states, folded from the append-only closing log:
55
+
56
+ ```
57
+ open ──close──▶ closed ──reopen──▶ open
58
+
59
+ └──seal (annual close)──▶ sealed [terminal]
60
+ ```
61
+
62
+ ## 4. The two dates
63
+
64
+ | | transaction date | settlement date |
65
+ |---|---|---|
66
+ | Means | the day it happened | the day money moved |
67
+ | Places the posting in a range | **yes, alone** | never |
68
+ | Used by P&L and balance sheet | yes | never |
69
+ | Used by reconciliation | no | **only this** |
70
+ | Absent when | never | no money moved |
71
+
72
+ Three reviewers independently named the ambiguity between these two the worst defect in the design.
73
+ The rule is one sentence: transaction date decides membership, settlement date decides
74
+ reconciliation, and neither ever does the other's job.
75
+
76
+ A posting for which no money moved carries **no** settlement date, and the tool refuses one. It can
77
+ tell because the chart marks bank, cash and card accounts with `cash: true`. Without that flag the
78
+ refusal would be unimplementable — which is what the design draft left it as.
79
+
80
+ ## 5. Crossing between books
81
+
82
+ Give the ledger two lines that cross the books and it stores four:
83
+
84
+ ```
85
+ "toner 42.30, business expense, paid on the private card"
86
+
87
+ you give: Dr expense_supplies 42.30 [business]
88
+ Cr private_card 42.30 [private]
89
+
90
+ it stores: Dr expense_supplies 42.30 [business]
91
+ Cr owner_account 42.30 [business] ← added
92
+ Dr business_claim 42.30 [private] ← added
93
+ Cr private_card 42.30 [private]
94
+
95
+ business balances alone. private balances alone.
96
+ ```
97
+
98
+ The pair is configuration (`crossing:`), and a ledger for an entity that must account separately
99
+ sets `crossing: none` and gets a refusal instead.
100
+
101
+ **The order matters and is load-bearing**: the posting is checked for overall balance *first*, and
102
+ crossed *second*. A crossing redistributes a residue between books; it must never absorb one. If it
103
+ ran first, a posting simply wrong by ten would land as a crossing of ten and the balance invariant
104
+ would hold vacuously. (This was found by a test, not by reading.)
105
+
106
+ ## 6. The annual close
107
+
108
+ ```
109
+ annual_close(2026)
110
+
111
+ ├─ 1. post the closing entry, dated 2026-12-31
112
+ │ every income and expense balance ──▶ retained_earnings
113
+ │ (this is the ONE posting allowed into a period-closed range)
114
+
115
+ └─ 2. seal every month of the fiscal year
116
+ 2026-01 … 2026-12 ──▶ sealed, terminal
117
+ ```
118
+
119
+ Post first, seal second. Sealing first would leave the entry with nowhere to go.
120
+
121
+ **Operator decision, 2026-08-05:** the closing entry may be posted into a month that is already
122
+ period-closed, and the annual close is the only operation that may do this. In ordinary use every
123
+ month is closed before the year is, so refusing would make the annual close unreachable — the exact
124
+ defect this ordering exists to fix. The seal record captures each range's final figures, so the
125
+ change is visible rather than hidden.
126
+
127
+ Without the closing entry, year two's balance sheet is short by year one's result on the first day
128
+ of January, and the balance sheet and the profit-and-loss stop agreeing.
129
+
130
+ The profit-and-loss **excludes** closing entries. They transfer a result rather than produce one,
131
+ and counting them would make every closed year read as zero.
132
+
133
+ ## 7. Correcting an error
134
+
135
+ | When the error is found | What to do |
136
+ |---|---|
137
+ | Month still open | Edit the posting in place |
138
+ | Month closed, year open | Re-open the month, edit, close it again. The superseded closing record stays |
139
+ | Year sealed | One **new** posting in an open month, against the prior-period-adjustment account |
140
+
141
+ The sealed-year correction never touches an income or expense account, and the tool refuses one
142
+ that tries. Those balances are already inside retained earnings; restating them would drop last
143
+ year's error into this year's profit — the precise outcome the correction exists to prevent. One
144
+ side is `prior_period_adjustment` (type `equity`); the other is the balance-sheet account that was
145
+ actually misstated — the bank, a payable. No money moves, so there is no settlement date.
146
+
147
+ ## 8. Import keys
148
+
149
+ A key is the pair **(profile, reference)**, never the reference alone. Two banks both numbering
150
+ their bookings from 1 would otherwise collide and the second bank's row would be taken for the
151
+ first's.
152
+
153
+ - A re-import whose key is present and whose content **matches** → reported as already present.
154
+ - A re-import whose key is present and whose content **differs** → reported as *changed*, with both
155
+ rows, and nothing is written. A bank revising a provisional amount must not leave the stale
156
+ figure standing because the tool recognised the key and looked no further.
157
+ - A source with no reference field → keyed by batch and position, and every re-import is reported
158
+ as undeduplicable. A line dictated twice is proposed twice, on purpose.
159
+ - A discarded proposal is **kept**, which is what stops the next re-import proposing it again, and
160
+ the discard can be undone.
161
+
162
+ ## 9. Configuration is the jurisdiction
163
+
164
+ No tool's code holds an account name, a tax rate or a country's rule. Adding a country means
165
+ writing one YAML file. A household-only setup is the same file with one book, `crossing: none` and
166
+ no tax labels.
167
+
168
+ The loader has exactly one refusal, with a closed list of causes: an account removed or retyped
169
+ while postings reference it; a required named account missing or wrongly typed; a currency changed
170
+ while postings exist; an import profile naming a column it does not map. It reports every cause at
171
+ once. Renaming an account is always safe — the chart is editable in use, and a close stores the
172
+ chart it was taken against, so editing never restates a closed period.
173
+
174
+ ## 10. What is deliberately absent
175
+
176
+ - **More than one currency.** With it went conversion, rates, revaluation and every foreign
177
+ account. A foreign payment is recorded at what the account was charged; the original amount is a
178
+ note nothing parses. Multi-currency is a separate design against a ledger that already works.
179
+ - **Value-added-tax derivation.** A registered entity needs the split at posting time, because
180
+ input tax is a balance-sheet claim and the expense must be recorded net. Registration is a
181
+ redesign. Labels here are opaque: reports group by them and stop.
182
+ - **Deleting evidence,** and with it any retention setting. A tool that cannot delete cannot delete
183
+ wrongly.
184
+ - **A "cash movement" report.** Reconciliation covers the need; the scope list named a report no
185
+ tool ever produced.
186
+ - **A second ledger.** Only the addressing is built.
187
+
188
+ ## 11. Open questions, carried
189
+
190
+ 1. How opening balances are represented — an ordinary posting in a month later closed, or a record
191
+ type of their own. The spreadsheet migration makes this concrete.
192
+ 2. Whether closing-record detection should anchor each record's hash on the attestation chain.
193
+ Records carry a hash today; nothing external verifies the sequence.
194
+ 3. Whether the private book should be excluded from report output by default, so a business report
195
+ cannot carry household lines into an accountant's hands.
196
+ 4. Whether the store should keep an edit history for open-range postings. Today an open-range edit
197
+ overwrites, so the correction history exists only for months that were closed and re-opened.
198
+ 5. Whether a posting may have more than one settlement line. Reconciliation currently assumes not.
199
+ 6. Whether a ledger migrated mid-year should mark its first annual close as covering a partial
200
+ year, so a ten-month result is not read as a twelve-month one.