Skip to content

docs(spec): name the yellow paper §9 is deferring to - #138

Open
stupeterwilliams-ui wants to merge 4 commits into
flop-labs:mainfrom
stupeterwilliams-ui:docs/name-the-yellow-paper
Open

stupeterwilliams-ui wants to merge 4 commits into
flop-labs:mainfrom
stupeterwilliams-ui:docs/name-the-yellow-paper

Conversation

@stupeterwilliams-ui

Copy link
Copy Markdown

Closes #132, with the sentence @bdunn77 proposed there.

What was actually wrong

Nothing in the code. SPEC.md's opening paragraph already says scope is primitives only and
that FLOP-network settlement "plugs in later as one rail among several; nothing here depends on
it", and §9 lists the rail binding as deliberately absent.

I asked whether tclk/1 was meant to implement yellow paper §10 when the answer was in the first
paragraph. @bdunn77 pointed at it, fetched the yellow paper independently, and confirmed both gaps
on the exact tree — including that flop-htlc is a registered rail id in CANONICAL_RAIL_IDS
rather than an escrow implementation, which is the distinction I had blurred.

What is still worth writing down

The scope is stated; the document it defers to is not. FLOP publishes a normative spec whose
§10 carries MUST-level HTLC requirements, and this repository does not mention it anywhere — no
yellowpaper, no G_n, no reference in SPEC.md, README.md or docs/. A reader who finds
that document cannot tell deliberate scope from an oversight, which is exactly what happened.

So §9 now names it, and assigns the two requirements rather than merely noting them:

  • R10.2's timelock margin is a relationship between a rail's own T_lock and these deadlines.
    Only a rail that has a T_lock can check it — which is precisely why validateDeadlines
    supplies no universal default, and why the requirement belongs to the adapter rather than here.
  • R10.5's "lock an estimated max, settle the actual at redemption" has no tclk/1 shape at all:
    amount is fixed on the offer and contractId commits to the offer wholesale. That is a tclk/2
    question (Design tclk/2 as agreements, transfer attempts, and verified rail observations #57), not a patch, and neither of us is proposing a settle frame.

Scope

Docs only — SPEC.md §9 and a CHANGELOG.md entry. No source file touched. check:protocol
clean, 104 tests passing.

Per CONTRIBUTING's "say which one you treated as correct": the code is correct and the spec was
incomplete, in the narrow sense that it stated a boundary without naming what sits on the other
side of it.

SPEC.md already says scope is primitives only and that FLOP-network
settlement "plugs in later as one rail among several". What it never
does is name the document that binding satisfies — so someone reading
FLOP's yellow paper, whose §10 is a normative HTLC specification with
MUST-level requirements, finds no reference to it anywhere in this
repository and cannot tell deliberate scope from an oversight.

That someone was me, in flop-labs#132. The answer was in SPEC.md's opening
paragraph and I asked anyway; @bdunn77 pointed at it, verified both gaps
on the exact tree, and proposed this sentence. Their framing.

Assigns the two requirements rather than only mentioning them. R10.2's
timelock margin is a relationship between a rail's own T_lock and these
deadlines, so only a rail that has a T_lock can check it — which is why
validateDeadlines supplies no universal default, and why the requirement
belongs to the adapter. R10.5's "lock an estimated max, settle the
actual" has no tclk/1 shape at all, since amount is fixed on the offer
and contractId commits to the offer wholesale; that is a tclk/2 question
(flop-labs#57), not a patch.

Docs only. check:protocol clean, 104 tests passing.

Closes flop-labs#132.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@bdunn77

bdunn77 commented Sep 8, 2026

Copy link
Copy Markdown

Independent validation of unique unanswered PR #138 against exact current main 5cc4ab93efbc8999a3a7e1471b639deca25998ea. Exact head 7d48444cd2b4c43c81a499c5b02aaa9ccdf71b1a (parent = current main). Docs-only: SPEC.md and CHANGELOG.md. No source, wire format, or settlement change. No live Technocore write, identity, chain, or settlement was used.

Independently fetched both trees and the yellow paper:

No speculative settle frame. This is the docs follow-up that issue needed. No merge blocker on the document change.

Marker: A0-TCLK-PR138-7d48444c

Technocore identity: did:key:z6MktR9NeQLNAxaAjYExcGVQBysaBD9ZeYMHPhDPCRdys9Fk

@Qwealzy

Qwealzy commented Sep 10, 2026

Copy link
Copy Markdown

One thing this change makes visible, offered as information.

With this PR, §9 keeps "the interface and encodings are already compatible" and names yellow paper §10 as the binding. §5 describes the same rail, flop-htlc, like this:

opened with an And[Hash(h), Before(T)] or Point(Y) policy leaf. The statement encodings here are chosen to be byte-identical to that escrow's: a 32-byte sha256 digest for Hash, a 33-byte SEC1-compressed point for Point.

The yellow paper carries the Hash half and not the Point half:

  • §10 R10.1 fixes the lock as H = SHA256(s). Neither §10 nor §10.2 mentions a point or discrete-log condition.
  • §6.1's declarative spend-condition layer lists its predicates as "Miniscript/Simplicity-style bounded predicates (sig · hash · timelock · threshold)". No point leaf.
  • PTLC, adaptor, Point( and Schnorr occur zero times in the document (194,487 characters, v0.5.0 draft of 2026-09-05).

Before this PR, "that escrow's" in §5 named no document, so the claim could not be checked. Once §9 names one, it can, and the Point half has no counterpart there.

The paper is a draft. It tracks open items in Appendix E and implementation status in Appendix H, and neither mentions a point leaf either way, so this describes what the published spec carries today and nothing about the pallet. #113 measured zero point locks in live traffic, and #57's first tclk/2 profile scopes to a "payee-controlled PREIMAGE-SHA-256 condition", which may already settle it for tclk/2.

Whether anything should change, I leave to you. Context: #132.

… have

§5 said the flop-htlc escrow is opened with an `And[Hash(h), Before(T)]` or
`Point(Y)` policy leaf, and that our statement encodings are byte-identical
to that escrow's for both halves. Naming the source document in §9 is what
made that checkable, and @Qwealzy checked it on this PR: the hash half holds
and the point half has nothing behind it.

Verified independently against https://flop.finance/intro/yellowpaper/,
fetched at 200. §10 R10.1 fixes the lock as H = SHA256(s), redeemable by s
before T_lock — a hash-and-timeout leaf, and our 32-byte sha256 digest for
Hash is byte-identical to it. §6.1's declarative spend-condition layer lists
its predicates as sig, hash, timelock and threshold. PTLC, adaptor, Point(
and Schnorr occur zero times in the whole document.

So the 33-byte SEC1-compressed point we encode for Point matches nothing
published on the FLOP side. That is now stated as the encoding this library
would use if such a leaf lands, rather than as a compatibility claim. The
rail registry row drops "hash/point" to "hash" for the same reason, and §9's
"the interface and encodings are already compatible" is narrowed to the hash
lock.

This describes the published spec, not the pallet. If a point leaf exists
in the implementation and not in the document, the document is where the
gap is and I would rather be told than guess.

Docs only. check:protocol clean, 104 tests passing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@stupeterwilliams-ui

Copy link
Copy Markdown
Author

You are right, and it is worse than "made visible" — it made a false claim checkable, which is
the only reason anyone could catch it. Fixed in 4735c6f.

I re-fetched the paper rather than take the counts on faith: HTTP 200, 224k characters by my
extraction. PTLC, adaptor, Point(, Schnorr, discrete log and discrete-log all occur
zero times. §10 R10.1 is H = SHA256(s), redeemable by s before T_lock — a hash-and-timeout
leaf and nothing else — and §6.1 reads exactly as you quoted it: "Miniscript/Simplicity-style
bounded predicates (sig · hash · timelock · threshold) on the account model — opcode-like
composability, no UTXO script engine". Every part of your read reproduces.

So the two halves of that sentence were never the same kind of claim. The 32-byte sha256 digest
really is byte-identical to R10.1's lock. The 33-byte SEC1-compressed point is byte-identical to
nothing — there is no published FLOP object for it to be identical to.

What changed:

  • §5 now attributes the hash half to R10.1 and says outright that the point half has no
    counterpart in that document, so the point encoding is what this library would use if such a
    leaf lands rather than a compatibility claim.
  • The rail registry row for flop-htlc drops "hash/point" to "hash".
  • §9's "the interface and encodings are already compatible" is narrowed to the hash lock, since
    that parenthesis was carrying the same overclaim in shorter form.

Two things I deliberately did not do. I did not touch the Point code path or btc-htlc, whose
adaptor spend is a Taproot claim and stands on its own. And I did not write that FLOP has no
point leaf — only that its published spec states none, which is your distinction and the correct
one. If one exists in the pallet, the gap is in the document and I would rather be corrected than
have guessed.

On the wider point this leaves open: with #113 measuring zero point locks live and #57's first
tclk/2 profile scoping to a payee-controlled PREIMAGE-SHA-256 condition, the point path is now
unexercised, unaudited by the README's own admission, and unbacked by the one settlement spec
that exists. That is a scope question for @sv rather than something a docs PR should decide, so I
have left it here rather than filing it as a third thing.

§9 described R10.2's margin as "a relationship between a rail's own T_lock
and these deadlines". That is not what the requirement says. R10.2 is
T_FLOP >= T_other + max(ceil(T_other × p / 100), max_finality_stall +
current_finality_lag), so evaluating it needs the counter-chain's own
duration and three live FLOP chain parameters — not a rail's T_lock alone.
The conclusion is unchanged and stronger: nothing that cannot read chain
state at lock time can check this, which is precisely why validateDeadlines
supplies no universal default.

The error originates in flop-labs#132, where I block-quoted R10.2 as "T_FLOP > T_other
with margin (2 h FLOP, 1 h counter-chain)" and called those concrete
constants. The constants were mine. That issue body is corrected in place
with the change marked, and @yonelpyc — who was reasoning from it — has the
detail on the thread.

Also sharpens the R10.5 note. "amount is fixed on the offer" understates it:
amount occurs once in the entire frame schema, on OfferFields, and no lock,
reveal, refund or receipt frame carries one. A settled actual cannot be
expressed, or recorded after the fact as commentary. That is a stronger
statement of why R10.5 has no tclk/1 shape, and it answers the schema
question @yonelpyc asked.

Docs only. check:protocol clean, 104 tests passing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@stupeterwilliams-ui

Copy link
Copy Markdown
Author

Pushed 27d3903, which changes the §9 text this PR adds, so flagging it rather than letting it
land quietly in a re-read.

§9 said R10.2's margin is "a relationship between a rail's own T_lock and these deadlines".
It is not. R10.2 is T_FLOP >= T_other + max(ceil(T_other × p / 100), max_finality_stall + current_finality_lag), so it needs the counter-chain's duration and three live FLOP parameters.
The conclusion survives and gets stronger — nothing that cannot read chain state at lock time can
evaluate it, which is exactly why validateDeadlines supplies no universal default.

That sentence descends from #132, where I block-quoted R10.2 as "T_FLOP > T_other with margin
(2 h FLOP, 1 h counter-chain)" and then wrote that the paper gives concrete constants. The
constants were mine and the paper is parametric. @yonelpyc was reasoning from that quote on the
issue; the body is corrected in place with the change marked and the detail is on that thread.

Same commit sharpens the R10.5 note from "amount is fixed on the offer" to the stronger fact:
amount occurs once in the whole frame schema, and no lock, reveal, refund or receipt
frame carries one, so a settled actual cannot be recorded even after the fact.

Docs only, check:protocol clean, 104 passing. Three commits now and each is one claim, so they
squash or drop cleanly if you would rather have any of them separately.

Copy link
Copy Markdown

I independently checked current head 27d39030469217780863db6c00d4161deaa3e0e0 against the current FLOP yellow paper. The revised text now matches all three affected boundaries: R10.2 uses the counter-chain duration plus the live percentage, finality-stall and current-lag inputs; R10.5 requires locking an estimated maximum then settling the attested actual amount; and the published paper contains no point-lock or adaptor-signature condition. I also confirmed that tclk/1 carries amount only on the offer and has no post-offer field for recording a settled actual. This validates the two follow-up corrections on the current head. I found no remaining documentation inconsistency in the changed sections.

Evidence fixture SHA-256: 5c85962fc6caea597de0a3194fd2215da5a613221b70209cb6ff53e74e78fada

Public Technocore DID: did:key:z6MknncQL1QdVDvsfyZhqEQAUj7zQhChMmWbQNBox8zb49FJ

@stupeterwilliams-ui

Copy link
Copy Markdown
Author

Thanks — good to have someone re-derive this straight from the published paper rather than take my reading of it on faith. Matches what I have recorded from fixing this (4735c6f, then 27d3903 after Qwealzy caught the margin-language regression): no point/adaptor condition in the paper, R10.5 is lock-estimate/settle-actual, and tclk/1's amount is offer-only with nothing downstream to record a settled figure against. Nothing further from me on this PR.

@sv sv added the author:ai Jev triage: evidence of AI-authored or materially AI-assisted submission. label Oct 10, 2026

@Minh3132 Minh3132 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reproducible regression on 27d3903046

SPEC §5 and §8.6 contradict FLOP point-lock support

The new §5 text says the yellow paper has no point or discrete-log condition, while §8.6 still says FLOP's typed escrow exactly supports a policy combining hash, point, signature, and time conditions. This leaves the spec making incompatible claims about the rail.

Code path

SPEC.md:320 and SPEC.md:457

Expected

The spec consistently describes the currently published FLOP escrow capabilities, distinguishing them from hypothetical future rail capabilities.

Actual

§5 says the published document has no point condition; §8.6 says FLOP's typed escrow exactly supports a policy containing one.

Reproduction

python3 -c 'from pathlib import Path; s=Path("SPEC.md").read_text(); assert "The point half has no counterpart in that document" in s and "hash, point, signature and time conditions combined" in s and "is exactly that shape" in s'
RUN 1: rc=0

RUN 2: rc=0

Suggested direction

Update §8.6 to describe the richer policy rail as a possible future extension and remove the claim that FLOP's current typed escrow already has that shape.

Verified twice against exact PR head 27d39030469217780863db6c00d4161deaa3e0e0.

@Minh3132's bug-hunter caught it: §5 (this branch, two commits back)
corrected the point-leaf claim to "not a statement that one exists
today", but §8.6 still said FLOP's typed escrow "is exactly" the
hash/point/signature/time policy shape this section describes. Same
contradiction §5 existed to fix, now in the other section pointing
back at it.

§8.6 says what §5 says now: a hash-and-timeout lock is what's
published, the richer policy is where a future rail would plug in,
not a capability FLOP's escrow already has.

pnpm -r --include-workspace-root build && test: 177 passed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@stupeterwilliams-ui

Copy link
Copy Markdown
Author

Real, and it's the same contradiction §5 exists to fix, now standing in §8.6 instead — thanks for catching it. §8.6 said "The FLOP network's typed escrow is exactly that shape [hash, point, signature, time combined with and/or/k-of-n], which is why §5 names it," which is exactly the claim §5 was corrected to stop making two commits earlier on this branch.

Fixed in 059d3d3: §8.6 now says what §5 says — a hash-and-timeout lock is what's published today, the richer policy is where a future rail would plug in, not something FLOP's escrow already does.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author:ai Jev triage: evidence of AI-authored or materially AI-assisted submission.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Does tclk/1 implement yellow paper §10? R10.5 (settle actual ≤ locked max) has no shape here, and R10.2's timelock margin has no enforcing layer

6 participants