The Sigmoid That Gates Trust: How CCF Converts Coherence Into Behavioral Output
Effective coherence is computed. The minimum gate has done its work. The Sinkhorn-Knopp projector has redistributed trust. The robot now has a single scalar, C_eff, in the range [0.0, 1.0], representing how much the robot trusts its current situation.
Now what?
C_eff must be converted into observable behaviour. The robot has motors, LEDs, a speaker, and a speech synthesiser. Each output channel has its own range, its own units, its own safety constraints. The motor can turn 0 to 180 degrees. The LED can emit wavelengths from 380 nm (violet) to 700 nm (red). The speaker can output 0 to 85 dBA. The speech synthesiser can produce single words or full sentences.
The naive approach: map C_eff to each channel independently. Motor range = C_eff x 180. LED brightness = C_eff x 255. Volume = C_eff x 85. This creates a calibration nightmare. Every new actuator needs its own mapping function. Every deployment needs per-channel tuning. The complexity scales linearly with the number of output channels.
CCF does something different. Patent sections [0054a] and [0055d] describe a two-stage pipeline: first, C_eff is mapped to a permeability scalar P through a sigmoid function. Then P is applied multiplicatively to ALL output channels simultaneously. One function. One scalar. Every actuator scales together.
The Behavioral Envelope
The permeability P is a modulation factor in [0.0, 1.0] applied multiplicatively to every output channel:
motor_amplitude = motor_max * P
led_brightness = led_max * P
audio_volume = volume_max * P
verbal_complexity = complexity_max * P
personality_expression = expression_max * P
When P = 0.0: all channels suppressed. The robot watches but does not act. This is the ShyObserver state at minimum trust -- the robot is present but inert. Motors locked. LEDs dim. No audio output. No speech.
When P = 1.0: all channels at their configured maximum. This is the QuietlyBeloved state at full trust -- the robot moves fluidly, LEDs are warm and expressive, audio is at conversational volume, speech is natural and varied.
The beauty of this design is compression. ONE number controls the entire behavioural repertoire. A new actuator does not need a new mapping function -- it needs a maximum value, and P handles the rest. The calibration problem reduces from "tune N channels independently" to "set N maximums and tune one sigmoid."
From patent section [0054a]: the modulation factor is applied identically across all channels, preserving the relative balance between channels. If the motor maximum is 120 degrees and the LED maximum is 200 brightness units, then at P = 0.5 the motor operates at 60 degrees and the LED at 100 units. The ratio 120:200 = 60:100 = 3:5 is preserved. The robot behaves as a scaled version of its full self, not as a differently configured version.
The Permeability Function
The mapping from C_eff to P is a logistic sigmoid, from patent section [0055d]:
P(c) = 1 / (1 + exp(-k * (c - c_0)))
Two parameters:
- c_0 = 0.5 (midpoint): the coherence value at which P = 0.5
- k = 8.0 (steepness): how sharply the transition occurs
This sigmoid divides the coherence range [0.0, 1.0] into three distinct behavioural regions.
Suppression region (C_eff below approximately 0.2): P is near zero. The exponential term dominates. At C_eff = 0.1:
P(0.1) = 1 / (1 + exp(-8 * (0.1 - 0.5)))
= 1 / (1 + exp(3.2))
= 1 / (1 + 24.53)
= 1 / 25.53
= 0.039
Permeability of 3.9%. Motors are barely twitching. LEDs are nearly off. The robot is observing. This is the cold-start state: a robot in a new environment, or one that has just experienced a context change. It watches and waits.
Transition region (C_eff approximately 0.2 to 0.8): P increases rapidly. This is the calibration zone where small changes in coherence produce noticeable changes in behaviour. At C_eff = 0.5:
P(0.5) = 1 / (1 + exp(-8 * (0.5 - 0.5)))
= 1 / (1 + exp(0))
= 1 / (1 + 1)
= 0.5
Exactly 50% permeability at the midpoint. By design.
At C_eff = 0.4:
P(0.4) = 1 / (1 + exp(-8 * (0.4 - 0.5)))
= 1 / (1 + exp(0.8))
= 1 / (1 + 2.226)
= 0.310
At C_eff = 0.6:
P(0.6) = 1 / (1 + exp(-8 * (0.6 - 0.5)))
= 1 / (1 + exp(-0.8))
= 1 / (1 + 0.449)
= 0.690
Between 0.4 and 0.6 coherence, permeability moves from 31% to 69%. The transition is steep but smooth. There are no discontinuities. No thresholds where behaviour jumps. The sigmoid ensures that the human observer sees a gradual opening-up of the robot's expressiveness as trust builds.
Saturation region (C_eff above approximately 0.8): P approaches 1.0. At C_eff = 0.9:
P(0.9) = 1 / (1 + exp(-8 * (0.9 - 0.5)))
= 1 / (1 + exp(-3.2))
= 1 / (1 + 0.041)
= 0.961
96.1% permeability. The robot is operating at near-full expression. Further increases in coherence produce diminishing returns in behaviour -- the system is already near its maximum. This saturation prevents over-sensitivity at high trust levels. The difference between 0.9 and 0.95 coherence is barely perceptible in behaviour, which is correct: the robot should not visibly change when trust goes from "very high" to "slightly higher."
Tension Modulation
The sigmoid midpoint c_0 is not fixed. It shifts with social tension. From patent section [0055d]:
c_0_eff = c_0 + 0.2 * (tension - 0.5)
Tension is a scalar in [0.0, 1.0] computed from the social phase classifier. It represents environmental instability: rapid context changes, unfamiliar presences, conflicting signals. Baseline tension is 0.5 (neutral).
The modulation range: 0.2 x (tension - 0.5) ranges from -0.1 (at tension = 0.0) to +0.1 (at tension = 1.0). The effective midpoint c_0_eff therefore ranges from 0.4 to 0.6.
Low tension (calm, familiar environment): c_0 shifts LEFT. The sigmoid moves left along the coherence axis. Behaviour unlocks at lower coherence. The robot opens up more easily.
High tension (unfamiliar, unstable environment): c_0 shifts RIGHT. The sigmoid moves right. More coherence is needed for the same behavioural output. The robot tightens up.
This is psychologically intuitive. In a calm environment, you need less evidence of trustworthiness before relaxing. In a tense environment, you need more evidence. The sigmoid shift encodes this intuition as a continuous, smooth modulation.
Worked Example: Kitchen Morning
Robot in the kitchen. C_eff = 0.6 (moderately familiar context). Tension = 0.3 (calm morning, no unusual activity).
Step 1 -- compute effective midpoint:
c_0_eff = 0.5 + 0.2 * (0.3 - 0.5)
= 0.5 + 0.2 * (-0.2)
= 0.5 - 0.04
= 0.46
Step 2 -- compute permeability:
P(0.6) = 1 / (1 + exp(-8 * (0.6 - 0.46)))
= 1 / (1 + exp(-8 * 0.14))
= 1 / (1 + exp(-1.12))
= 1 / (1 + 0.326)
= 0.754
Step 3 -- apply to channels (assuming configured maximums):
Motor amplitude: 120 degrees * 0.754 = 90.5 degrees
LED brightness: 200 units * 0.754 = 150.8 units
Audio volume: 70 dBA * 0.754 = 52.8 dBA
Verbal complexity: 1.0 * 0.754 = 0.754 (75% of full vocabulary)
The robot is operating at about three-quarters of its full expressiveness. Smooth servo movements. Warm, visible LEDs. Conversational volume. Natural speech patterns. This is a robot that knows this kitchen and is comfortable here.
Worked Example: Stranger Enters
Same robot. Same kitchen. Same C_eff = 0.6. But now tension = 0.7 (a stranger entered the room, detected by the presence sensor switching from "static" to "approaching" with an unfamiliar ultrasonic signature).
Step 1 -- compute effective midpoint:
c_0_eff = 0.5 + 0.2 * (0.7 - 0.5)
= 0.5 + 0.2 * 0.2
= 0.5 + 0.04
= 0.54
Step 2 -- compute permeability:
P(0.6) = 1 / (1 + exp(-8 * (0.6 - 0.54)))
= 1 / (1 + exp(-8 * 0.06))
= 1 / (1 + exp(-0.48))
= 1 / (1 + 0.619)
= 0.618
Step 3 -- apply to channels:
Motor amplitude: 120 * 0.618 = 74.2 degrees
LED brightness: 200 * 0.618 = 123.6 units
Audio volume: 70 * 0.618 = 43.3 dBA
Verbal complexity: 1.0 * 0.618 = 0.618
The robot pulls back. Same coherence, same kitchen, but the stranger's presence increased tension. Motor range drops from 90.5 to 74.2 degrees. Volume drops from 52.8 to 43.3 dBA. Speech becomes simpler. The robot is still operating -- it has not shut down -- but it is visibly more cautious.
The person watching sees this: the robot was animated and expressive, a stranger walked in, and the robot became quieter and more contained. Not frozen. Not alarmed. Just... shy. This is the behaviour that gives the robot its name.
The Piecewise Linear Alternative
Not every platform has a fast exp() implementation. ARM Cortex-M0 (no FPU) computes exp() in software, which is slow. For these platforms, CCF provides a piecewise linear approximation of the sigmoid.
The approximation uses four breakpoints at the quadrant boundaries:
P_linear(c) =
0.0 if c <= 0.15
(c - 0.15) * (0.5 / 0.35) if 0.15 < c <= 0.50
0.5 + (c - 0.50) * (0.5 / 0.35) if 0.50 < c <= 0.85
1.0 if c > 0.85
This produces a trapezoidal approximation: flat at 0 below 0.15, linear ramp from 0 to 0.5 between 0.15 and 0.50, linear ramp from 0.5 to 1.0 between 0.50 and 0.85, flat at 1.0 above 0.85. The maximum deviation from the true sigmoid is about 0.06 (6% error in the transition region).
The piecewise linear version uses only comparisons, subtraction, and multiplication. No exp(). No division. Compiles to approximately 8 ARM instructions. Execution time is under 100 nanoseconds on Cortex-M0 at 48 MHz.
The trade-off: the piecewise linear version has slope discontinuities at the breakpoints. An observer watching the robot's behaviour might notice a subtle change in the rate of behavioural opening at C_eff = 0.15 and C_eff = 0.85. In practice, coherence changes slowly enough (it is a running accumulator) that the slope discontinuity is imperceptible.
Why a Sigmoid and Not a Linear Map
A linear map P(c) = c is simpler. Why the sigmoid?
Suppression floor. At C_eff = 0.1, a linear map gives P = 0.1 -- the robot is at 10% output, which is visible and potentially confusing. The sigmoid gives P = 0.039 -- the robot is essentially still. The sigmoid creates a clean "off" region at low trust that a linear map cannot.
Saturation ceiling. At C_eff = 0.9, a linear map gives P = 0.9 -- the robot is noticeably below full output. The sigmoid gives P = 0.961 -- the robot is perceptually at full expression. The sigmoid creates a clean "on" region at high trust.
Sensitivity in the middle. The sigmoid concentrates its dynamic range in the [0.2, 0.8] coherence band, exactly where trust is actively being calibrated. A linear map spreads sensitivity uniformly. The sigmoid puts the sensitivity where it matters.
Tension modulation range. Shifting a linear map left or right changes the endpoints (P goes negative or exceeds 1.0, requiring clamping). Shifting a sigmoid preserves the [0.0, 1.0] output range regardless of the midpoint. The tension modulation works naturally without boundary conditions.
Composition with the Minimum Gate
The full pipeline from sensor input to motor output:
Sensor readings
-> Quantization (context key)
-> Accumulator lookup (C_ctx)
-> Minimum gate: C_eff = min(C_inst, C_ctx)
-> Sigmoid: P = 1 / (1 + exp(-k * (C_eff - c_0_eff)))
-> Motor output = motor_max * P
The minimum gate (forced convergence theorem) ensures that C_eff is bounded by both instantaneous stability and accumulated trust. The sigmoid then converts this bounded scalar into a smooth behavioural modulation. The two stages are orthogonal: the min gate provides the safety bound, the sigmoid provides the perceptual mapping.
If the environment suddenly becomes unstable (C_inst drops), C_eff drops immediately (the min gate is instantaneous), and P drops through the sigmoid. The robot contracts. No delay. No smoothing. The safety response is as fast as the sensor can report instability.
If the environment is stable but the robot is new to this context (C_ctx is low), C_eff stays low despite high C_inst, and P stays in the suppression region. The robot watches, even though the environment is calm. Trust must be earned before the behaviour opens up.
The combination of the min gate's safety guarantee and the sigmoid's smooth perceptual mapping is what produces the observable "shy" behaviour. The robot is not running an emotion model. It is not simulating anxiety. It is applying a monotone function to a bounded scalar. The shyness is emergent from the mathematics.
The full claim structure covering the permeability function is in the patent. The implementation is available in ccf-core on crates.io under BSL 1.1. Commercial licensing through Flout Labs.
See also Fleet Analytics: 20 Numbers, No Sensor Data for how the phase distribution and permeability statistics feed into fleet-level monitoring without transmitting raw sensor data.
— Colm Byrne, Founder — Flout Labs, Galway, Ireland
Patent pending. US Provisional 64/039,626.
FAQ
Why k = 8.0 for the steepness parameter? What happens with different values?
k = 8.0 was chosen empirically during mBot2 testing. At k = 4.0, the transition is too gradual -- the robot spends too much time in a "half-expressive" state that looks hesitant rather than shy. At k = 12.0, the transition is too sharp -- the robot flips from inactive to active over a narrow coherence band, which looks like a binary switch rather than a personality. k = 8.0 produces a transition width of approximately 0.6 coherence units (from 10% to 90% permeability), which maps well to the trust-building timescale. A human observer sees the robot gradually warm up over several interactions, which is the target behaviour.
Does the tension modulation create a feedback loop? Can tension drive itself higher through reduced behaviour?
No, because tension is computed from environmental sensors, not from the robot's own behaviour. Tension is derived from the social phase classifier, which uses context key transitions, presence patterns, and coherence velocity. The robot's behavioural output (motor position, LED colour, audio volume) does not feed back into the tension computation. This is a deliberate architectural decision: the robot responds to the environment, not to its own response to the environment. A feedback loop would create the possibility of runaway suppression, which violates the safety contract.
Can the sigmoid be tuned per deployment without recompilation?
Yes. The parameters c_0 and k are runtime-configurable in ccf-core. The Personality struct includes permeability_midpoint and permeability_steepness fields that can be loaded from configuration at startup. Different robot personalities can use different sigmoid shapes: a "bold" personality might use c_0 = 0.35 (opens up earlier), while a "cautious" personality might use c_0 = 0.65 (needs more trust). The tension modulation range (0.2) is also configurable via tension_modulation_range. All parameters are bounded to prevent configurations that violate safety properties.
What is the latency from C_eff change to motor output change?
One tick. The sigmoid computation is instantaneous (one exp() call, one division). The motor command is updated in the same tick that C_eff changes. On the mBot2 at 100 ms tick rate, the latency from environmental change to motor response is at most 100 ms: one tick for the sensor to update, one tick for the accumulator and min gate, and the sigmoid and motor command are computed in the same tick as the min gate. In practice, the dominant latency is the sensor polling interval, not the sigmoid computation.
How does this relate to the social phase system?
The social phase (ShyObserver, CuriousApproacher, ActiveCompanion, QuietlyBeloved) is a CLASSIFIER on top of the coherence and tension values. It provides a human-readable label for the robot's current state. The permeability function is the ACTUATOR -- it converts the same coherence value into a motor command. They operate in parallel on the same input. The social phase label is used for logging, dashboard display, and fleet analytics. The permeability value is used for physical output. They are consistent because they are both monotone functions of the same underlying scalar.