Skip to content

feat(positions): organization positions, settlement, and the wallet they are not - #23

Merged
isaacismaelx14 merged 1 commit into
mainfrom
feat/phase-9-organization-positions
Aug 22, 2026
Merged

feat(positions): organization positions, settlement, and the wallet they are not#23
isaacismaelx14 merged 1 commit into
mainfrom
feat/phase-9-organization-positions

Conversation

@isaacismaelx14

Copy link
Copy Markdown
Member

Phase 9, both halves. The private side is in kreds-network at 312c526; nothing about how the Network computes a position is in this PR or in this repository.

What was actually missing

The domain has had all eight quantities since Phase 0, with both worked examples from the laws pinned as tests. What it did not have was any way to produce a position from real data: debts and receivables had nowhere to live, and nothing ever moved an entry out of the settlement window. withdrawable was permanently zero for every earner.

Liabilities get their own tables

Not columns on accounts. 19: Invariants keeps them outside the supply equation because "adding either to the equation would double-count the KRED that funds them", and a liability in a separate table cannot be summed into a balance by accident. Amendment A01 exists because the first model recorded debt as a negative balance.

Constraints, not conventions:

Constraint Why
settled_value <= gross_value a claim settled past its value owes its holder money
outstanding <= principal a repayment with the wrong sign would deepen the debt
claimant_account_id <> obligor_account_id Law XXXIV forbids the two-account version of this

Settlement

The mechanism Law VII rests on, which did not exist. 11 on why the length was chosen:

"A day of delay is invisible to an honest user checking their balance tomorrow. It is fatal to an attack whose entire economics depend on extracting value before the liability lands."

The window is an argument, never a default: the published normal window and the risk-adjusted ones come from different places and one of those is deliberately not published. A window of zero throws.

Two sweeps racing settle each entry exactly once. Mutation-tested by removing the PENDING guard on the UPDATE.

Protocol v3

OfficialPosition had a flat balance and a flat withdrawable with no context attached. That is Law V's shortcut already taken, at the one place it matters most: the boundary Core actually reads. It now carries one global wallet and a list of organization standings, and there is no top-level balance, so Core cannot ask what somebody holds without saying in which context. Both repositories pin the shape independently with @ts-expect-error.

netPosition is the only figure on this protocol that carries a sign. A balance never does.

Policy

packages/policy now reads settlement, accounting, receivables and debtTypes, with the laws pinned as literals rather than parsed as data. A policy file permitting negative balances, or letting an underwater position withdraw a single kredbit, fails to load instead of being obeyed. The snapshot is untouched and its checksum still matches.

Two things mutation testing found

The negative-balance test matched on the word "negative", and kredbits refuses a negative with a message containing the same word, so it passed with the Law XXI check deleted. Two guards, one message, one of them untested.

The settlement window is written twice, as SQL and as domain. Breaking either alone changed nothing, so the comment claiming a division of labour was wrong. It now says what is true, and there is a boundary test at exactly one window, which is the only input that can tell <= on a cutoff from >= on a due time.

…t runs

Phase 9A. The domain had all eight quantities since Phase 0, including
both worked examples from the laws. What it did not have was any way to
produce one from real data: two of the five inputs had nowhere to live,
and nothing ever moved an entry out of the settlement window.

Debts and receivables get their own tables, deliberately not columns on
accounts. 19 keeps them outside the supply equation because "adding
either to the equation would double-count the KRED that funds them", and
a liability in a separate table cannot be summed into a balance by
accident. Amendment A01 exists because the first model recorded debt as
a negative balance.

The constraints are in the database rather than in a convention. A
receivable cannot settle beyond its own value, a debt cannot owe more
than was financed, and a claimant cannot be their own obligor: Law XXXIV
forbids the two-account version of that, this forbids the no-account
version.

Settlement is the mechanism Law VII rests on and it did not exist. The
window arrives as an argument, never a default, because the published
normal window and the risk-adjusted ones come from different places and
one of those is deliberately not published. A window of zero throws: that
is not a short window, it is the absence of one.

The window is written twice, as an indexed SQL cutoff and as the domain's
`due`. Mutation testing showed that breaking either alone changes
nothing, so the comment claiming a division of labour was wrong and now
says what is true. What the redundancy buys is a rule reachable without a
database, plus a boundary test: an entry created exactly one window ago
must settle, which is the only input that can tell `<=` on a cutoff from
`>=` on a due time.

Two sweeps racing settle each entry once, because the UPDATE still
requires PENDING. Without that both claim the same rows and both report
success.

The policy package now reads settlement, accounting, receivables and
debtTypes, with the laws pinned as literals rather than parsed as data.
A policy file permitting negative balances, or letting an underwater
position withdraw a single kredbit, fails to load instead of being
obeyed. The snapshot is untouched and its checksum still matches.

Also found by mutation: the negative-balance test matched on the word
"negative", and `kredbits` refuses a negative value with a message
containing the same word, so it passed with the check deleted. Two
guards, one message, one of them untested.
@isaacismaelx14
isaacismaelx14 merged commit 238fe9e into main Aug 22, 2026
1 check passed
@isaacismaelx14
isaacismaelx14 deleted the feat/phase-9-organization-positions branch August 22, 2026 17:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant