Functional Weave
Code in Rust

manufacturing.takt-time

Takt time: available production time divided by customer demand, exact and in whole seconds.

1.0.0 · published 2026-10-03 by charlie · Anterra

Pinned by 14 tests, run in TypeScript, Python and Rust.

What it does

Takt time is the pace a line must work at to meet demand:

takt = available time / customer demand

For example

  • takt_time(27,000, 450, down) → exact …, seconds 60 an 8-hour shift less two 15-minute breaks (27000 s) for 450 units is 60 s
  • takt_time(27,000, 400, down) → exact …, seconds 67 27000 s for 400 units is exactly 67.5 s; down keeps pace at 67
  • takt_time(27,000, 400, half-up) → exact …, seconds 68 67.5 s rounds half-up to 68

The function

The same function in TypeScript, Python and Rust, pinned by the same tests. Pick your language; the choice follows you around the registry.

pub fn takt_time(available_seconds: i64, demand: i64, mode: &str) -> TaktTime
available_secondsintworking time in the period, after breaks and planned stops
demandintunits the customer needs in the same period, more than zero
modeRoundingModehow the exact takt becomes whole seconds; down never falls behind demand
returnsTaktTime

The type it declares, generated into your project

/// The exact takt as a fraction of seconds, and the same rounded to whole seconds.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TaktTime {
    /// seconds per unit, reduced
    pub exact: Rational,
    /// seconds per unit, rounded by mode
    pub seconds: i64,
}

Your code names it in one line, in the file that uses it

fune!(manufacturing.takt-time@^1);  // then call takt_time(…)
impl/rust.rs · 43 lines · open · raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

use super::funejson::Value;  ← the fune runtime: the JSON value the test vectors use; fune build keeps it only where a signature takes one
use super::math_rational::{rational, rational_to_integer, rational_to_value};  ← from math.rational ^1.0.0 · built alongside by fune

const MAX_SAFE: i64 = (1i64 << 53) - 1;

/// Takt time, available time / demand, as an exact fraction and in whole
/// seconds. The whole seconds are rounded once from the exact fraction, so a
/// caller balancing a line on `exact` never inherits a rounding step.
///
/// # Panics
/// Panics on negative available time, demand that is not positive, or an
/// unknown rounding mode.
pub fn takt_time(available_seconds: i64, demand: i64, mode: &str) -> TaktTime {
    if !(0..=MAX_SAFE).contains(&available_seconds) {
        panic!(
            "availableSeconds must be a whole number of seconds, not negative, received {}",
            available_seconds
        );
    }
    if !(1..=MAX_SAFE).contains(&demand) {
        panic!("demand must be a whole number of units greater than zero, received {}", demand);
    }
    let exact = rational(available_seconds, demand);
    let seconds = rational_to_integer(&exact, mode);
    TaktTime { exact, seconds }
}

pub fn takt_time_to_value(result: &TaktTime) -> Value {
    Value::obj(vec![
        ("exact", rational_to_value(&result.exact)),
        ("seconds", Value::Int(result.seconds)),
    ])
}

pub fn fune_vector(args: &[Value]) -> Value {
    if let Value::Float(f) = &args[0] {
        panic!("availableSeconds must be a whole number of seconds, not negative, received {}", f);
    }
    if let Value::Float(f) = &args[1] {
        panic!("demand must be a whole number of units greater than zero, received {}", f);
    }
    takt_time_to_value(&takt_time(args[0].as_i64(), args[1].as_i64(), args[2].as_str()))
}

Install

fune build

With that line in your source, in a Rust project (language rust in fune.project), fune build resolves it and its 2 dependencies, pins them in fune.lock, downloads only the Rust package of each, and builds the code above into your project’s .fune/build, one readable file per capability with a header linking back here. A crate’s build.rs runs it before every compile. Or pin a range in fune.project and build in one step:

fune add manufacturing.takt-time
Download for Rust manufacturing.takt-time-1.0.0-rust.fune · 7,744 bytes sha256 58d02444ef6d231fdf7d2eab8caf5e2819d040c141772fc941f36fcf5619b68a

The manifest, vectors and README with only the Rust implementation. Install it without the registry with fune add ./manufacturing.takt-time-1.0.0-rust.fune, or fetch it from a terminal with fune pull manufacturing.takt-time@1.0.0:rust.

The whole function, every language, is one file too: manufacturing.takt-time-1.0.0.fune, 9,998 bytes, sha256 fd7d347610f0d78c840a26ef782ce2053b081d4bf02cd41df8ded064c3afccb7. It installs into a project of any language.

Customise it in your app

The seams this capability offers. Put a marker directly above a function of your own and fune build wires it into the built code; the package on the registry is not changed, the built file’s header lists it under CUSTOMISED, and fune hooks lists every hook in the project. How hooks work.

before — your function gets the arguments and returns them, changed or not, or throws to refuse the call.

// fune: before manufacturing.takt-time

after — your function gets the result and the arguments, and returns the final result.

// fune: after manufacturing.takt-time

replace — inside this capability’s code only, calls to a dependency go to your function, with the same signature. Other capabilities that use it are unaffected; write in * to replace it everywhere.

// fune: replace math.rational in manufacturing.takt-time
// fune: replace math.round-div in manufacturing.takt-time

step — your function runs at a numbered point inside the function’s body, receives the in-scope values it names as parameters, and may return replacements. List the points with fune show manufacturing.takt-time --steps.

// fune: step manufacturing.takt-time after <n|label>

Tests

A version published now needs at least 8 tests for every function, and one that expects the error for each function that throws; the registry refuses it otherwise. fune verify --all runs each case in TypeScript, Python and Rust, and a project runs them again with fune verify. This page lists the cases; it does not run them. The exact JSON is vectors.json.

CaseArgumentsExpected
an 8-hour shift less two 15-minute breaks (27000 s) for 450 units is 60 s 27,000, 450, down → exact …, seconds 60
27000 s for 400 units is exactly 67.5 s; down keeps pace at 67 27,000, 400, down → exact …, seconds 67
67.5 s rounds half-up to 68 27,000, 400, half-up → exact …, seconds 68
67.5 s rounds half-even to 68 (68 is even) 27,000, 400, half-even → exact …, seconds 68
an exact half on an even second: 26 s over 4 units is 6.5, half-even goes down to 6 26, 4, half-even → exact …, seconds 6
27000 s for 460 units is 1350/23 = 58.70 s; half-up gives 59 27,000, 460, half-up → exact …, seconds 59
1350/23 rounds down to 58 27,000, 460, down → exact …, seconds 58
two shifts over a 5-day week: 270000 s for 4800 units is 56.25 s, up gives 57 270,000, 4,800, up → exact …, seconds 57
demand larger than the seconds available: takt under one second 3,600, 7,200, half-up → exact …, seconds 1
no available time gives a takt of zero 0, 100, down → exact …, seconds 0
Show the other 4 tests
CaseArgumentsExpected
zero demand is an error 27,000, 0, down → error: demand must be a whole number of units greater than zero
negative available time is an error -1, 10, down → error: availableSeconds must be a whole number of seconds, not negative
fractional demand is an error 27,000, 2.5, down → error: demand must be a whole number of units greater than zero
an unknown rounding mode is an error 27,000, 400, nearest → error: unknown rounding mode

More from the author

An 8-hour shift less two 15-minute breaks is 27,000 seconds; with a demand of 450 units that is one unit every 60 seconds.

**Exact first, then rounded once.** The answer is returned twice: `exact`, the reduced fraction of seconds (27,000 / 400 is `135/2`), and `seconds`, that fraction rounded to whole seconds by the mode you choose. Keep `exact` for line balancing (dividing takt among stations or comparing it with cycle times) so no rounding compounds; use `seconds` for the board on the shop floor.

**Which mode.** `down` is the safe choice for a pace: a takt rounded up (67.5 s to 68 s) makes 397 units in the shift, not 400. `half-up` and `half-even` give the nearest second; `up` is there for completeness.

**Available time is the caller's.** Pass the time the line is actually planned to run in the period (shift length less breaks, meetings and planned maintenance), in seconds, and demand for the same period. The function does no calendar arithmetic, so a week or a month works the same as a shift.

Zero available time gives a takt of 0. Demand must be more than zero (no demand means no pace to keep), and neither may be negative.

Files

PathBytes
README.md1,279
impl/python.py1,161
impl/rust.rs1,676
impl/typescript.ts999
vectors.json2,403