Finding the Exponent: Binary Construction in Mercury’s Square Roots and Logarithms

How knowing where to begin—and knowing how to refine—turns continuous mathematics into computational algorithms.

Mathematics gives us familiar relationships:

x2 = a   and   bx = a

But a computer must answer a more concrete question: How can we construct the unknown value from a finite sequence of operations?

Mercury, an arbitrary-precision floating-point arithmetic library, offers an interesting perspective. Its square-root and logarithm algorithms approach their answers through successive binary contributions. Each candidate is tested against the value being sought, and the construction becomes progressively finer.

The algorithms have something important in common. But their differences reveal why some inverse operations are easier to begin than others.

The Advantage of Knowing the First Bit

Consider the square root:

x = √a

If we know the leading binary position of a, we can determine the leading binary position of its positive square root.

For example:

26 ≤ 100 < 27

Since 26 = 64 and 28 = 256, the square root falls between 23 and 24:

23 ≤ √100 < 24

The answer begins at binary position 3.

This gives an algorithm a useful starting point. It can begin with the contribution 23, then examine successively smaller powers of two.

Given a current approximation m, propose:

q = m + 2k

If q2 ≤ a, the contribution fits and can be retained. Otherwise, it is rejected.

The result is constructed one binary place at a time.

Notice what made the beginning convenient: squaring doubles the exponent of a power of two. The magnitude of the input therefore tells us where to begin constructing the root, even though the remaining bits still have to be tested.

But What If the Unknown Is the Exponent?

Now consider:

bx = a

The logarithm asks for the missing exponent:

x = logb(a)

For real logarithms, the target a must be positive and the base b must be positive and different from 1.

Unlike square-root extraction, we cannot generally read the leading position of x directly from the leading position of a. We must establish an appropriate exponent scale relative to the base.

Mercury’s logarithm implementation approaches this constructively. Repeated squaring or square rooting helps locate an initial power contribution. Once that scale is established, the algorithm can begin refining the unknown exponent.

For a positive exponent, think of candidate contributions in descending binary positions:

x ≈ bk2k + bk-12k-1 + bk-22k-2 + …

Here each binary choice bj is either 0 or 1. Not every term is retained. Each candidate contribution is tested according to whether its corresponding power moves toward or beyond the target. For bases below 1, the comparisons reverse direction, but the construction principle remains.

When refinement reaches fractional binary positions, the mathematical relationship becomes particularly elegant.

Why Square Roots Return to the Story

Consider a nonnegative exponent with fractional binary contributions:

x = n + b1/2 + b2/4 + b3/8 + …

where each bi is either zero or one.

Exponentiation gives:

ax = an × (a1/2)b1 × (a1/4)b2 × (a1/8)b3 × …

But:

a1/2 = √a

and:

a1/4 = √(√a)

Each additional square root corresponds to a finer fractional binary contribution.

This is the connection that makes Mercury’s constructive logarithm algorithm so interesting: square roots are not merely related to logarithms mathematically; they can supply the successive power contributions used to recover the exponent.

Mercury’s optimized logarithm implementation also maintains an accumulated power, avoiding the need to recompute the entire exponentiation for each candidate contribution. Its slower counterpart provides a useful contrast by recomputing candidate powers more directly.

Why Binary?

Binary is not required by the continuity of logarithms. A real logarithm is continuous on its positive domain, but continuity alone does not dictate an algorithm.

Binary refinement is attractive because it transforms a search into successive two-way decisions.

Each step resolves another binary position. Each fractional exponent step can be generated through square rooting. And each candidate can be evaluated against the target.

There is a useful sense in which two is the natural minimal integer subdivision factor: it creates the smallest possible nontrivial choice.

It is not, however, a universal optimum for numerical computation. Other algorithms can compute logarithms through different approximations and convergence methods.

Mercury’s value as an educational implementation lies partly in how clearly its binary approach exposes the construction.

Where Continuous Mathematics Meets Finite Precision

Mathematically, successive refinement can continue indefinitely. A computer cannot.

Mercury represents a value using a configurable number of 32-bit mantissa words. Each additional word supplies 32 more bits of stored precision.

Eventually, a proposed correction becomes too small to change the representable result. The continuous mathematical process has encountered the finite resolution of its numerical representation.

This distinction matters. A converged finite-precision calculation is not the same thing as an exact mathematical limit. But a well-designed numerical algorithm can approach that limit systematically, with precision chosen by the caller.

The Larger Lesson

Square roots and logarithms are inverse operations of different relationships, yet both demonstrate a powerful approach to numerical computation:

Find the scale, propose a contribution, test it, and refine.

For square roots, the initial scale follows naturally from the leading binary position of the input. For logarithms, the exponent scale must first be established relative to the base and target.

From there, binary refinement turns the search into a sequence of increasingly fine decisions.

That is one of Mercury’s most interesting educational qualities. The implementation invites us to examine not only the answer, but how the answer is constructed.

The mathematics is continuous. The algorithm proceeds through discrete decisions. Precision determines how far the construction can go.

And the source code lets us follow those decisions all the way down.

Continue Exploring Mercury

Compare the algorithms directly in the Mercury C implementation, follow the canonical Mercury reference, or explore the Mercury learning hub.

Update: The SamePersistence Seam Did Not Replicate

The first SamePersistence record remained unusual even under a full algorithmic null, so I reran the same experiment from scratch before changing anything else.

The second record did not reproduce the effect. Its frozen metrics landed comfortably inside the algorithmic-null population, including Retained Anticipation at the 21.8th percentile and average anticipation near the center of the null.

That means the first result was genuinely unusual, but it is not currently repeatable evidence of a persistent SamePersistence advantage.

This is why replication came before adding a new source or tuning the strategy.

To see the truth, the hard questions need to be asked — especially when the answer is inconvenient.

github.com/johnwaynecornell/TruthInTheFlip

TruthInTheFlip on GitHub, log updates

TruthInTheFlip: The Seam Survived

SamePersistence Under a Full Algorithmic Null

The last Truth in the Flip entry asked a deliberately uncomfortable question:

What if 50% is the causal ceiling?

That question came from a pattern that had become increasingly difficult to ignore.

Across mature tracker records, rich statistical structure was easy to find. Excursions formed. Settlements followed. Local persistence appeared. Some derived measures looked surprisingly favorable.

But structure is not the same thing as foreknowledge.

A fair source can wander.

A statistic can develop shape.

A strategy can look locally convincing.

None of those facts alone means the next unseen event has become predictable.

That led to a working distinction:

Detectable structure need not imply anticipatable structure.

The next experiment was designed to make that distinction harder.

A Simpler Strategy

Among the mature experiments was a deliberately simple anticipation strategy called SamePersistence.

It does not inspect Heads and Tails directly.

It watches whether successive outcomes have been the Same or Different.

Over a completed 10-billion-transition window:

SamePercentage >= 50%
    → anticipate Same

SamePercentage < 50%
    → anticipate Different

Equivalently:

SamePercentage > DiffPercentage
    → Same

SamePercentage < DiffPercentage
    → Different

The strategy therefore asks a very small question:

Does the transition type that dominated the recent window tend to persist into the next observation period?

The rule was already fixed.

No threshold was chosen from the result.

No alternate window was selected afterward.

The First Null

The mature SamePersistence.NET1.tkr record was first compared with a 10,000-trial conditional null.

That null preserved the exact historical predictor decisions while replacing their outcomes with fair independent outcomes.

Several statistics separated.

Most notably:

RetainedAnticipation
    observed percentile: 99.7%

AvgMeanA
    observed percentile: 99.6%

AvgEndA
    observed percentile: 99.6%

The result was interesting, but incomplete.

There was an obvious objection.

The null had kept the historical strategy schedule fixed.

What if that schedule itself encoded something special about the observed history?

That required a stronger test.

Rebuilding the Strategy Inside the Null

The next null did not preserve the historical SamePersistence decisions.

Instead, every synthetic trial received a fresh fair history.

SamePersistence then ran again from the beginning and generated a new decision path of its own.

Conceptually:

fresh fair source
    ↓
SamePersistence
    ↓
fresh rolling 10B state
    ↓
fresh Same/Different decisions
    ↓
same experiment horizon
    ↓
same report machinery

The original tracker supplied experiment geometry — cadence, horizon, and observation boundaries — but not its outcomes or predictor choices.

Each of the 10,000 null trials therefore represented a fresh run of the algorithm against a fair source.

This is the comparison I wanted before saying more publicly.

The Result

The seam survived.

The observed record’s positions under the conditional and algorithmic nulls were almost unchanged:

Metric                         Conditional   Algorithmic

EdgeExcursionScore                98.0%         98.1%
EdgeSettlementScore               98.0%         97.9%
EdgePersistenceIndex              87.9%         88.4%
RetainedAnticipation              99.7%         99.7%
SettlementAdjustedAnticipation    91.6%         91.9%
AvgMeanA                          99.6%         99.5%
AvgEndA                           99.6%         99.5%

For RetainedAnticipation:

observed:
    50+3.04026e-04%

algorithmic null median:
    50+2.66312e-04%

percentile:
    99.7%

sample-corrected upper tail:
    0.0036

The ordinary anticipation averages were also displaced upward:

AvgMeanA
    percentile: 99.5%
    upper tail: 0.0056

AvgEndA
    percentile: 99.5%
    upper tail: 0.0053

The important point is not any single small tail value.

The important point is that allowing SamePersistence to regenerate its own state and decisions did not make the original separation disappear.

What This Does — and Does Not — Say

This is not proof that a fair random source has been defeated.

It is not proof of a universal anticipation advantage.

And it does not invalidate the 50% causal benchmark.

Under an iid fair source, 50% remains the expected success rate of a causal predictor.

What changed is narrower:

The mature SamePersistence record is unusually favorable relative to 10,000 fresh fair histories processed through the SamePersistence algorithm itself.

The earlier result therefore cannot be dismissed simply as an artifact of freezing the historical decision schedule.

That is a stronger statement than I was prepared to make after the conditional null.

It is also where the experiment becomes more interesting.

Complexity Did Not Win

There is another curious part of the story.

Two more elaborate persistence experiments — ClassicMetaGuess-conditioned BSP2 and AntiMetaGuess-conditioned BSP2 — fell comfortably inside their corresponding null populations.

The simpler source-only rule did not.

That does not make SamePersistence “better.”

It changes the question.

The interesting object may not be complicated strategy behavior at all.

It may be the transition stream itself:

Same
Different
Same
Same
Different
...

Which leads to the next question:

Is there persistent forward structure in the Same/Different transition stream itself?

Re-Rolling the Dice

The next experiment is intentionally uncreative.

There will be no new threshold.

No nearby window will be searched.

No inversion will be tried.

No stronger-looking rule will be designed from the opened record.

Instead, the same experiment will simply be run again.

A fresh tracker will use:

SamePersistence
10B strategy window
same runner geometry
same target horizon
same analysis
same algorithmic null

The purpose is replication, not improvement.

If the first record was an unusual draw, a fresh independent record is exactly where that should become visible.

If a second record develops the same kind of separation under the same frozen procedure, the question becomes harder again.

That is where Truth in the Flip should go next.

The point is not to protect a result.The point is to give the result every reasonable opportunity to disappear.

And if it does not disappear, we keep asking why.

To see the truth the hard questions need to be asked.

github.com/johnwaynecornell/TruthInTheFlip

TruthInTheFlip on GitHub, log updates

TruthInTheFlip: Structure Is Not Foreknowledge

The 50% Ceiling Hypothesis

Truth in the Flip began with a simple question: can something meaningful be found in the relationship between random events without pretending that randomness has disappeared?

Over time, that question became more precise.

The experiments have repeatedly shown structure in the path: excursions, persistence-like regions, reversals, settlement behavior, relationships between Same/Different outcomes, and patterns that remain visible even when Heads/Tails itself stays close to balanced.

But the newest experiments have forced a harder question.

What if structure can be observed without providing information about the next unseen event?

That possibility deserves to be stated plainly.

For an independent fair binary source, a prediction made only from information available before the next event has an expected success rate of 50%.

No amount of transformation of the past can create information that is not present in it.

If GtG_t is a guess constructed from everything known before event tt, and XtX_t is an independent fair event, then:

P(Gt=Xt∣past)=12P(G_t=X_t\mid\text{past})=\frac12

The predictor may be complicated. It may adapt. It may contain memory, windows, state, symbolic rules, or layers of other predictors.

Under that null, its expected correctness remains 50%.

That does
not
mean its observed path must sit quietly at 50%.

Finite records wander.

They can produce impressive local excursions. They can form apparent regimes. A predictor can spend long intervals above or below 50%. A retrospective analysis can identify those regions clearly.

What matters is whether the information was available
before
the events occurred.

That distinction has become increasingly important in the recent Truth in the Flip experiments.

BetSamePersistence2

BetSamePersistence2
was designed to separate two layers.

An inner anticipation strategy makes Same/Different decisions. The outer persistence layer then observes the historical success of those inner Same bets and uses that history to make its own decision.

The first mature experiment used
ClassicMetaGuess
as the inner strategy.

Its mature anticipation path was remarkably close to 50%, despite substantial local excursion and settlement geometry.

A second experiment was then designated using
AntiMetaGuess, deliberately reversing the orientation of the inner strategy.

The result was not the simple inversion I expected.

At the 100B reporting scale, the AntiMetaGuess experiment produced:

avgMeanA  = 50-6.06317e-06%
avgEndA   = 50-4.92866e-06%

Edge Excursion Score  = +0.370296
Edge Settlement Score = -0.902124

The anticipation path remained almost perfectly centered even though the local geometry remained pronounced.

At the finer 10B scale, 889 complete segments told a similar story:

avgMeanA  = 50-5.28014e-06%
avgEndA   = 50-5.58175e-06%

Edge Excursion Score  = +0.527340
Edge Settlement Score = -0.815270

Approximately half the anticipation path remained above 50 and half below it.

The reversal of the inner strategy therefore did not simply reverse the outer outcome.

That is important.

It suggests that the geometry being observed may not be a conventional directional prediction signal.

Excursion Is Not Settlement

One pattern has appeared often enough to deserve its own distinction.

A process may move into a region that looks strongly favorable and still fail to settle there.

The segment reports explicitly separate those ideas.

An
excursion
asks how far a path managed to travel.

A
settlement
asks where it finally remained.

Those are not the same measurement.

The AntiMetaGuess experiment makes the difference vivid. At one scale, over 30% of 100B segments reached a best TrueZ of at least 1.96, while only about 27% finished nonnegative.

A path can therefore contain substantial local structure without leaving a durable directional displacement.

That observation may turn out to be more important than any single Z score.

A Working Null

This leads to a new working null for Truth in the Flip:

The causal upper limit of anticipation may be 50%, even when substantial structure is visible retrospectively in the path.

This is not being presented as proven.

A finite collection of experiments cannot prove a universal ceiling.

But the hypothesis now explains enough of the observations that it deserves to become explicit rather than remaining an assumption in the background.

Under this interpretation, an anticipator can reveal something real about the organization of the historical record without gaining foreknowledge of the next event.

That would mean:

detectable structure is not necessarily anticipatable structure.

And perhaps more simply:

structure is not foreknowledge.

Why This Is Not a Negative Result

If the hypothesis survives serious testing, it would not mean that the project found nothing.

Quite the opposite.

It would identify an important boundary.

Statistical structure can be visible.

Regimes can appear.

Excursions can be measured.

Relationships between representations can be real.

But none of those observations automatically imply usable information about an independent future event.

The distinction between
description
and
anticipation
may itself be part of the truth being measured.

That is exactly the kind of boundary Truth in the Flip was built to examine.

What Comes Next

The next phase will stop asking which new strategy can be made to rise above 50%.

Instead, the project will test the 50% ceiling hypothesis directly.

The cumulative anticipation result has a simple null: if a causal predictor is acting on an independent fair binary source, each prediction is correct with probability one half.

The more complicated report statistics — excursion, settlement, retained anticipation, settlement-adjusted anticipation, and related path geometry — require their own null distributions because they are nonlinear measurements of the path.

The plan is therefore to freeze the existing methodology and compare these statistics against synthetic null records processed through the same analytical pipeline.

No search for a more favorable window is required.

No new strategy is required first.

The question is now simpler and harder:

Can a causally frozen anticipation process demonstrate durable information beyond 50%, or are we observing structure that remains fundamentally non-predictive?

Whatever the answer is, it belongs in the record.

That is the point of calling the project
Truth in the Flip.

github.com/johnwaynecornell/TruthInTheFlip

TruthInTheFlip on GitHub, log updates

When Two Percentages Cancel: Hidden Direction in Same and Heads

A binary stream can be viewed in at least two natural ways. We can count its values—Heads and Tails—or we can count the relation between consecutive values—Same and Different. These views appear to describe different aspects of the stream.

But a simple subtraction reveals that they overlap in a surprisingly precise way:

SamePercentage - HeadsPercentage

This expression does not merely compare sameness with a preference for Heads. One entire class of transitions cancels out, leaving a directional measurement of what happened after Tails.

The Four Transitions

Every counted transition belongs to one of four classes:

HH  Head followed by Head
HT  Head followed by Tail
TH  Tail followed by Head
TT  Tail followed by Tail

Same transitions are:

Same = HH + TT

Transitions ending in Heads are:

Heads = HH + TH

Subtracting the second from the first gives:

Same - Heads
= (HH + TT) - (HH + TH)
= TT - TH

The HH contribution disappears completely.

SamePercentage - HeadsPercentage measures whether a preceding Tail was followed more often by another Tail or by a Head.

Its interpretation is direct:

  • A positive value means TT exceeded TH: Tails showed persistence.
  • A negative value means TH exceeded TT: Tails showed reversal.
  • A value near zero means neither direction dominated.

A subtraction between two broad percentages has secretly isolated one directional half of the transition table.

The Mirror Measurement

The corresponding Heads-side expression is:

SamePercentage - TailsPercentage

Here:

Same - Tails
= (HH + TT) - (HT + TT)
= HH - HT

This time TT cancels. What remains measures whether a preceding Head was followed more often by another Head or by a Tail.

We can provisionally name the pair:

  • Tail Continuation Balance: Same - Heads = TT - TH
  • Head Continuation Balance: Same - Tails = HH - HT

These are raw directional balances. They preserve both the direction of the effect and the amount of the stream that contributed to it.

The Pair Reconstructs the Familiar Geometry

Let:

D_T = Same - Heads
D_H = Same - Tails

Adding them gives:

D_T + D_H
= 2 × SamePercentage - 100
= SamePercentage - DiffPercentage

Their sum is the overall balance between persistence and alternation.

Subtracting them gives:

D_T - D_H
= TailsPercentage - HeadsPercentage

Their difference is the ordinary value imbalance, viewed from the opposite direction.

The two directional measurements therefore form a small coordinate system:

  • Their sum describes Same versus Different.
  • Their difference describes Tails versus Heads.

This is more than a numerical coincidence. It shows that the value-space and relation-space descriptions of a binary stream are algebraically intertwined. The directional transition balances sit between them.

Why ClassicMetaGuess Is a Natural Probe

TruthInTheFlip does not only record Heads and Tails. Its central experiments anticipate the relation between flips.

ClassicMetaGuess observes whether the most recent transition was Same or Different and anticipates the opposite relation next:

Same      → anticipate Different
Different → anticipate Same

Its opposite, AntiMetaGuess, anticipates continuation in the relation stream:

Same      → anticipate Same
Different → anticipate Different

These two strategies are nearly ideal instruments for this subject because neither gives Heads or Tails a privileged role. If every Head in a stream were renamed Tail and every Tail renamed Head, its Same/Different relations would remain unchanged, and both strategies would make the same relational choices.

ClassicMetaGuess probes alternation in the relation stream. AntiMetaGuess probes persistence in that stream. They are complementary views of whether Same tends to follow Different and whether a relation tends to repeat itself.

The new directional metrics ask a different but adjacent question:

How is the observed Same/Different balance distributed across transitions beginning with Heads and transitions beginning with Tails?

The strategy and the metric should therefore not be collapsed into one idea. The anticipation strategy is an active rule that selects a relation for the next flip. The directional balance is a descriptive property reconstructed from the outcomes. One acts; the other measures.

Their relationship is valuable precisely because they remain distinct. A relation-symmetric strategy can be compared with source measurements that reveal whether its apparent behavior was carried equally by both sides of the binary alphabet.

Exploring Quant.tkr with TruthInTheFlip Farm

The archived Quant.tkr record gives us a concrete source for exploring these identities. A rolling window keeps the measurement local while absTotal preserves the position in the full experiment.

The Tail Continuation Balance can be emitted with:

offset#SamePercentage,negate#HeadsPercentage

The Head Continuation Balance is:

offset#SamePercentage,negate#TailsPercentage

A Farm command for both is:

csv tracker window by_total 100B file "Quant.tkr" absTotal SamePercentage HeadsPercentage TailsPercentage offset#SamePercentage,negate#HeadsPercentage offset#SamePercentage,negate#TailsPercentage

The overall Same/Different balance reconstructed from the pair is:

scale#offset50#SamePercentage,2

That produces:

2 × (SamePercentage - 50)
= SamePercentage - DiffPercentage

A broader export can place the reconstructed geometry beside the anticipation record:

csv tracker window by_total 100B file "Quant.tkr" absTotal AnticipatedPercentage ZScore SamePercentage HeadsPercentage offset#SamePercentage,negate#HeadsPercentage offset#SamePercentage,negate#TailsPercentage scale#offset50#SamePercentage,2

This does not claim that a contemporaneous source balance caused the anticipation result. It puts the two trajectories in a common record so their shape, settlement and possible relationships can be examined.

A Standardized Directional Score

The same cancellation can be expressed through the existing Z-scores. Because ZScoreSame and ZScoreHeads use the same sample total and the same 50 percent reference:

ZScoreSame - ZScoreHeads

is proportional to TT - TH. However, simply subtracting two Z-scores does not automatically produce another correctly scaled Z-score. They are derived from the same transitions and are therefore correlated.

Under an independent fair-source model, a naturally scaled Tail-directional score is:

(ZScoreSame - ZScoreHeads) / sqrt(2)

The corresponding Farm expression is:

scale#offset#ZScoreSame,negate#ZScoreHeads,0.7071067811865476

The Heads-side mirror is:

scale#offset#ZScoreSame,negate#ZScoreTails,0.7071067811865476

These scores make directional behavior more comparable across sample sizes. They should still be introduced with care: their interpretation depends on the fair independent null and on the tracker’s counting boundaries.

The Boundary Quirk

The raw identities are exact because SamePercentage, HeadsPercentage and TailsPercentage are calculated over the same counted observations.

A conditional question requires an additional step:

P(T after T) - P(H after T)

The raw Tail Continuation Balance can be written as:

P(previous T) × [P(T after T) - P(H after T)]

Dividing by the proportion of preceding Tails would remove the weighting. However, the tracker directly exposes the distribution of current Heads and Tails, not a separate count of the prior values participating in the recorded transitions.

Those distributions can differ at the two endpoints of a finite interval. At billions of flips the numerical difference is vanishingly small, but it is still a conceptual distinction. The raw balance is exact; a conditional version using TailsPercentage as its denominator is an extremely close finite-window approximation.

Relating the Source to Strategy Selection

TruthInTheFlip also records how often a strategy selected Same and how often that choice succeeded. This permits a second family of comparisons.

The strategy’s Same-selection posture is:

BetSamePercentage - SamePercentage

In Farm form:

offset#BetSamePercentage,negate#SamePercentage

This asks whether the strategy selected Same more often than Same actually occurred. It describes the strategy’s posture, not its accuracy.

A more performance-oriented quantity is Same Selection Lift:

BetSameWinRate - SamePercentage

In Farm form:

offset#BetSameWinRate,negate#SamePercentage

A positive value says that Same occurred more frequently among the conditions where the strategy selected Same than it did across the window as a whole. The Different-side mirror is:

offset#BetDiffWinRate,negate#DiffPercentage

These measurements become especially relevant to strategies such as BetSamePersistence2. That experiment uses an independent inner anticipation record to decide whether the next outer window should favor Same or Different. Selection Lift can help distinguish merely choosing the locally common side from identifying conditions where that choice performed better than the window’s general baseline.

What the Subtraction Is Saying

The original expression now has several compatible readings:

SamePercentage - HeadsPercentage
= TT - TH
= weighted Tail-conditioned persistence
= one directional component of Same versus Different

Its greatest value may be conceptual. Heads/Tails and Same/Different are often treated as separate summaries. Yet when their percentages are placed in the same algebra, they reveal the directional transitions hidden underneath.

ClassicMetaGuess and AntiMetaGuess approach the stream from relation-space without preferring either value. The new balances approach it from the transition table and recover the contribution of each starting value. Together they provide a layered view:

  1. The source produces Heads and Tails.
  2. Consecutive values produce Same and Different.
  3. An anticipation strategy acts on that relation stream.
  4. Directional balances reveal where the observed relational structure was carried.

Nothing new has been inserted into the record. The information was already present. The subtraction simply gives it a name and a place from which it can be seen.

github.com/johnwaynecornell/TruthInTheFlip

ClipFlow: When a Fluent CLI Meets Cross-Platform Clipboard Reality

1. The Illusion of Simplicity

Command-line utilities are at their best when they read like plain English sentences. Consider these operations:

ClipFlow copy text string "Hello World"
ClipFlow paste text console
ClipFlow copy image file screenshot.png
ls | ClipFlow copy files console
ClipFlow paste files directory ./restore

Each invocation expresses an unmistakable intent. You name the operation (copy or paste), the semantic data type (text, html, image, files), and the I/O endpoint (string, console, file, directory). There are no cryptic single-letter flag soups, no positional ambiguity, and no exposed platform plumbing.

Yet underneath that tranquil command line lies one of the messiest, most fragmented subsystems in modern desktop computing: the system clipboard.

To a shell script or a developer, a clipboard feels like a temporary global variable—a shared key-value store in the sky where you put bytes in and take bytes out. In reality, the clipboard is not a storage bucket at all. On Linux X11, it is an asynchronous inter-client negotiation protocol mediated by window properties and atom identifiers. On Wayland, it is an isolated compositor-controlled pipe constrained by surface focus. On Windows, it is an OLE/COM data object system governed by memory handles, global allocators, single-threaded apartments (STA), and proprietary framing envelopes.

Building ClipFlow was an exercise in bridging these two worlds: creating an expressive, fluent CLI on the outside while engineering a robust normalization and persistence layer underneath to survive the chaotic reality of operating system clipboards.


2. Designing a Fluent CLI: Grammar via Types

Most command-line parsers fall into one of two traps. Either they force developers to write massive imperative argument-parsing loops full of switch statements, or they rely on rigid declarative option schemas that struggle to express natural verb-noun phrasing.

ClipFlow takes a different approach by leveraging FluentCommandLine, a reflection-driven CLI framework. Instead of defining a static syntax tree by hand, the grammar is constructed by registering modular C# types whose static methods return strongly typed commands and endpoint binders.

In ClipFlow, the entry module wires together the command vocabulary:

public class ClipFlow_Fluent
{
    public static void FluentModuleInitialize(FluentEnvironment env)
    {
        env.AddModule<ClipType>();
        env.AddModule<ClipEndpoint>();
    }

    [FluentMethod]
    [KV_FA(FluentAttribute.Help, "set clipboard content from an endpoint")]
    public static ClipCommand copy(ClipType type, ClipEndpoint endpoint)
    {
        return new ClipDelegateCommand(ctx => ClipUtilityWindow.Copy(ctx, type, endpoint));
    }

    [FluentMethod]
    [KV_FA(FluentAttribute.Help, "apply clipboard content to an endpoint")]
    public static ClipCommand paste(ClipType type, ClipEndpoint endpoint)
    {
        return new ClipDelegateCommand(ctx => ClipUtilityWindow.Paste(ctx, type, endpoint));
    }

    [FluentMethod]
    [KV_FA(FluentAttribute.Help, "show topic information")]
    public static ClipCommand show(ShowTopic topic) => topic;
}

Notice what is happening here:

  1. The copy and paste methods do not take arbitrary string arrays. They require an instance of ClipType and an instance of ClipEndpoint.
  2. ClipType and ClipEndpoint are themselves fluent modules that expose method definitions like text(), html(), image(), files(), file(path), console(), directory(path), and stringVal(value).
  3. The parser incrementally evaluates the token stream against registered return types and parameter signatures.

When a user executes:

ClipFlow copy text file notes.txt

FluentCommandLine matches the verb copy, looks ahead to satisfy the ClipType parameter (finding ClipType.text()), and then satisfies the ClipEndpoint parameter by invoking ClipEndpoint.file("notes.txt").

Because grammar rules are tied directly to method signatures and return types, invalid combinations fail before execution even begins. More importantly, extending the CLI with a new clipboard type or endpoint requires zero changes to the core dispatch loop—you simply add a new typed method.


3. The Architectural Split: ClipType vs. ClipEndpoint

Early in the design, it became clear that coupling format conversion to I/O destinations would lead to an unmaintainable $M \times N$ explosion of code paths. If every clipboard format had to know how to read and write to files, standard input, standard output, strings, and directory trees, the system would collapse under duplicate validation and edge cases.

To avoid this, ClipFlow enforces a strict separation of concerns across three distinct layers:

graph TD
    subgraph UI & Storage Layer
        Endpoint[ClipEndpoint: console / file / string / directory]
    end

    subgraph Semantic Domain Layer
        Identity[Semantic Identity: string / SKImage / List of Paths]
        Type[ClipType: text / html / image / files]
    end

    subgraph Native Platform Layer
        CC[CrystalCatalyst DataInterchange]
        OS[OS Clipboard: Windows OLE / X11 / Wayland]
    end

    Endpoint <-->|Read / Write| Identity
    Identity <-->|Advertise / Provide / Receive| Type
    Type <-->|Format Negotiation| CC
    CC <-->|Platform Protocol| OS

The Separation Rule

ClipType owns clipboard semantics.
ClipEndpoint owns external locations and presentation.
CrystalCatalyst owns platform interchange.

How Data Moves Through the System

Copy Pipeline

  1. Endpoint Ingestion: The ClipEndpoint reads raw external data (from a file path, console stream, or argument string) and populates the in-memory Semantic Identity on the ClipType (for example, reading a PNG file into a SkiaSharp SKImage, or reading stdin lines into a list of normalized strings).
  2. Format Advertisement: ClipType.Advertise() registers supported native MIME types/formats with CrystalCatalyst.DataInterchange (e.g., text/plain, image/png, image/bmp, text/file-uri).
  3. Lazy Provisioning: When the operating system requests data for an advertised format, ClipType.Provide() converts the Semantic Identity into the requested raw byte stream on demand.

Paste Pipeline

  1. Format Enumeration: When pasting, CrystalCatalyst queries the active clipboard provider for all currently available native formats.
  2. Format Selection: ClipType.Select() iterates through the advertised formats and matches the highest-priority format known to that type.
  3. Payload Reception: ClipType.Receive() ingests the raw native byte buffer, strips platform-specific envelopes or encodings, and populates the clean Semantic Identity.
  4. Endpoint Output: The ClipEndpoint consumes the Semantic Identity and writes it to disk, emits it to stdout, or merges it into a directory.

Because endpoints only interact with the high-level Semantic Identity, a file endpoint does not know whether an image came from a Windows DIB, an X11 PNG selection, or a Wayland data source. It simply receives an SKImage and encodes it to disk.


4. Platform Realities: What Lies Beneath

The clean domain model above is only possible because CrystalCatalystLibrary and ClipFlow.Format absorb the massive discrepancies between OS clipboard implementations. To appreciate why this abstraction is necessary, let’s examine what happens at the platform level.

Linux X11: Selections, Atoms, and the Persistence Problem

Under X11, the clipboard is not a shared memory segment. Instead, it is governed by the ICCCM selection mechanism:

  • When an application copies data, it asserts ownership of the CLIPBOARD selection atom on an X11 window.
  • The data remains in the copying application’s process memory.
  • When another application wants to paste, it sends a SelectionRequest event to the owner window asking for a specific target format (such as UTF8_STRING, image/png, or TARGETS).
  • The owner converts the data, sets a window property on the requester, and responds with a SelectionNotify event.

This architecture creates a critical problem for command-line tools: when a CLI process copies data and immediately exits, its window is destroyed, and the clipboard data vanishes instantly.

To solve this, ClipFlow integrates with the X11 CLIPBOARD_MANAGER protocol via CrystalCatalyst. Before exiting, ClipFlow advertises SAVE_TARGETS to the system clipboard manager (e.g., xfce4-clipman, klipper, or mutter), transfers ownership of the data payloads to the manager daemon, and waits for acknowledgment before terminating.

Linux Wayland: Security Isolation and wl-clipboard

Wayland intentionally eliminates global window hierarchies and background selection snooping. Under standard Wayland protocols, a client cannot read or write to the clipboard unless it has an active, focused graphical surface.

For a headless or short-lived CLI utility, this presents a severe hurdle. When running in pure Wayland environments where X11 clipboard managers are absent, ClipFlow detects the compositor session and routes persistent operations through Wayland clipboard data-offer mechanisms and wl-copy/wl-paste IPC bridges.

Windows: OLE DataObjects and STA Apartments

On Windows, clipboard data interchange is built on COM and OLE IDataObject. While Windows handles persistence automatically by caching clipboard handles in the OS session, interacting with it requires strict adherence to Win32 rules:

  • Clipboard operations must run on a thread initialized as a Single-Threaded Apartment ([STAThread]).
  • Custom formats require dynamic atom registration via RegisterClipboardFormatW.
  • File lists require packing paths into a binary DROPFILES (CF_HDROP) structure with double-null terminators and UTF-16 encoding.

Format Aliasing

Different platforms and applications use different names for the exact same conceptual data:

  • Plain text may appear as text/plain, UTF8_STRING, STRING, or TEXT.
  • HTML may appear as text/html, HTML, HTML_TEXT, or CF_HTML.
  • Images may appear as image/png, image/bmp, image/x-bmp, or CF_DIBV5.

ClipFlow handles this by maintaining prioritized format headers for each ClipType, negotiating the richest format available during paste and advertising standard cross-platform equivalents during copy.


5. Case Studies in Semantic Normalization

Platform interchange is not just about format names; it is about data payloads. Raw platform payloads are often wrapped in metadata or encoded in non-standard representations.

Case Study 1: The Windows CF_HTML Envelope

When copying HTML on Windows, applications do not put raw <h1>Hello</h1> strings onto the clipboard. Instead, the Win32 standard mandates a CF_HTML envelope that wraps the snippet in byte-offset metadata:

Version:0.9
StartHTML:0000000071
EndHTML:0000000170
StartFragment:0000000140
EndFragment:0000000160
<html><body>
<!--StartFragment--><h1>Hello World</h1><!--EndFragment-->
</body></html>

If a CLI tool blindly copies this payload to a file on Linux or displays it in the console, the user gets header garbage instead of HTML.

In ClipFlow, ClipType.Html implements robust unwrapping:

public static string UnwrapCfHtml(string html)
{
    if (string.IsNullOrEmpty(html)) return string.Empty;
    if (!html.StartsWith("Version:", StringComparison.OrdinalIgnoreCase))
        return html;

    int startFrag = FindOffset(html, "StartFragment:");
    int endFrag = FindOffset(html, "EndFragment:");

    if (startFrag >= 0 && endFrag > startFrag)
    {
        byte[] utf8Bytes = Encoding.UTF8.GetBytes(html);
        if (startFrag < utf8Bytes.Length && endFrag <= utf8Bytes.Length)
        {
            return Encoding.UTF8.GetString(utf8Bytes, startFrag, endFrag - startFrag);
        }
    }

    // Fallback to comment markers if offset calculation fails
    const string startMarker = "<!--StartFragment-->";
    const string endMarker = "<!--EndFragment-->";
    int sPos = html.IndexOf(startMarker, StringComparison.OrdinalIgnoreCase);
    int ePos = html.IndexOf(endMarker, StringComparison.OrdinalIgnoreCase);
    if (sPos >= 0 && ePos > sPos)
    {
        return html.Substring(sPos + startMarker.Length, ePos - (sPos + startMarker.Length));
    }

    return html;
}

Notice the byte-oriented slicing: because CF_HTML header offsets specify byte positions rather than character positions, computing offsets directly on multi-byte UTF-8 character strings would cause truncation bugs on non-ASCII characters. Normalizing this at the ClipType boundary guarantees that every downstream endpoint receives a pure, clean HTML fragment.

Case Study 2: File Lists and Path Normalization

File list interchange is another area where platforms diverge wildly:

  • Linux X11/Wayland applications interchange files using text/uri-list with file:///path/to/file URI formatting.
  • Windows uses CF_HDROP containing raw local paths like C:\Users\John\file.txt.
  • Console users frequently pipe relative paths: ls | ClipFlow copy files console.

To ensure complete interoperability, ClipFlow defines a fundamental invariant:

$$\text{ClipType.Files.Identity} = \text{Normalized Absolute Local Filesystem Paths}$$

When paths enter the system (via stdin, a file list, or clipboard URIs), NormalizePathOrUri processes each entry:

  1. Strips URI schemes (file://, file://localhost/).
  2. Performs URL percent-decoding (%20 $\rightarrow$ space).
  3. Translates Windows drive URI schemes (file:///C:/... $\rightarrow$ C:\...).
  4. Resolves relative paths against the current working directory to absolute filesystem paths.
  5. Verifies that paths exist before allowing them onto the clipboard, preventing clipboard pollution with broken references.

When copying an entire directory tree (ClipFlow copy files directory ./src), ClipEndpoint.Directory expands the paths, and when pasting into a destination (ClipFlow paste files directory ./target), it executes merge-oriented recursion:

source directory + destination file      -> replace destination file with directory
source file + destination directory      -> replace destination directory with file
source directory + destination directory  -> recursively merge contents

This transforms the clipboard from a basic text buffer into an effective, scriptable bulk-transfer pipeline.


6. The Smoke-Testing Epiphany: Unit Tests Are Not Enough

One of the most valuable engineering lessons from the ClipFlow project was the limitation of standard in-process unit testing.

During early development, we built an extensive test suite in ClipFlow.Tests. We tested format serialization, URI parsing, CF_HTML unwrapping, image decoding, and endpoint dispatch. All unit tests passed with flying colors.

Yet, when we ran the compiled CLI in a real desktop environment, clipboard copy commands intermittently failed to persist data to other applications.

The cause was immediately apparent: in-process unit tests run within a single long-lived process. When a test copies data to an in-memory or mock clipboard and immediately pastes it back in the same test runner, it never exercises process termination, window destruction, X11 manager handoffs, or OS IPC lifecycles.

The Behavioral Smoke Contract

To guarantee true clipboard reliability, we created ClipFlow.Smoke, an automated black-box test harness built on one core rule:

┌────────────────────────────────────────┐
│ Process 1: ClipFlow copy text string   │
└───────────────────┬────────────────────┘
                    │
           (Process 1 Terminates)
                    │
┌───────────────────┴────────────────────┐
│ Process 2: ClipFlow paste text file    │
└───────────────────┬────────────────────┘
                    │
           (Process 2 Terminates)
                    │
┌───────────────────┴────────────────────┐
│ Verify disk output equals original data│
└────────────────────────────────────────┘

The smoke harness executes the compiled binary across two completely independent operating system processes. Only if Process 2 can successfully retrieve and decode the payload produced by Process 1 is the test considered passing.

The smoke suite covers 13 end-to-end scenarios:

  • Multi-line Unicode strings with Asian characters and emojis.
  • File-to-console streaming and stdin pipe ingestion.
  • HTML fragment preservation.
  • SkiaSharp image round-tripping with pixel-for-pixel decoded equivalence.
  • Wildcard directory expansion and recursive merge restoration.
  • Relative path normalization and negative validation (invalid paths failing cleanly with non-zero exit codes).

Building ClipFlow.Smoke immediately caught subtle cross-platform regressions that unit tests were blind to—including timing races during X11 selection loss and Windows carriage-return discrepancies in piped text streams.


7. Observability: Turning Protocol Debris into Diagnostic Control

During early development, debugging asynchronous X11 atom transfers and Windows message pumps required heavy diagnostic logging. Native C++ files were littered with std::cerr traces:

std::cerr << "SelectionRequest event received for target: " << target_name << "\n";
std::cerr << "Clipboard_X11: Acquired CLIPBOARD ownership\n";

While indispensable for debugging native IPC, this created a major issue for a CLI tool: piping commands in shell scripts (ClipFlow paste text console | grep foo) was corrupted by noisy stderr protocol chatter.

The naive solution would have been to delete all std::cerr statements once the feature worked. But deleting diagnostic logging creates technical debt—the next time a platform-specific clipboard bug appears on Wayland or Windows 11, developers are forced to re-add print statements from scratch.

The Solution: Application-Level Diagnostic Routing

Instead of eliminating diagnostics, we built an application-level callback seam into CrystalCatalystLibrary:

// Native ABI (opaque for generator compatibility)
_EXPORT_ void Application_SetDiagnosticsCallback(P_INSTANCE(void) callback);
_EXPORT_ void Application_DiagnosticMessage(utf8_string_struct message);

In C++, diagnostic messages are routed through a central helper:

void Application_DiagnosticMessage(utf8_string_struct message)
{
    if (TheApplication && TheApplication->on_diagnostic_message)
    {
        TheApplication->on_diagnostic_message(message);
    }
    else
    {
        std::cerr << message.to_string() << "\n";
    }
}

Critical failures (such as display allocation errors or GL context failures) remain unconditionally on std::cerr. But all protocol and selection traces flow through Application_DiagnosticMessage.

On the managed side, CrystalCatalystLibrary.net exposes a clean, thread-safe API:

public static partial class Application
{
    [ThreadStatic]
    private static NativeDiagnosticCallback? _nativeDiagnosticCallback;

    public static void SetDiagnosticsCallback(Action<string>? callback)
    {
        if (callback == null)
        {
            _nativeDiagnosticCallback = null;
            Imports.Application_SetDiagnosticsCallback(IntPtr.Zero);
            return;
        }

        _nativeDiagnosticCallback = (ref utf8_string_struct msg) => callback(msg.ToString());
        Imports.Application_SetDiagnosticsCallback(
            Marshal.GetFunctionPointerForDelegate(_nativeDiagnosticCallback));
    }
}

In ClipFlow, this plumbing surfaces through a clean -diag flag:

# Standard usage is completely quiet
ClipFlow copy text string "Hello"

# Pass -diag to inspect real-time native protocol negotiation
ClipFlow -diag paste text console
DIAG: Handling clipboard selection request
DIAG: Chosen format: text/plain
DIAG: Clipboard paste format text/plain
Hello

By retaining thread-static delegate lifetimes and supporting nullable callbacks, the native engine remains fully observable when needed without polluting standard terminal workflows.


8. Architectural Takeaways

Building ClipFlow reinforced several core architectural principles that apply to any system bridging high-level interfaces with complex OS primitives:

  1. Domain Models Must Precede Platform Integrations: When you design your CLI surface around domain abstractions (ClipType, ClipEndpoint, Semantic Identity) rather than platform mechanics, your user interface remains stable regardless of how many OS quirks you have to patch underneath.
  2. Normalize at the Ingestion Seam: Never let platform-specific envelopes (like CF_HTML headers or file:// percent-encoded URIs) leak into core business logic. Parse and normalize payloads immediately upon entry.
  3. Out-of-Process Tests for Out-of-Process Contracts: Unit tests are necessary for logic, but systems that rely on OS persistence and IPC lifecycles must be verified by multi-process black-box tests.
  4. Treat Observability as an Architectural Feature: Don’t throw away debugging logs when cleaning up a codebase. Wrap them in a lightweight, thread-safe routing callback and give the user or application control over when they appear.

With these boundaries in place, the resulting tool delivers on its original promise: a fluent, readable command line that makes clipboard operations feel simple again.

git | ClipFlow copy files console

ClipFlowPack/README.md on GitHub

CrystalCatalystLibrary on GitHub

JWCEssentials on GitHub

Truth in the Flip: A Forward Rule Reaches Prospective Validation

TruthInTheFlip has spent months examining extremely small statistical structures across enormous random sequences.

A recent series of experiments has now reached a more concrete question: can information available in the present be turned into a causal Same/Different choice that performs better than chance on a future region that has not yet been observed?

A Surprisingly Simple Rule

The strongest development-side result is not a complicated predictor.

It is persistence.

The current BetSame edge is used to train a simple past-only linear model of the next 10B segment’s BetSame edge. The predicted sign becomes the decision:

predicted future edge >= 0  -> Same
predicted future edge <  0  -> Different

The model is retrained only from prior history as the walk-forward evaluation advances. Each decision is then scored against the next unseen 10B region.

Historical Walk-Forward Result

Across four development tracker histories, approximately 4.36 to 4.38 trillion forward-scored flips per tracker produced accumulated nominal binomial Z values near +6:

Crypto 3       +6.72
Random SD      +6.28
Quant          +6.89
Quant IDQE     +6.04

The corresponding realized accuracies are only around 50.0001%. The effect is therefore not a large percentage advantage; it is a very small directional edge accumulated over trillions of outcomes.

Two Structural Controls

Because ordinary binomial Z assumes independent trials, the experiment did not stop at those values.

The first control circularly shifted each held-out future sequence within its original fold. This preserved the sequence and much of its serial structure while breaking its exact temporal alignment with the causal decisions.

The second control preserved consecutive four-segment blocks — 40B flips of local structure at a time — while randomly permuting their larger-scale ordering.

Each control used 10,000 Monte Carlo trials. The fitted decisions were never retrained inside the controls.

Under the block-permutation control, the 95th-percentile baseline Z values were approximately:

Crypto 3       +1.35
Random SD      +2.16
Quant          +2.17
Quant IDQE     +1.57

The observed forward values remained near +6, and none of the 10,000 block-permutation trials matched the observed result on any development tracker. The earlier circular-shift control produced the same qualitative conclusion.

This does not justify treating the observed values as conventional six-sigma iid discoveries. It does show that the forward result is unusually strong relative to two null procedures designed to preserve substantial structure while breaking actual temporal alignment.

What Happened to BetSameGapTrend?

The development sequence originally focused on a causal state called BetSameGapTrend. It repeatedly showed incremental forward forecasting information beyond simple persistence.

However, when predictions were converted into final Same/Different decisions and subjected to the structural controls, its additional decision-level advantage was not comparably exceptional.

That result simplified the prospective experiment rather than weakening it.

The validation rule no longer needs the experimental state at all.

The Rule Is Frozen

The prospective rule is now:

FutureBetSameEdge ~ CurrentBetSameEdge

positive prediction -> Same
negative prediction -> Different

next horizon: 10B flips
lag: 1 segment

No threshold tuning, alternate window selection, nonlinear classifier, or post-control optimization is planned before validation.

Quant2 Has Been Waiting

While all of this analysis was being performed on the historical development trackers, a new physical Quantis QRNG record has been accumulating separately.

That tracker is Quant2.tkr.

Quant2 has not participated in metric selection, regression fitting, window selection, lag selection, thresholding, decision design, or either structural control.

At the latest checkpoint it had reached approximately:

1.8854 trillion flips
11.14 million flips/sec
1 day 23 hours wallclock

Its ordinary aggregate statistics remain close to neutral, and they are not being used to modify the frozen rule.

The historical Quant comparison horizon is approximately 8.9034 trillion flips. At the current(2026-09-02) recording rate, Quant2 is approximately 7.3 days from reaching that horizon.

What Comes Next

The historical development question is now substantially settled.

A simple causal persistence rule survived chronological walk-forward testing and two different temporal-structure controls across four existing tracker histories.

The next important result will not come from another historical optimization.

It will come from opening a record that was already being generated before the rule was frozen and asking whether the same rule survives there.

That answer is still being generated.

github.com/johnwaynecornell/TruthInTheFlip

TruthInTheFlip on GitHub, log updates

Final Countdown: Waiting for the Boring Part

Truth in the Flip is nearing the end of its current Quant_IDQE (QRNG+Extractor) tracker.

After nearly four weeks of continuous running and trillions upon trillions of flips, the tracker is now entering its final stretch. Soon(2026-08-27) the completed .tkr file will be committed to the project artifacts, where it can finally stop being a live experiment and become a fixed object of analysis.

And I am hoping for something wonderfully boring.

Not because I want the tracker to say nothing, but because an ordinary-looking long-run result may be exactly what makes this tracker useful.

The Temptation of the Checkpoint

During the run, the anticipation signal has wandered through substantial positive and negative excursions. It has crossed familiar statistical thresholds, retreated from them, crossed again, and continued moving.

The raw heads balance has followed its own path.

At any single moment, it is easy to focus on the most dramatic number on the screen. A large positive Z-score looks exciting. A reversal looks equally interesting. A threshold crossing naturally attracts attention.

But the tracker is larger than any one checkpoint.

The Tracker Becomes a Dataset

The real value begins when the run is frozen.

The new Farm tooling was built specifically so that the tracker does not have to collapse into a single final statistic.

Instead, we can ask questions about:

  • segments,
  • excursions,
  • settlement,
  • persistence,
  • anticipation structure,
  • relationships between metrics,
  • and the shape of the run through time.

That is where a boring endpoint becomes interesting.

Why Boring Can Be Valuable

Suppose the tracker ultimately settles into an ordinary-looking long-run state. That does not erase the path that produced it.

Instead, the completed tracker becomes a reference horizon.

Other trackers can then be compared against it not merely by their final Z-scores, but by the way they moved through their own histories.

We can ask:

  • Did another tracker spend more time in large excursions?
  • Did it settle differently?
  • Did anticipation persist differently?
  • Did its segment structure resemble this tracker?
  • Did apparently dramatic regions survive later settlement?
  • Were relationships between heads, tails, same, and different structurally similar?

Those questions become much more meaningful once there is a large, completed tracker produced from the ID Quantique source and preserved as an artifact.

Building the Farm Before the Harvest

One of the fortunate accidents of this run is that the analysis framework grew while the tracker was still running.

Farm now has a much richer vocabulary for asking questions of the data: processes, segments, aggregates, metric expressions, nested statistical functions, hidden metric dependencies, and extensible metric catalogs.

That means the tracker will arrive not merely as a large file waiting for a few hard-coded statistics, but as data entering an analytical environment that can be explored from many angles.

In that sense, the waiting period became useful in its own right.

We built the farm before the harvest.

The Final Countdown

So this is not really a countdown to a particular statistical result.

It is a countdown to a completed dataset.

Soon the live tracker will become a fixed artifact. The changing numbers on the screen will stop changing. The run will have a beginning, an end, and a complete history between them.

Then we can begin asking what that history actually says.

And if the final result turns out to be fantastically boring, that may be exactly what we need.

github.com/johnwaynecornell/TruthInTheFlip

Truth in the Flip: Building the Farm Before the Harvest

The current Quant_IDQE.tkr run has reached another useful horizon:

7774800000000 flips → heads: 50+1.2e-04% (Z:+0.7446)
| a: 50+1.1e-04% (Z:+0.6663)
| aHeads: 50-1.2e-05%
| aTails: 50+2.2e-04%
| aSame: 50-5.1e-05%
| aDiff: 50+2.6e-04%
| wallclock: 24.06:27:36
| fps: 3707835
| Z(1.96) in 2.09:20:31
| Z(3.00) in 6.00:23:57

That is 7.7748 trillion flips, after more than twenty-four days of computation, with the tracker still advancing at roughly 3.7 million flips per second.

The current Z-scores are not a conclusion. They are a snapshot.

That distinction matters.

One of the recurring ideas behind Truth in the Flip has been that a long-running stochastic process should be allowed to remain a process. A momentary excursion is interesting, but it is not the same thing as a settled result. A statistic can move toward significance, away from it, through it, and back again.

So the tracker continues.

But while the tracker has been running, something else has grown around it.

The analysis machinery has become a project of its own.

Building the Farm

The command-line analysis system is called TruthInTheFlip Farm.

The name started naturally enough: tracker data comes in, processes work over it, statistics are harvested from it.

But the architecture has become more interesting than a collection of reports.

The Farm is built around composition.

At a high level, a command describes three separate concerns:

source → process → output

A source identifies tracker records and applies selection or transformation.

A process determines how those records are interpreted.

An output layer projects the resulting metrics.

A simple example might look like:

csv tracker file Quant_IDQE.tkr Total ZScore AnticipatedPercentage

Conceptually, that is closer to:

csv(
    tracker(
        file("Quant_IDQE.tkr")),
    Total,
    ZScore,
    AnticipatedPercentage)

than it is to the usual command-line model of switching over a bag of unrelated options.

The command grammar is typed.

A method returning a tracker selector can be supplied anywhere another operation expects a tracker selector. A segmentation operation returns a process whose products have their own metric catalog. Another operation can consume those products.

That compositional structure has become the central idea of the Farm.

From Trackers to Segments

Individual tracker records are useful, but a long stochastic run is often more interesting when viewed as a sequence of intervals.

The Farm therefore supports segmentation.

For example:

segment

turns a tracker population into SegmentStats.

A segment can describe things such as:

  • its beginning and ending tracker records,
  • its best True Z excursion,
  • its ending True Z,
  • its mean True Z,
  • anticipation behavior,
  • underlying heads behavior,
  • and the fraction of its path spent above or below useful thresholds.

Then there is another level:

segment_agg

which operates over populations of SegmentStats and produces a SegmentAggregate.

Conceptually:

Tracker
    ↓
segment
    ↓
SegmentStats
    ↓
segment_agg
    ↓
SegmentAggregate

That hierarchy turned out to matter enormously once metric functions became composable.

A Small Metric Expression Language

Originally, CSV projection mostly meant selecting a metric name:

ZScore

or walking through a nested property:

End.AnticipatedPercentage

The . already had a clear meaning:

.    metric/property traversal

Then metric functions arrived.

The syntax uses #:

abs#EndTrueZ

or:

mean#anticipatedTails

So the basic vocabulary became:

.    metric/property traversal
#    metric function application

The next question was unavoidable.

What happens when a function needs more than one argument?

That gave us:

,    function argument separation

and suddenly expressions such as these became possible:

lerp#MinZHeads,MaxZHeads,.5
pearson#ZScoreHeads,ZScoreTails
pearson#ZScoreHeads,abs#ZScoreTails

The surprising part is that the grammar does not need parentheses.

Arity Supplies the Structure

Consider:

clamp#value,min,max

The reflected clamp method tells the parser that it takes three parameters.

That fact supplies the structure.

The parser does not need this:

clamp(value,min,max)

because the method signature already says how many expressions must be consumed.

This becomes especially interesting with nesting.

One of the stress tests used while finishing the parser was:

clamp#mean#abs#stddev_sample#AnticipatedPercentage,-1,0

And then, because trusting a parser too early is dangerous, I tried:

clamp#clamp#mean#abs#stddev_sample#AnticipatedPercentage,-1,0,-1,-.5

It worked.

The structure can be understood roughly as:

clamp
    clamp
        mean
            abs
                stddev_sample
                    AnticipatedPercentage
        -1
        0
    -1
    -.5

No parenthesis stack is needed in the text representation.

The recursive parser knows when an expression ends because the reflected method arity tells each call how many parameters it owns.

That turned out to be one of my favorite properties of the design.

Scalar and Aggregate Parameters

There is another distinction hiding inside the method signatures.

A scalar metric parameter such as:

double value

means:

evaluate this expression at the current process level.

An aggregate parameter such as:

List<double> values

means:

sample this expression from the child process population.

That gives metric functions process semantics without requiring each function to know anything about the Farm.

A scalar function such as:

abs#EndTrueZ

stays where it is.

An aggregate function such as:

mean#ZScore

moves one level into the process below it, collects the values, and then evaluates the function.

This means nested aggregates naturally descend through the process graph.

For example:

mean#mean#ZScore

can mean:

  1. collect ZScore over tracker records,
  2. calculate a mean for each segment,
  3. then collect those means across an aggregate of segments,
  4. and calculate another mean.

The syntax and the process hierarchy cooperate.

That was not originally designed as a grand expression language. It emerged from asking what the type signatures already knew.

Statistical Functions

Once the plumbing was capable of carrying functions properly, it made sense to give the Farm a useful statistical vocabulary.

The scalar side now includes operations such as:

abs
negate
square
sqrt
ln
pow
offset
offset50
scale
ratio
clamp
lerp

The aggregate side includes descriptive statistics such as:

count
sum
mean
min
max
median
variance_population
variance_sample
stddev_population
stddev_sample
rms
mean_abs
covariance_population
covariance_sample
pearson

I deliberately prefer explicit names such as:

stddev_sample

and:

stddev_population

instead of hiding the n versus n - 1 choice behind an ambiguous stddev.

The Farm is supposed to make analysis easier, not make statistical assumptions invisible.

Pearson as a Parser Test

Pearson correlation became one of the most useful tests of the new machinery.

This expression:

pearson#ZScoreHeads,ZScoreTails

requires two independent aggregate populations.

That exposed an important implementation issue: initially both parameters were accidentally drawing from the same stored series.

The symptom was wonderfully obvious.

Every Pearson coefficient was 1.

Of course it was.

The Farm had effectively been calculating:

pearson(x, x)

instead of:

pearson(x, y)

Once aggregate state became parameter-specific, the result changed immediately.

A real run produced:

mean#anticipatedTails,"pearson#ZScoreHeads,ZScoreTails"
12525048877.594,-1.000000000000002
25000093183.95,-0.9999999999999996
24999860225.76,-1.0000000000000002
24999952853.39,-1
25000013324.862,-1.0000000000000007
25000014662.32,-0.9999999999999997
24999941909.36,-1.0000000000000002

The tiny excursions outside -1 are ordinary floating-point roundoff.

The interesting part is that ZScoreHeads and ZScoreTails are behaving as essentially perfect opposites over those sampled segment populations.

That is not necessarily mysterious. Those quantities are closely related mathematically.

But as an engineering test, the result was excellent.

The Farm had successfully:

  • parsed a two-argument aggregate function,
  • sampled two separate child-process expressions,
  • kept their observations aligned,
  • invoked the reflected statistical function,
  • and projected the resulting expression as CSV.

The Expression Survives the Pipeline

There was another design decision that paid off during this work.

A metric expression should remain its own canonical name.

So this:

pearson#ZScoreHeads,ZScoreTails

should not become:

pearson_ZScoreHeads_ZScoreTails

just because CSV uses commas structurally.

Instead, the CSV writer does what CSV is supposed to do:

"pearson#ZScoreHeads,ZScoreTails"

The expression remains intact.

That matters downstream.

I tested a Pearson expression through the plotting path as well, and the formula appeared correctly in the chart.

That means the same expression can travel through:

Farm
    ↓
CSV
    ↓
Pandas
    ↓
plot

without losing its identity.

The column name is not merely an implementation artifact.

It is a compact description of what was calculated.

A Human-Readable Segment Report

Not every analysis should require CSV or Python.

The Farm also contains:

segment_report

which is a curated human-readable report over segmented tracker data.

It supports progressive report grades and can expose increasingly detailed material such as:

  • segment count,
  • Edge Excursion Score,
  • Edge Settlement Score,
  • Edge Persistence Index,
  • anticipation geometry,
  • underlying heads geometry,
  • threshold frequencies,
  • detailed per-segment rows,
  • Pearson correlation diagnostics,
  • retained anticipation,
  • settlement-adjusted anticipation,
  • standout segments,
  • and total file compute time.

Three summary quantities have become especially useful:

Edge Excursion Score
    median(best TrueZ per segment)

Edge Settlement Score
    mean(end TrueZ per segment)

Edge Persistence Index
    settlement × fraction positive

These do not replace the underlying tracker.

They provide different views of how an apparent edge behaves over time.

An excursion can be large and still fail to settle.

A positive ending average can still be supported by very few segments.

Persistence asks yet another question.

This is exactly why I wanted the Farm to preserve multiple perspectives rather than collapse a long run into one headline number.

The Farm and the Tracker

There is something satisfying about the timing of all this.

The Quant_IDQE.tkr run was not paused while the Farm was being built.

It kept moving.

At the snapshot that opened this post:

7,774,800,000,000 flips

the tracker reported:

heads Z: +0.7446
anticipation Z: +0.6663

with anticipation components including:

aHeads: 50-1.2e-05%
aTails: 50+2.2e-04%
aSame:  50-5.1e-05%
aDiff:  50+2.6e-04%

Those values are worth recording because they describe this point in the run.

They should not be mistaken for its final state.

The tracker has already demonstrated that long stochastic runs can wander substantially across different horizons.

That is part of the experiment.

Waiting Without Being Idle

When this run began, the main question was about the tracker.

By the time it ends, the analytical environment waiting for it will be considerably stronger than the one that existed at the start.

The waiting period produced:

  • a reusable Farm process layer,
  • compositional tracker selectors,
  • segmentation,
  • second-level segment aggregation,
  • a human-readable segment report,
  • reflected metric catalogs,
  • recursive metric paths,
  • scalar metric functions,
  • aggregate statistical functions,
  • multi-parameter functions,
  • numeric literals,
  • nested structural arity,
  • Pearson correlation,
  • canonical CSV expression names,
  • and a path into Pandas and plotting.

That changes what can be asked of the final tracker.

Instead of one report containing the questions I happened to anticipate beforehand, the tracker can now be interrogated compositionally.

A new metric expression can be written at the command line.

A population can be segmented differently.

A statistic can be applied at one process level or another.

A result can become CSV without adding a custom report.

And the same canonical expression can survive into downstream analysis.

Before the Harvest

The name Farm now seems more appropriate than when I first used it.

A farm is not the harvest.

It is the infrastructure that makes many harvests possible.

The long-running tracker is still out there accumulating evidence.

At this moment, it has crossed 7.77 trillion flips and is still running.

There is no need to force an ending because a statistic happens to look interesting today.

When Quant_IDQE.tkr finally reaches its intended horizon, I will preserve the completed tracker and examine it from several directions.

The Farm will be ready.

And perhaps that is the most useful development from this waiting period.

We did not merely wait for a number.

We built better ways to ask what the number means.

Documentation

The Farm has several layers of documentation:

github.com/johnwaynecornell/TruthInTheFlip

While Quant_IDQE Runs: TruthInTheFlip Farm Takes Shape

The current Quant_IDQE.tkr run is still maturing. At the time of writing, it is roughly halfway through the period I want to observe before drawing much from it.

That has created an interesting kind of development window.

Rather than continually disturbing the running experiment, I have been working on the machinery around TruthInTheFlip: how tracker data is selected, transformed, summarized, exported, inspected, and eventually plotted.

What began as a CSV utility has grown into something more general.

It is now TruthInTheFlip Farm.

From a CSV Utility to a Composable Farm

The first idea was simple: make it easier to extract useful CSV from a .tkr file.

That quickly exposed a more interesting structure.

There are really several different questions involved:

  • Where does the data come from?
  • Which part of the data do I want?
  • How should records be grouped?
  • What statistics should be calculated?
  • How should the result be presented?

Instead of combining those concerns into a growing collection of specialized commands, the Farm treats them as composable pieces.

A command can now read naturally from the outside inward.

For example:

csv tracker file "crypto3.tkr" total ZScore

means, conceptually:

file
    → tracker process
        → csv representation

Likewise, a segmented report can be expressed as:

csv segment file "crypto3.tkr" by_total 100B
    Index EndTotal MeanTrueZ EndTrueZ BestTrueZ

The pieces have distinct jobs.

file constructs a tracker source.

segment constructs a process over that source.

by_total 100B describes how segments are formed.

csv takes the resulting process and gives it an output representation.

This turned out to be a much better foundation than adding commands such as csv_segreport, csv_trackerreport, and every other combination that might eventually be useful.

The grammar composes instead of multiplying.

FluentCommandLine

A major part of this work became a reusable project of its own: FluentCommandLine.

It builds a typed command graph from ordinary functions.

Instead of parsing a traditional bag of strings and switches, each recognized function has typed arguments and a typed return value. The return value of one function can become the argument of another.

That means the command language itself reflects the software architecture.

A function returning a tracker source can be accepted wherever a tracker source is expected.

A function returning a FarmProcess can be consumed by csv.

A boundary can be passed to from or to.

The parser knows these relationships because they are real type relationships, not conventions encoded into command strings.

That also gives the system a useful self-describing property.

Help output can be generated from the same function registry the parser actually uses.

For that reason, the generated help is the bottom line for a particular build.

If static documentation ever falls out of sync with the executable, the executable’s generated help and metric listings are authoritative.

JWCFarm

The processing machinery also became general enough to deserve its own layer.

JWCFarm now contains reusable concepts such as:

  • FarmProcess
  • process lifecycle handling
  • process actions
  • metric catalogs
  • metric binding
  • metric projections

A Farm process does not need to know whether its output will become CSV, a future human-readable report, or something else.

It simply produces typed items through a lifecycle.

That separation became particularly useful once CSV was treated as a presentation adapter rather than something intrinsic to tracker or segment processing.

The same process can eventually support several representations without changing the process itself.

Selecting Ranges

The command language now supports typed boundaries as well.

For example:

from absTotal 200B

or:

from absWallclock 01:00:00

These can be composed with a source before processing.

A complete expression might look like:

csv tracker
    from absTotal 200B
    to absTotal 400B
    file "crypto3.tkr"
    absTotal AnticipatedPercentage ZScore

The distinction between navigation and measurement became important here.

A metric answers:

What is true at this record?

A boundary answers:

Where am I in the stream?

That is why absolute total, absolute wallclock, and UTC time make natural boundary coordinates, while many other perfectly valid metrics do not need to become part of the navigation language.

Windowing and Completeness

Windows introduced another subtle distinction.

A window can change the apparent local totals and statistics while the underlying tracker still has an absolute position in the full run.

That led to explicit absolute metrics such as:

absTotal
absWallclockTime
absWallclockTimeNs

It also raised the question of whether a produced record represents a complete unit.

Tracker records now default to complete, while windowing can mark completeness appropriately.

That lays the groundwork for a future whole process modifier that can discard incomplete output without contaminating the segmentation rules themselves.

The distinction matters.

A segment selector should decide how a segment is cut.

A process modifier should decide whether a produced result is accepted.

Keeping those ideas separate leaves the language room to grow without forcing the current release to grow with them.

Metrics Became a First-Class System

The metric system grew considerably during this work.

Tracker metrics now include not only the original counts and anticipation statistics, but also percentage forms, Z-scores, absolute coordinates, and Same/Different-derived statistics.

A particularly interesting addition came from examining the relationship between actual Same/Different transitions and the strategy’s Same/Different decisions.

The Tracker can now expose values such as:

same
diff
SamePercentage
DiffPercentage
ZScoreSame
ZScoreDiff

These are distinct from metrics such as ZScoreAnticipatedSame.

ZScoreSame asks how an unconditional always-guess-same baseline performed against chance.

ZScoreAnticipatedSame asks how the strategy performed specifically when it chose Same.

Those are related questions, but they are not the same question.

The Farm made that distinction easier to see because it made asking new questions cheap.

Nested Metrics

Segment output can also reach into the Tracker records it contains.

For example:

End.AnticipatedPercentage
End.SamePercentage
Z.ZScoreHeads

A segment does not need to duplicate every Tracker property as a top-level segment property.

Instead, the metric binder can follow a typed path.

This has become one of my favorite parts of the system.

A segment can expose meaningful structural anchors such as:

Begin
End
Z

and the caller can then select whichever Tracker metric is interesting at that anchor.

That keeps the segment model smaller while making the reporting surface richer.

Python Becomes a Consumer, Not a Requirement

Once the Farm can produce clean CSV on stdout, Python becomes a very natural downstream consumer.

A script can run the Farm, capture stdout, and load it directly into Pandas.

Conceptually:

result = subprocess.run(
    command,
    capture_output=True,
    text=True,
    check=True
)

df = pd.read_csv(io.StringIO(result.stdout))

From there the normal scientific Python ecosystem is available.

This has already been useful for plotting:

  • segment True-Z trajectories
  • anticipation percentage
  • Same/Different behavior
  • sign agreement
  • distributions
  • scatter plots
  • correlations

One useful lesson came from plotting percentage values near 50%.

Drawing a zero baseline made the interesting variation almost disappear because the data lived in a narrow band around 50.

The more meaningful view was either to draw a 50% reference line or subtract 50 and plot the edge directly.

That small plotting mistake actually helped clarify the semantics of the data.

This is the workflow I now expect to use repeatedly:

ask a question
    → select data with Farm
    → project metrics
    → visualize
    → quantify what looks interesting
    → promote broadly useful discoveries into metrics

In that sense, visualization is not merely the final presentation layer.

It can feed back into the metric model.

Testing the Whole Path

The Farm now has a focused automated test suite as well.

There are unit tests for areas such as:

  • Fluent environment context
  • module initialization
  • parsing
  • metric binding
  • nested metric paths
  • process lifecycle
  • abort behavior
  • CSV formatting
  • invariant numeric output

There are also integration tests that algorithmically create a real .tkr file, write several Tracker snapshots, and then run the Farm against it.

Those tests exercise the full path:

Fluent command
    → typed parsing
    → tracker boundary
    → source composition
    → real .tkr storage
    → FarmProcess
    → metric projection
    → CSV

Boundary tests verify inclusive from and to behavior over absolute totals, wallclock values, and UTC time.

At the moment, the test suite is green across the board.

That gives me much more confidence than simply knowing that a few commands work interactively.

Documentation

The Farm now has several layers of documentation:

The README provides the entry point.

The Farm guide explains the compositional language.

The Metrics guide explains what can be selected and how nested paths work.

The plotting guide shows how to take Farm output into Pandas and Matplotlib.

The executable remains self-describing, so documentation does not need to duplicate every generated metric listing forever.

Extensibility

Another architectural improvement came late in the work.

FluentCommandLine modules now have an initialization hook.

A module can register additional modules, parsers, contextual services, and other supporting infrastructure when it is installed into a FluentEnvironment.

This means advanced users can potentially extend an application without modifying the application’s own worktree.

That was an important requirement for me.

The host can provide a stable environment while modules contribute new command vocabulary and supporting behavior around it.

The mechanism is still deliberately small.

I would rather discover the next abstraction from actual need than turn the Farm into a general-purpose state machine before it has earned one.

What Comes Next

There are already obvious directions the Farm could grow.

One is a whole process modifier for accepting only complete process output.

Another is human-readable reporting.

The interesting thing is that neither appears to require breaking the current architecture.

CSV already established the pattern:

FarmProcess
    → representation

A future human-oriented command could simply provide another representation with a curated set of fields:

report tracker file "crypto3.tkr"

or:

report segment file "crypto3.tkr" by_total 100B

Unlike CSV, such a report would probably choose its fields for the user.

CSV is intentionally explicit and machine-friendly.

A human report should probably be opinionated.

That can come later.

For now, I want to keep the release boundary where it is.

Meanwhile, the Experiment Continues

All of this has been happening while Quant_IDQE.tkr continues to mature.

That is a satisfying relationship between the experiment and its tooling.

The experiment does not need to stop while I improve how I inspect it.

And the tooling does not need to know in advance exactly which questions will become interesting.

The Farm gives me a way to ask those questions compositionally as the data develops.

TruthInTheFlip began with a very simple proposition: sometimes it is useful to ask whether the next event will be the Same or Different rather than trying to predict the event directly.

The Farm reflects a similar philosophy at the software level.

Instead of trying to anticipate every future report, it provides a small set of pieces that can be composed into the report that is needed.

That feels like the right direction.

Truth in the Flip on GitHub