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.

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, storage?, reachability? })` exposes query / getState / subscribe / invalidateTags / refresh / emitConflict / mutate / drain / resume / dispose over one cache.

  • 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.