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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +88 -0
- data/lib/kairos_mcp/version.rb +1 -1
- data/templates/skillsets/account_manager/config/accounts.yml +115 -0
- data/templates/skillsets/account_manager/knowledge/account_manager_guide/account_manager_guide.md +200 -0
- data/templates/skillsets/account_manager/lib/account_manager/config.rb +259 -0
- data/templates/skillsets/account_manager/lib/account_manager/importer.rb +122 -0
- data/templates/skillsets/account_manager/lib/account_manager/money.rb +64 -0
- data/templates/skillsets/account_manager/lib/account_manager/report.rb +247 -0
- data/templates/skillsets/account_manager/lib/account_manager/store.rb +718 -0
- data/templates/skillsets/account_manager/lib/account_manager/tool_helpers.rb +54 -0
- data/templates/skillsets/account_manager/lib/account_manager.rb +30 -0
- data/templates/skillsets/account_manager/plugin/SKILL.md +96 -0
- data/templates/skillsets/account_manager/plugin/agents/bookkeeper.md +81 -0
- data/templates/skillsets/account_manager/skillset.json +33 -0
- data/templates/skillsets/account_manager/test/test_account_manager.rb +1319 -0
- data/templates/skillsets/account_manager/tools/am_close.rb +80 -0
- data/templates/skillsets/account_manager/tools/am_entry.rb +144 -0
- data/templates/skillsets/account_manager/tools/am_import.rb +70 -0
- data/templates/skillsets/account_manager/tools/am_query.rb +96 -0
- data/templates/skillsets/account_manager/tools/am_receipt.rb +69 -0
- data/templates/skillsets/account_manager/tools/am_report.rb +85 -0
- data/templates/skillsets/multi_llm_review/lib/multi_llm_review/consensus.rb +65 -5
- data/templates/skillsets/multi_llm_review/lib/multi_llm_review/prompt_builder.rb +35 -1
- data/templates/skillsets/multi_llm_review/lib/multi_llm_review/review_serializer.rb +101 -2
- data/templates/skillsets/multi_llm_review/lib/multi_llm_review/sanitizer.rb +137 -8
- data/templates/skillsets/multi_llm_review/skillset.json +2 -2
- data/templates/skillsets/multi_llm_review/test/test_evidence_fidelity.rb +484 -0
- data/templates/skillsets/multi_llm_review/tools/multi_llm_review.rb +52 -5
- data/templates/skillsets/multi_llm_review/tools/multi_llm_review_collect.rb +81 -11
- metadata +21 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d38191ff3e513822d6183bf4fee4c92e497148978eda3bda064a01b81d0bf95b
|
|
4
|
+
data.tar.gz: 97999aa9377a086ea092237ad53605fec24b9e01c9691e7c92c24b6329bd565e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
data/lib/kairos_mcp/version.rb
CHANGED
|
@@ -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
|
data/templates/skillsets/account_manager/knowledge/account_manager_guide/account_manager_guide.md
ADDED
|
@@ -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.
|