continu.st

where process persists and craft compounds over time

The Continuity Principle

In software architecture, continuity is the quality that allows a system to absorb change without fracture. A continuous system bends where a brittle one breaks. This is not resilience -- resilience implies recovery from failure. Continuity implies the failure never occurs because the design anticipated the change.

"A system that cannot evolve is already obsolete."

Chapter I

Understanding the foundations: why persistent processes outlast ephemeral optimization.

persistence.js
const persist = (state, transform) => {
  const next = transform(state);
  return Object.freeze({
    ...state,
    ...next,
    _version: state._version + 1
  });
};

Immutable State

Each transformation produces a new version. The previous state remains accessible -- a geological record of decisions. Version numbers are not metadata; they are the architecture.

v1 v2 v3 version graph

The version graph branches but never severs. Every path leads back to the root. Follow any edge and you traverse the full history of a decision.

Event Sourcing

Rather than storing current state, record every event that led to it. The present becomes a function of the past. Replay, audit, debug -- all become trivial operations on an append-only log.

"The log is the database. Everything else is a view."

event-log
type Event = {
  id: UUID,
  timestamp: Date,
  payload: Record,
  causation: UUID | null
};

Each event carries its own causation chain. Follow the chain backward to understand why any given state exists. Forward to predict consequences.

The Persistence Spectrum

Systems exist on a spectrum from ephemeral to eternal. At one end: stateless functions that forget everything between invocations. At the other: append-only ledgers that never discard a single byte. Most interesting architectures live somewhere in the middle -- choosing what to remember and what to release with deliberate care.

The art is not in maximizing persistence but in choosing the right granularity. Persist too little and you lose context. Persist too much and you drown in history. The continuous system finds the natural joints in the data and preserves exactly the right cross-sections.

ephemeral selective eternal persistence spectrum

"Memory is not free. Choose what to remember."

Building Continuous Pipelines

A pipeline is a series of transformations through which data flows. In a continuous pipeline, each stage is idempotent and the pipeline itself is resumable. Failure at stage N means restarting at stage N, not stage 1. The pipeline remembers where it was.

Chapter II

Practical patterns for systems that never truly stop.

"Idempotency is the foundation of all reliable systems."

pipeline.ts
interface Stage<I, O> {
  name: string;
  execute: (input: I) => Promise<O>;
  checkpoint: (output: O) => Promise<void>;
  recover: () => Promise<O | null>;
}

class ContinuousPipeline<T> {
  private stages: Stage<any, any>[] = [];

  async run(input: T): Promise<void> {
    let data: any = input;
    for (const stage of this.stages) {
      const cached = await stage.recover();
      if (cached) { data = cached; continue; }
      data = await stage.execute(data);
      await stage.checkpoint(data);
    }
  }
}

Checkpoint Recovery

The recover method on each stage checks for a previously checkpointed output. If found, the stage is skipped entirely. The pipeline resumes from the last successful checkpoint, making partial failures a non-event.

The pipeline stores its cursor position as a durable artifact. Crash, reboot, restart -- the pipeline knows exactly where to pick up. No human intervention required.

Backpressure

A continuous system must regulate its own throughput. When downstream stages slow, upstream stages must slow in sympathy. This is backpressure -- the system breathing in rhythm with its own capacity.

backpressure
const throttle = async (queue) => {
  while (queue.depth > MAX) {
    await sleep(100);
  }
  return queue.push(item);
};
in proc out backpressure signal

The feedback loop from output to input creates a self-regulating organism. No external orchestrator needed. The system is its own governor.

stream-merge.ts
async function* merge<T>(
  ...streams: AsyncIterable<T>[]
): AsyncGenerator<T> {
  const pending = new Set(
    streams.map((s, i) =>
      advance(s, i))
  );
  while (pending.size > 0) {
    const { value, done, idx } =
      await Promise.race(pending);
    if (!done) {
      yield value;
      pending.delete(idx);
      pending.add(
        advance(streams[idx], idx));
    }
  }
}

Stream Merging

Multiple input streams converge into a single output, preserving the arrival order. The merge operator is the junction where independent timelines synchronize. Each stream contributes at its own pace.

"Concurrency is not parallelism; it is the art of managing many things at once."

Windowing

Streams are infinite, but analysis requires boundaries. A window carves a finite slice from the infinite stream -- by time, by count, or by session. The window is the lens through which we observe the continuous.

window types
// tumbling: fixed, non-overlapping
window('5m', { slide: '5m' })

// sliding: fixed, overlapping
window('5m', { slide: '1m' })

// session: gap-based
window({ gap: '30m' })

The choice of window defines what questions you can answer. Tumbling windows for aggregation. Sliding windows for trends. Session windows for behavior.

tumbling sliding window strategies

Exactly-Once Semantics

The hardest guarantee in distributed systems. At-least-once is easy: just retry. At-most-once is easy: just do not retry. Exactly-once requires idempotent writes and transactional log commits working in concert.

anti-pattern
// WRONG: non-idempotent
counter += 1;
commit(offset);

// RIGHT: idempotent write
store.put(key, value);
commit(offset);

"Exactly-once is not a protocol. It is a contract between the producer and the consumer."

The distinction matters in production. A payment processed twice is not a bug report -- it is a financial incident. The continuous system treats delivery semantics as a first-class architectural concern.

Systems end. Processes continue.

The log persists.

Every version remains.

The continuous process has no final state, only the next transformation.

continu.st