v18.0.0 makes Worldlines and Optics the first-use public API story for application code.
This is not a removal guide. The lower-level graph capability bag,
WarpApp, WarpCore, and materialize-named diagnostic surfaces remain
available for compatibility, migrations, substrate tooling, and operator
evidence. The migration goal is to stop teaching application code to open a
graph and fold state as the normal read path.
| Area | v17 habit | v18 preferred shape |
|---|---|---|
| Entry point | openWarpGraph({ graphName }) |
openWarpWorldline({ worldlineName }) |
| App writes | graph.patches.patch(...) |
worldline.commit(...) |
| Live reads | graph.query.worldline() |
worldline.live() |
| Historical reads | graph.query.worldline({ source }) |
await worldline.seek({ source }) |
| Filtered reads | graph.query.observer(...) or worldline.observer(...) |
worldline.observer(...) |
| Optic reads | graph.query.worldline().optic() |
Verify existing basis with worldline.prepareOpticBasis(), then use worldline.coordinate().optic() |
| Whole-state replay | graph.materialize() |
Diagnostic only; use worldline reads for apps |
| Advanced substrate work | WarpApp / WarpCore escape hatches |
openWarpGraph() capability namespaces |
Before:
import { GitGraphAdapter, openWarpGraph } from '@git-stunts/git-warp';
import GitPlumbing from '@git-stunts/plumbing';
const plumbing = new GitPlumbing({ cwd: './team-repo' });
const persistence = new GitGraphAdapter({ plumbing });
const graph = await openWarpGraph({
persistence,
graphName: 'events',
writerId: 'agent-1',
});After:
import { GitGraphAdapter, openWarpWorldline } from '@git-stunts/git-warp';
import GitPlumbing from '@git-stunts/plumbing';
const plumbing = new GitPlumbing({ cwd: './team-repo' });
const persistence = new GitGraphAdapter({ plumbing });
const events = await openWarpWorldline({
persistence,
worldlineName: 'events',
writerId: 'agent-1',
});The value previously passed as graphName becomes worldlineName. The
underlying storage layout still uses graph refs; the public application noun is
now the admitted worldline.
Before:
const patchSha = await graph.patches.patch((patch) => {
patch.addNode('task:auth')
.setProperty('task:auth', 'status', 'open');
});After:
const patchSha = await events.commit((patch) => {
patch.addNode('task:auth')
.setProperty('task:auth', 'status', 'open');
});Both forms commit one atomic WARP patch and return the patch commit SHA. The v18 form keeps application code on the Worldline-first handle.
Before:
const live = graph.query.worldline();
const props = await live.getNodeProps('task:auth');After:
const live = events.live();
const props = await live.getNodeProps('task:auth');events.live() does not expose graphName, materialize(), checkpoint,
provenance, sync, strands, or raw core access.
Before:
const beforeReview = graph.query.worldline({
source: {
kind: 'coordinate',
frontier: { alice: 'abc123...' },
ceiling: 12,
},
});After:
const beforeReview = await events.seek({
source: {
kind: 'coordinate',
frontier: { alice: 'abc123...' },
ceiling: 12,
},
});Historical reads stay in the read model. Application code should not rebuild old state by manually replaying patches.
Before:
const live = graph.query.worldline();
const publicView = await live.observer('public', {
match: ['task:*', 'service:*'],
redact: ['internalNotes'],
});After:
const publicView = await events.observer('public', {
match: ['task:*', 'service:*'],
redact: ['internalNotes'],
});Use observers for product boundaries such as redaction, tenant scoping, and role-specific views.
Before:
const status = await graph.query.worldline()
.optic()
.node('task:auth')
.prop('status')
.read();After:
await events.prepareOpticBasis();
const coordinate = await events.coordinate();
const status = await coordinate
.optic()
.node('task:auth')
.prop('status')
.read();Foundation optics require checkpoint-tail basis evidence. prepareOpticBasis()
verifies existing basis evidence and fails closed when it is missing; it does
not materialize the full graph to manufacture a basis. This path is
transitional until gate 2 adds memory-budgeted basis and tail providers. If an
optic reports E_OPTIC_NO_BOUNDED_BASIS, repair or build the checkpoint-tail
evidence through operator tooling, or use events.live(), events.seek(...),
or an observer read when you do not need Optic identity.
Keep openWarpGraph() when you intentionally need:
graph.strandsfor speculative lanes, braid overlays, comparison, or transfer planning.graph.provenancefor patch-level explanation and evidence.graph.checkpointfor operational checkpoint and GC work.graph.syncfor programmatic sync and serving.graph.comparisonfor coordinate comparison and transfer facts.graph.subscriptionsfor reactive push-style state notifications.graph.materialize,materializeStrand, ormaterializeSlicefor diagnostic replay, migration evidence, and tooling.
Keep WarpApp or WarpCore only when a compatibility dependency still expects
that facade shape. New application code should not add new dependencies on
those facades.
v18 does not claim:
- full retirement of legacy content/property storage,
- native Continuum witnesshood,
- broader slice-first read execution beyond the bounded-memory public path, or
- zero use of materialization inside the runtime.
The v18 public claim is narrower and stronger: application callers have a Worldline-first API, graph/materialize-first surfaces are compatibility, diagnostic, migration, or substrate tools, and public release is blocked until normal reads, writes, content lookup, and sync pass the bounded-memory large-graph product gate.
- Replace app-facing
openWarpGraph({ graphName })calls withopenWarpWorldline({ worldlineName }). - Replace app-facing
graph.patches.patch(...)calls withworldline.commit(...). - Replace live
graph.query.worldline()reads withworldline.live(). - Replace historical
graph.query.worldline({ source })reads withawait worldline.seek({ source }). - Replace app-facing observer creation with
worldline.observer(...). - Keep
openWarpGraph()only where a caller needs an advanced capability namespace. - Remove app-facing
materialize()calls unless the caller is explicitly diagnostic, migratory, or operator tooling. - Run
npm run typecheck,npm run test, or the equivalent consumer checks for your project.
Use this plan after migrating a consumer:
| Scenario | Expected Result |
|---|---|
openWarpWorldline({ worldlineName, writerId }) opens successfully |
Returned handle has worldlineName and writerId |
openWarpWorldline({ graphName, writerId }) is attempted |
Typecheck rejects graphName |
worldline.commit(...) writes a node |
worldline.live().getNodeProps(...) sees it |
worldline.seek({ source }) pins a historical coordinate |
Later patches are hidden from the pinned read |
worldline.observer(...) redacts properties |
Redacted keys are absent from observer reads |
worldline.materialize is accessed |
Typecheck rejects the property |
Existing diagnostic openWarpGraph() tooling remains in place |
Substrate commands still compile and run |
WarpWorldlineOpenOptions uses worldlineName. Rename the option at the
application boundary. Do not pass both names.
That is intentional on WarpWorldline. Use live(), seek(...),
observer(...), or optic() for app reads. Move diagnostic replay code to a
small adapter that opens openWarpGraph() explicitly.
The optic does not have checkpoint-tail basis evidence. Use a worldline or observer read for the same question, or repair/build the checkpoint-tail evidence required by the optic path.
Strands remain an advanced graph capability. Open openWarpGraph() in the
module that owns speculative-lane behavior, and keep the rest of the app on the
Worldline-first surface.