OSS-first docs

These docs teach the open system first: contracts, generated surfaces, runtimes, governance, and incremental adoption. Studio shows up as the operating layer on top, not as the source of truth.

AI index

Spec pack

Data Fetching is one spec-first protocol with an in-house engine.

Queries, caching, offline, and conflict resolution collapse into a single canonical protocol in contracts-spec, carried by one Transport port and executed by the in-house engine in contracts-runtime-core — no `@tanstack/*`, no second cache model to drift from.

Packages and roles

  • @lssm-tech/lib.contracts-spec — I/O-free protocol primitives (/query, /results).

  • @lssm-tech/lib.contracts-runtime-core — framework-neutral engine + Transport/Storage/reachability ports (+ /storage/indexeddb, /storage/async-storage, /observability).

  • @lssm-tech/lib.contracts-runtime-client-react — thin React binding: ContractDataEngineProvider, useContractQuery, useContractMutation.

  • @lssm-tech/lib.contracts-runtime-server-rest / -server-mcp — REST and MCP Transport adapters carrying ContractResult<QueryResultEnvelope>.

  • @lssm-tech/lib.design-system — QueryState-aware, I/O-free UI components.

The canonical QueryState

Design-system components consume this render-ready shape directly. The engine produces it; the React hooks return it verbatim.

// One canonical state, three orthogonal axes — never collapse them.
type QueryStatus = 'idle' | 'loading' | 'success' | 'error' | 'auth-expired';
type QueryFetchStatus = 'idle' | 'fetching';

interface QueryState<TData> {
  status: QueryStatus;          // data lifecycle
  fetchStatus: QueryFetchStatus; // in-flight network (revalidation = 'fetching' while 'success')
  data?: TData;
  error?: ContractProblem;
  cacheStatus?: 'fresh' | 'stale' | 'warm' | 'offline' | 'empty' | 'conflict';
  isStale: boolean;
  isOffline: boolean;           // offline is a FIELD, not a status
  conflict?: QueryConflict<TData>; // conflict is a FIELD, not a status
  versionToken?: VersionToken;  // server-issued etag
}

Client quick-start

import {
  ContractDataEngineProvider,
  useContractQuery,
  useContractMutation,
} from '@lssm-tech/lib.contracts-runtime-client-react';
import { createDataEngine } from '@lssm-tech/lib.contracts-runtime-core';
import { createRestTransport } from '@lssm-tech/lib.contracts-runtime-server-rest/rest-transport';

const engine = createDataEngine({
  transport: createRestTransport({ baseUrl: 'https://api.example.com' }),
});

function EntityList() {
  // The hook returns the canonical QueryState VERBATIM (+ refetch) — zero adapter into the DS.
  const state = useContractQuery<readonly { id: string; name: string }[]>({
    operation: { key: 'workspace.entities.list', version: '1.0.0' },
    input: { limit: 20 },
  });
  if (state.status === 'loading') return null;
  return <ul>{state.data?.map((e) => <li key={e.id}>{e.name}</li>)}</ul>;
}

export const App = () => (
  <ContractDataEngineProvider engine={engine}>
    <EntityList />
  </ContractDataEngineProvider>
);

`useContractMutation({ ctx? })` returns `{ status, data, problem, conflictOutcome, isPending, mutate }`; pass `optimistic` writes to `mutate` and the engine handles the durable offline queue, replay-on-reconnect, etag conflict resolution, and rollback.

Engine, transport, and storage

  • `createDataEngine({ transport, localOffline, env?, flag?, advanced?: { storage, reachability } })` exposes query / getState / subscribe / invalidateTags / refresh / emitConflict / mutate / drain / resume / dispose. `localOffline` selects online-only, memory-cache, or offline-capable semantics; `env`/`flag` are the host on/off trigger (precedence flag > env > default), and `createDataEngineFromEnv` reads `CONTRACTSPEC_LOCAL_OFFLINE` from the host `process.env` in one call.

  • REST and MCP are interchangeable Transport adapters; MCP decodes `structuredContent` first. The version token doubles as the realtime invalidation token on the `subscribe()` seam.

  • Durable storage (`/storage/indexeddb` web, `/storage/async-storage` native) is secure-by-default: secret-bearing fields are redacted before persistence, with an encryption seam for at-rest data.

  • Auth: the principal is carried through `ctx` unstripped; `auth-expired` pauses the offline queue, refreshes, and resumes. Enforcement of `policy.auth` stays in authos/identity-rbac — front the operation registry with a default-deny PDP.

Rendering with design-system

`DataViewList`, `EntityDetailPanel`, and `RelationshipSection` are I/O-free and `QueryState`-aware: pass the hook result straight into the `queryState` prop and they render loading / error / offline / stale / empty / conflict / auth-expired / retry — they never fetch.

OSS docscore-modelStart with OSS. Adopt Studio when you want the operating layer.

Why ContractSpec

Keep educational and comparison content reachable without letting it define the primary OSS learning path.