← Back to blog
September 9, 2026Colm Byrne
Evidence boundary. Older posts may discuss prototype designs, patent claims, or planned integrations. The demonstrated v1 release is ccf-core/ccf-agent v1.0.1: hard min-gate coupling, QAC trust updates, and runtime certificates. Gate C exercised the computed runtime on Seed-class ARM hardware with driver-fed input. Unless a post cites a specific run, do not read it as proof of live sensors, mBot2 behaviour, Cognitum store validation, or production deployment.

The rover that had two names for the same three metres of concrete

A real moment

The Blackwater is up again at Fermoy and the county flood depot has been open since four in the morning. Aoife Nolan is on duty. Somewhere out on the embankment there is a small inspection rover walking the line of pump housings, checking each one and reporting what it finds. It has been doing that job for two winters.

The rover keeps a running tally of how well it does at each place it goes. Pump house three has two tallies, not one. The first is for daylight visits. There have been 66 of them and they average 0.65 on how cleanly the visit went, on a scale where one means nothing went wrong at all. The second tally is for visits after dark under the depot floodlights. There have been 54 of those and they average 0.55.

The rover kept them apart for a reason that made sense at the time. Until this month it had no way to tell the two lighting conditions apart except by the clock, and the clock is a poor guide to daylight in December. Two different tallies was the honest answer to a distinction it could not reliably make.

Last week a new light sensor went on. The rover can now see the difference directly, and what it sees is that there is no difference to see. Same walkway, same handrail, same three metres of concrete where the water sits. Daylight and floodlight were the same situation the whole time.

So it has 120 visits' worth of experience at pump house three, filed under two labels that were never really two things. Tonight it has to decide what to do about that, and the decision changes how carefully it moves when the water is coming up.

Why this matters

Anything that earns trust through experience has to file that experience under something. A person does it too. You trust a colleague more in one kind of meeting than another, and if you are honest about it, the boundary between the two kinds is fuzzier than your confidence suggests.

For a robot the labels are explicit. They are context keys, and they are guesses about how the world divides up. Guesses get revised. A sensor gets added. A measurement gets finer. An anonymous label for "someone at the door" becomes a label for a specific person once the robot can tell people apart. Every one of those revisions raises the same question: what happens to the trust that was earned under the old labels?

Two easy answers are available and both are bad. Throw the old state away and start again, which discards real work. Or carry it forward with no record of where it came from, which means nobody can check it later. Neither is acceptable if the trust in question is going to decide how much force a machine applies near a person. Provenance work in agent systems has been converging on the second half of this for a while, keeping lineage metadata on every write. The part that is specific to a trust score is what the join is allowed to do to the number itself.

There is a second problem underneath the first, and it is the one nobody expects. Trust scores in these systems usually have two parts: how well things went, and how much experience there is. The second part is what stops a robot acting confidently after three good interactions. It is a floor, and it rises with experience. When you join two tallies, the experience counts add. The floor goes up. The robot ends up with more benefit of the doubt than either tally bought on its own, without a single new interaction having happened.

What CCF does about it

CCF's answer to the first problem is to add the evidence, not the scores.

The rover does not take the better of 0.65 and 0.55. It does not average them either. It counts every visit from both labels, 66 plus 54, which is 120. It adds up the outcome of every visit from both labels, which comes to 72.4682. Then it divides. The answer is 0.6039.

We checked that number against a rover that never split the labels at all, one that saw the same 120 visits and filed them all under one name. It holds 0.603901363726. The joined tally holds 0.603901363726. They agree to the last digit that a double-precision number carries. That is not a coincidence and it is not a tuning result. It falls out of adding evidence rather than averaging scores, and we assert it as a test rather than only observing it.

Alongside the joined tally the rover writes down where it came from: which two labels, how many visits each contributed, and what each one held before the join. That record is what makes the join undoable. If the new light sensor turns out to be wrong and the two situations really were different, the record puts both tallies back exactly as they were. We measured that too: zero error on both counts and both values.

A join without that record is not reversible in any useful sense. We measured what you lose. Split a joined tally using only the visit counts, which is the obvious way to do it, and you get both counts back perfectly and both values wrong, by 0.0355 and 0.0445 on our test pair. Each child comes out holding the joined average instead of its own history. The gap grows with how far apart the two labels were to begin with.

The second problem, the rising floor, does not have as clean an answer, and we are not going to pretend it does.

The numbers

The headline result is that the evidence-adding join is exact. Its error against a ground truth is zero. The three obvious alternatives are not close. Averaging the two scores quietly discards 45.5 percent of the evidence behind them. Keeping only the better score invents 7.6 percent of evidence that never happened, and lands 0.046 above the truth. Taking the worse of the two throws away 59.2 percent.

On the rover, the join costs it something. Its step size for the next hour drops by 0.0175 on our scale, because a fair reading of both tallies is less flattering than its daytime record alone was. That is the direction we want. A join that makes a robot bolder should be viewed with suspicion.

The floor result is the uncomfortable one. We swept 1600 pairs of tallies and asked, for each, whether joining them produced more benefit of the doubt than the two tallies held between them. It did for 1184 of them, 74 percent. The average excess was 0.052 and the largest was 0.140.

Then there is a third finding we did not go looking for. The floor has a ceiling. Once a tally has enough visits behind it, the floor stops rising. We re-ran the whole comparison with 4000 visits instead of 120, past that ceiling, and all four ways of joining produced exactly the same result at the gate. Identical. Their underlying numbers still differed by up to 0.05 and their evidence handling still differed by 60 percent, and none of it reached the robot's behaviour. Which way you join only matters while the robot is still learning the place.

What this doesn't solve

The rising floor is a real property of the system and we have measured its size but not how often it fires. In a deployed robot a join only happens when the two labels clear a similarity test first, and our test held that gate open. So the 74 percent figure describes joins that were allowed to happen. It says nothing about how many are allowed.

The ceiling result cuts both ways. You can read it as protection, since a well-worn context is stable no matter how you join it. You can also read it as concealment, since a bad join in a well-worn context leaves no trace at the gate. We do not have a principled answer for which reading is right.

Our ground truth is synthetic. It is exact because we generated the visits ourselves, and no real robot has anything like it. What carries over is the ranking of the four methods and the rough size of the errors, not a promise about any particular deployment.

And we modelled no adversary. There is a whole literature on gaming reputation systems by choosing when to split and when to merge an identity. Nothing here does that, and a system that has to survive it needs more than this.

For the curious, the math

Each context tally holds three things: an accumulated value c between zero and one, an interaction count n, and an earned floor f computed from n as min(cap, n * k). With the filed defaults k = 0.005 and cap = 0.70, a tally with 66 visits carries a floor of 0.33 and one with 54 carries 0.27. The gate sees max(c, f).

Evidence mass is m = n * c. Because the tally updates as an incremental mean of per-visit outcome quality, m is exactly the sum of the qualities it has seen. The join sets n = n_A + n_B and c = (m_A + m_B) / n. That identity is the whole reason the exactness result holds.

The floor is then recomputed from the joined count. Sixty-six visits gives 0.33 and 54 gives 0.27, but 120 gives 0.60, which is more than either. That is the superadditivity. No implementation is at fault. A floor that is a function of experience volume will rise when a join sums volume.

Measuring how much a join inflates trust turned out to need care. Our first attempt compared the joined floor to the joined value, and that measure blames the join for conditions it inherited. A tally with 200 visits and a value of 0.54 is already sitting under its own floor before anything is joined to it. The measure we settled on compares the joined result against the count-weighted average of what the two tallies were each worth before the join. That question has a defensible answer, and it is the one the numbers above report.

The gate itself is unchanged and comes straight from the CCF core crate: g = min(instant coherence, context coherence) and alpha = rho(g) over a band from 0.02 to 0.40. We did not re-derive any of it.

Where this fits

This is one night's work on one piece of CCF: the operations that keep earned trust honest when the labels it was filed under change. It sits inside US provisional 64/039,655, Extension 6, filed in April 2026.

Full detail, the complete measured tables, the failure modes and the code are in the research write-up and the Rust crate, both linked below. The crate runs. The numbers in this post are its actual output, not estimates.

  • Research write-up and gist: linked from the CCF repository
  • Rust crate: crates/research/accumulator-merge-split-lineage/
  • Decision record: ADR-0011
  • Published core crate: https://crates.io/crates/ccf-core
  • Company: https://floutlabs.com
  • Project: https://github.com/Hulupeep/ccf

License and contact

BSL 1.1, converting to Apache 2.0 in 2032. Contact via floutlabs.com.