On this page

Guide development and migration record

Reader contents | Current compatibility advice

This maintainer record preserves the original chapter plan, investigations, repair evidence, and migration history. Status statements and proposed work below are historical, not the current reader-facing table of contents. The first-edition scope supersedes the original recipe wishlist. App migrations remain deferred unless selected.

For model authors: this guide assumes lifecycle: "aligned" in the top-level Project configuration. Start with the first-model tutorial and the aligned lifecycle contract. You do not need to understand runtime messages or underscore-prefixed built-in Stores to write your first model.

Suggested reading path: Fire → Walkers → Main → Turtles → Grazers. Use state management, neighborhoods, and utilities as references along the way. Troubleshooting and the quick reference / NetLogo bridge are ready to consult. Use the alphabetical API index to find a method or property by name. Consult compatibility and known limitations when reading older models or checking which behavior the aligned flag actually changes.

Compatibility: the runtime still uses legacy behavior when the flag is absent. Templates and unconverted apps are not automatically aligned. Freshening the remaining apps is deferred while we develop this guide; do not bulk-add the flag. The process below is for a future, explicitly selected app, not a request to resume migrations.

Freshening an existing app for aligned lifecycle

Freshening means reviewing initialization and reset ownership, not just changing Project. Preserve the model's scientific rules, parameter meanings, random draws, visit mode, and step/shift timing unless a repair is explicitly intended.

  1. Capture the existing behavior. Identify both the standalone app and its Studio library copy, if present. Record startup state, a few controlled steps, displayed outputs, parameter changes, births/deaths, and reset behavior. Compare each copy with its own prior behavior; the copies can legitimately differ. Record known failures rather than silently treating them as targets.
  2. Separate the four jobs. Constructors allocate stable fields/Stores and structural wiring; never call init() or setup() there. init() runs once per object after runtime context/defaults. Local reset() restores that object's state. Runtime-invoked setup() rebuilds relationships and derived state after populations are ready. Keep base calls where required. Main and patches survive world reset; turtles are recreated.
  3. Check early property dependencies. Configured patch colors are assigned before patch init(). Allocate anything needed by an overridden color setter in the constructor (EGOL3's level Store is an example). Main init() cannot assume patches, turtles, or agent configuration exist.
  4. Give custom state an explicit reset policy. Retain Store/listener identity on surviving objects. Do not accumulate listeners in setup, reconstruct populations in local reset, or assume synchronization resets custom Stores. Dispose registrations owned by turtles when those turtles are discarded.
  5. Leave orchestration to the runtime. Remove manual population/child init() and setup() calls. Move population-dependent Main work to setup. Use resetWorld() for a programmatic whole-world reset, not reset(). Check customization callbacks and deferred births as well as startup.
  6. Use public built-in properties. For example, replace this._color.setUpdater(fn) with this.colorUpdater = fn. Aligned super.patchStep() evaluates color; super.turtleStep() schedules movement and then evaluates heading/color/size/shape updaters. Remove duplicate explicit evaluation of those built-ins, without changing their intended timing. Custom Store updaters still need explicit evaluation.
  7. Opt in and verify. Add top-level lifecycle: "aligned" to each reviewed Project, including the embedded Studio Project. Compare controlled startup and trajectories; test multiple resets, changed inputs, zero agents, births/deaths, stable registrations, and initial display/agent rendering. If old reset was broken, test the intended repair separately from trajectory parity. Flagging the app alone is not evidence that it is freshened.
  8. Record evidence and limits. Note which copies were changed, which checks passed, any deliberate behavior repairs, and what was not exercised. Keep unrelated bugs out of the migration.

Migration status and checks

The canonical Agents, Life, Antz, Diffuse, Dla, and EGOL3 apps and their embedded model-library copies are migrated; standalone Ani2 is also migrated. Flock's first-run agent rendering was fixed in shared view initialization for both lifecycle modes; Flock itself has not been migrated. Templates and remaining apps stay as they are until migrations resume. Keep the compatibility flag until legacy and saved/external model compatibility has been addressed; this guide's aligned default is not a runtime-default change.

The opt-in regression suite is testing/nlapi-aligned-lifecycle.test.mjs. It exercises Project/message/dispatcher propagation, browser handshake, cartesian and hex initialization, patch-only/agent-only/empty-agent worlds, local reset versus coordinated world reset, stable Store identities and one-time registrations, constructor failures, and births without changing the existing phase boundaries. Existing legacy characterization tests remain intact.

Representative shipped-model coverage includes Life, Agents, Follower, Fng, Forest, Diffuse, Dla, EGOL3, WvMach, Antz, Ani2, and WolfSheep. Agents now runs through the dispatcher with aligned lifecycle; its deterministic trajectories, output, population, speed changes, repeated resets, and hook counts are compared with a source-derived legacy version. Life and Antz have equivalent source-derived comparisons for canonical and embedded copies. Diffuse and Dla also have source-derived legacy comparisons and repaired-reset regressions; EGOL3 has independent weighted-rule checks for each copy. Forest, WvMach, and WolfSheep are exercised through the actual legacy dispatcher. Dla's old library Status is not defined reset failure remains explicitly characterized in the source-derived legacy copy, while the shipped copy is repaired. These tests do not certify every saved/external model, DOM-dependent model integration, or browser rendering.

Status: work in progress. Three tutorials, practical Main/Patch/Turtle chapters, lifecycle/state chapters, utility/neighborhood references, troubleshooting, the Project configuration reference, and a quick reference/glossary are available. The broader chapter plan below also lists material still to be written; it is not a claim that the whole API has been documented or repaired.

Available chapters

The guide example tests load the tutorials' actual fenced Project/Main/Patch/Turtle sources and check published counts, chart values, movement/turn ordering, slider changes, resource competition, energy caps, empty populations, and repeated reset through the dispatcher. Selected Main/Turtle chapter fragments also execute, including customization, display shapes, pending movement, and birth/death visibility timing. The Patch chapter's complete heat model checks synchronous spreading, conservation, boundary behavior, color timing, live inputs, and stable Store reset. Project-reference checks cover nested input registration, defaults/bindings, explicit starts, population reinitialization, output shapes, and dt versus movement. Main-reference checks inventory declared prototype members and exercise its Store example, callback/queue timing, activation/clear policies, parameters, query side effects, logger payloads, and consuming status/stopping behavior. Patch-reference checks inventory NLPatch/HexPatch declarations and exercise both alternating-rule examples, color notifications/baselines, updater timing, occupancy snapshots, raw coordinate distance, and static serialization. Turtle-reference checks inventory declared members, execute the straight-motion and query/turn examples, and characterize velocity/local-reset behavior, visibility-cache differences, serialization, notifications, and known defective legacy entry points without changing runtime behavior. Root-reference checks inventory NLRoot and inherited APIRoot declarations, execute static/collection/selection examples, and check local reset, sampled paths, extrema policies, geometry, and weighted-selection behavior. Supporting-type checks inventory state/coordinate/agent collection declarations, execute Store/Property/coordinate/enum examples, and check factory reset, Store.create ownership, visibility-filtered lists, and sorting mutation. Index checks cover alphabetical order, unique names, and owner-specific instance/static declaration coverage. They also check neighborhood boundaries/duplicates and square/hex center inclusion, key tool semantics, the aligned state examples, and relative file links. These are headless runtime checks, not browser layout/launch certification. Run from the repository root:

node --test testing/nlapi-guide.test.mjs testing/nlroot-utilities.test.mjs testing/nlapi-aligned-lifecycle.test.mjs

Browser spot checks also loaded the exact Walkers and Grazers sources through the local Studio runtime POST path: 40/30 initial rendered turtles, advancing Step controls, Reset to time zero, and Grazers charts returning to food 960 / mean energy 4. Control events were dispatched programmatically; Studio popup launch and physical mouse hit-testing were not certified. Project examples use the supported format version 0.2, avoiding an unnecessary newer-version warning.

Neighborhood API stabilization

The shared neighborhood API now has consistent contracts in both lifecycle modes: modulo wrapping, unique collection/visitor results, center-including block, center-excluding ring/blockX, explicit zero-distance and validation rules, boundary-aware square nhood4, and topology-neutral neighbors. Turtle counts match unique-other-turtle queries; standard coordinate objects work with nhoodCoords. Radius/annulus queries use Euclidean distance with shortest wrapped displacement, and object-form APIRoot.distance includes both coordinate axes. See the reference.

These are intentional API behavior repairs, not additional app lifecycle migrations. Both Flock copies explicitly round their continuous Vision input up to an integer grid distance, preserving the previous rounding for positive values. All other app lifecycle migrations remain deferred. Both River copies also use public heading/speed assignments for radius-selected source flows; the previously ineffective query had hidden obsolete Store-style calls and a nonexistent parameter getter. The neighborhood tests cover the contracts and affected Flock, River, and RPS callers; existing model comparisons continue to check lifecycle behavior, not parity with the former neighborhood defects. Browser checks also exercised standalone Flock (1000 visible agents, step, reset) and River (eight steps, 16 flows, reset), without page exceptions. The broad testing baseline still has four pre-existing Studio/Designer catalog/selection/resource failures; neighborhood repairs do not address them.

node --test testing/nlapi-neighborhoods.test.mjs testing/nlapi-guide.test.mjs testing/nlapi-compatibility.test.mjs testing/nlapi-apps.test.mjs testing/ani2-aligned-lifecycle.test.mjs testing/nlapi-aligned-lifecycle.test.mjs testing/nlroot-utilities.test.mjs

Purpose and audience

Help model authors build, understand, and extend NuWebKit patch and agent simulations using JavaScript. Assume basic JavaScript knowledge, but no prior knowledge of the NL API or its execution model. Aim at the average NetLogo model author: explain the modeling idea before JavaScript machinery, introduce one concept at a time, and give observable results before advanced variations. Do not assume knowledge of inheritance, callbacks, Stores, or runtime protocols.

The manual should provide three reading paths:

Scope and source material

The four principal classes are:

Class Role Source
NLSimMain Model-wide initialization, scheduling, parameters, populations, and output nlsimmain.js
NLPatch A cell in the spatial environment, with state and neighborhood operations nlpatch.js
NLTurtle An individual agent, with state, movement, sensing, and lifecycle operations nlturtle.js
NLRoot Shared base functionality inherited by Main, Patch, and Turtle nlroot.js

Explain supporting types where they are needed: Store, coordinates, patch and agent collections, Enum, EnumSym, Shape, Dir, and VisitMode. Include inherited APIRoot utilities because model authors call methods such as NLRoot.random() even though they are implemented in apiroot.js. Keep system-dynamics stocks, flows, and integration methods outside the main scope, with a scope note rather than a second API manual.

Existing Studio help is useful supporting material, not a substitute for checking implementation: Main, Patch, Turtle, and Project.

Part I: Getting started

1. The model at a glance

2. Build and run a first model

Part II: Programming guide

3. Understand execution and lifecycle

4. Manage model state correctly

5. Program Main

Practical chapter available.

6. Program patches and their environment

Practical chapter available, including a complete conservative heat-spreading example with deterministic checks.

7. Program turtles

Practical chapter available. Legacy/specialized helpers are identified rather than presented as working introductory shortcuts.

8. Use shared utilities

9. Modeling recipes

Each recipe should include its required Project settings, complete model code, expected behavior, reset behavior, and relevant API reference links.

10. Troubleshooting and checking a model

Troubleshooting chapter available.

Part III: API reference

Reference chapter files and status:

Proposed file Contents
nlsimmain.md (available) Lifecycle hooks; initialization; scheduling; patch/agent access; population operations; parameters; displays; logging
nlpatch.md (available) State properties; lifecycle hooks; neighborhoods; distances; occupancy; listeners; HexPatch overrides
nlturtle.md (available) State properties; lifecycle hooks; movement; direction/distance; sensing; populations; appearance; listeners
nlroot.md (available) Shared state/reset behavior; coordinates; collection operations; selection and aggregation; inherited APIRoot utility inventory
supporting-types.md (available) Stores, coordinates, collection shapes, callbacks, and enums required by the four classes

Standard reference entry

For each method or property, document:

  1. Exact name/signature and declaring class; static or instance.
  2. Role: model-author operation, overridable hook, or runtime/internal helper.
  3. Parameters, defaults, accepted types, units, and return type.
  4. Preconditions, required configuration, and supported collection shapes.
  5. Side effects, mutation, timing, and reset implications.
  6. Boundary behavior, self inclusion, and duplicates where relevant.
  7. A minimal example and a link to a programming-guide use case.
  8. Limitations, failure behavior, verification status, and source location.

Inventory every declared method and property, including aliases and inherited members. Give runtime helpers a brief classification rather than presenting them as ordinary modeling operations.

Part IV: Appendices

Documentation quality and writing order

  1. Inventory the API and classify model-facing operations, hooks, and internals.
  2. Verify lifecycle, state, and reset behavior before drafting recipes.
  3. Write the first complete model and the execution/state chapters.
  4. Draft each class reference alongside its programming-guide chapter.
  5. Run examples in the actual runtime; check boundaries, resets, callback arguments, return shapes, and required Project settings.
  6. Finish recipes, troubleshooting, cross-links, and the alphabetical index.

Do not infer behavior from familiar method names or describe legacy code as a working feature without checking it. Initial source inspection shows apparent Java-port remnants in some NLRoot helpers and duplicate method definitions elsewhere. Record such cases as needing verification; distinguish confirmed limitations from supported behavior. Fixes to the API itself are a separate task, not part of writing this manual.

Source-linked defect inventory

These are concrete implementation findings, not claims that all older methods are defective. The links identify the current declarations; line numbers may move as fixes are made. The initial findings below record the pre-repair failures; see the stabilization status for fixes and current regression coverage.

Reproduced defects

Isolated Node.js probes evaluated the actual NLRoot class body with its imports replaced by minimal stand-ins. A separate probe evaluated both forward declarations together. These checks reproduce local JavaScript failures; they are not full simulation tests. The table retains those initial observations; seven helper defects have since been repaired as described below.

Method and source Reproduced failure and source evidence Repair direction
NLRoot.n_of(size, elements) An array input throws ReferenceError: Collections is not defined. The method also uses Java's subList, which JavaScript arrays do not provide. Use the existing NLRoot.shuffle() on a copy and a JavaScript slice. Define size validation and sampling semantics before fixing the slice bounds.
NLRoot.one_of(elements) An array input throws because elements.size() is not a function. The following unqualified random() is also not defined in this module. Define accepted collection types; use the corresponding length and the inherited random utility. Specify empty-collection behavior.
NLRoot.unquotify(s) A string input throws because s.length() calls a numeric property as a function. Use the string's length property; check empty, quoted, and unquoted strings.
NLRoot.parse(s) String input throws at s0.length(). Additional source defects include s1.length(), Java-style toArray(new String[0]), failure to advance s1 inside the quoted-token loop, and omission of the first token's content when assembling a multiword quote. Define the intended quoting/tokenization contract and replace the Java-port logic. Test empty input, repeated spaces, multiword quotes, and unterminated quotes. Do not repair only the first exception.
NLRoot.meanPMStd(vals) [1, 2, 3] throws ReferenceError: mean is not defined: the result array references mean, but the local variable is mean0. Use the computed mean; confirm result order and population-versus-sample standard deviation, and define empty-input behavior.
NLRoot.max_one_of_value(fn, elements) fn = x => x.score with [{score: 2}] throws because fn.apply(this, val) treats the element as an argument list rather than passing it as one argument. This differs from min_one_of_value, which calls fn(val). Align the callback contract with the minimum-value counterpart; test object and numeric collections.
NLRoot.max_of(objs, fun) Nonempty input throws ReferenceError: best_of is not defined; the instance method is called without this. Call this.best_of(...); check object selection, ties, and empty input.
NLRoot.min_of(objs, fun) The same unqualified best_of(...) call throws ReferenceError. Call this.best_of(...) and cover the same cases as max_of.
NLTurtle.forward(speed) and the following forward() JavaScript does not overload methods by arity. The second definition replaces the first: forward(2) returns the heading without calling fdNext(2). Decide whether forward is a movement operation or heading query; preserve intentional compatibility explicitly and test argument handling.

Additional source findings requiring targeted runtime checks

Method and source Concern to investigate
NLTurtle.fd(dist) Passes the _theta Store object, rather than a numeric heading, to go(). It then calls move(coords), although move() ignores arguments and schedules a speed-based move. Verify and repair immediate-movement semantics together rather than changing only one argument.
NLSimMain.initAgents() and the later initAgents(msg, ws, mainapp) The later definition replaces the earlier lifecycle hook in the base class. Its body also resembles an older message-handling path. Check callers and subclass overrides before removing or renaming it.
NLTurtle.inBounds() and the following duplicate The implementations are identical, so this is redundant code, not a demonstrated behavior defect. Remove duplication separately from functional repairs.

This is the initial inventory behind the outline's warning, not an exhaustive audit of the four classes. Each repair should add focused regression coverage and update the eventual reference entry with the verified contract.

Compatibility-first stabilization

Policy

First batch: narrow helper repairs

The following methods in NLRoot are repaired and covered by API regression tests:

Method Verified contract
unquotify(s) Removes a matching pair of outer double quotes; otherwise preserves the string.
meanPMStd(vals) Returns [mean, mean + populationSD, mean - populationSD]. Empty input retains the calculation's NaN results rather than introducing a new policy.
max_of(objs, fun) Calls the instance selector and returns an object, not its score. Keeps the first tied result; returns null for empty input.
min_of(objs, fun) Same object-selection, tie, and empty-input conventions as max_of.

A repository usage search found no calls to these four methods outside their declarations before this batch. That does not rule out externally saved apps. max_one_of_value is deliberately not changed: its existing argument-list application works for tuples and preserves callback this, even though it fails for ordinary object-element callbacks. A characterization test protects that usable legacy form pending a compatibility decision.

No signatures were renamed. Scheduling, reset, movement, configuration defaults, and random utilities are unchanged.

Characterized behavior retained for compatibility

Runtime characterization tests exercise actual API modules, covering:

Two slash modes, "C/A" and "A/C", currently have no shift-hook mapping: their aliases are assigned before the target entries in initVisitModeMap() exist. Store commitment still occurs. This is a newly characterized defect, not repaired here because adding hook calls can change existing simulations.

Shipped-app tests load actual model code and configuration from the library:

The model comparisons are headless. A local browser smoke test also loaded the canonical Agents page, connected the runtime, stepped, reset, changed Speed, and stepped again. Life and Antz browser evidence is recorded below. Seeded Agents/Antz comparisons are deterministic and exact for their controlled scenarios; this does not certify arbitrary stochastic runs, every library, or externally saved apps.

Validation and next gates

Run the new checks from the repository root:

node --test testing/ani2-aligned-lifecycle.test.mjs testing/nlapi-compatibility.test.mjs testing/nlapi-apps.test.mjs

The existing baseline command is:

node --test testing/*.test.mjs common/js/test/*.test.mjs scripts/*.test.mjs

The current focused NL API suite passes all 111 tests (exit 0), using:

node --test testing/ani2-aligned-lifecycle.test.mjs testing/nlapi-aligned-lifecycle.test.mjs testing/nlapi-apps.test.mjs testing/nlapi-compatibility.test.mjs testing/nlroot-utilities.test.mjs

Before Ani2, the recorded repository baseline ran 155 tests: 150 passed and five pre-existing failures remained. The recorded Ani2 run had 158 tests: 153 passed. After EGOL3 coverage the broad command above runs 178 tests: 173 pass, with five unrelated failures (exit 1; the Designer redirect assertion and four model-library catalog/selection/resource checks). No unrelated failing checks were repaired.

Historical: second batch of expanded compatibility checks

The earlier compatibility batch changed only tests and documentation. Its history is retained here; the first app migration below is the current state. Five consecutive focused runs had passed while exercising stochastic app behavior without imposing an exact random trajectory.

Additional shipped-app coverage:

Earlier batch: Agents aligned-lifecycle migration

The canonical app under agents/ and the embedded common/studio/model_library/models/Agents.html both set Project.lifecycle: "aligned". Their no-op Patch and Turtle constructors no longer call init(); runtime initialization calls those hooks after patch allocation or turtle defaults, respectively. The model's movement and stochastic rules are unchanged. Life and Antz were migrated subsequently, as described below. Templates and remaining shipped models stay legacy.

The dispatcher-path test compares a deterministic 5×7 world with seven agents for initial output, four motion steps, a live speed change, three more steps, and two consecutive resets. It also checks constructor/init/setup counts and turtle replacement on reset. A minimal test transform removes the Project opt-in and restores the old constructor hook calls to form the legacy comparison; it does not duplicate full app fixtures. Results are limited to this model/scenario and do not certify external saved projects or every Agents configuration. Do not remove the lifecycle flag until compatibility of the remaining bundled and saved models has been assessed.

Current batch: Life, then Antz

Life was migrated and verified before changing Antz. Both canonical Project files now select lifecycle: "aligned", as do the actual embedded files common/studio/model_library/models/LIfe.html (case intentional) and common/studio/model_library/models/Antz.html. Standalone pages still import their canonical modules; the all-app build includes those changes. No additional app or template was opted in.

Life: patch constructors no longer call init. The canonical custom state Store is created from the preset color after allocation, synchronized once, and reinitialized locally on reset. Setup seeds the active neighborhood for initial live cells; Main setup restores the original initial-count formula. The embedded version retains its color Store and installs its listener once. Tests compare every cell, counts/output, and active-site membership (not Set insertion order) over 45 ticks and three resets for each copy. An independent synchronous rule also checks 36 ticks and three resets. The embedded legacy reset retained stale active sites from the previous run; aligned reset clears these sites, so its active set is a subset of the legacy set after reset, while cells/counts/output remain exactly equal. This is an intentional aligned reset cleanup, not a change to the Life rule.

Antz: constructors no longer invoke init. FoodPatch and Nest initialization now extend their parent's init explicitly, preserving the factory-selected class, food/chemical Stocks, scents, and color updaters. Turtle init respects the newborn flag so post-default initialization does not overwrite the parent-derived birth location. Death unlinks the retiring turtle and releases its food Stock; Antz's resetWorld() also retires current and queued newborn turtles before delegating world orchestration. Its local reset() remains local and does not remove child Stocks. This avoids orphan Stock closures and agent-index references when instances are replaced. No general Stock disposal API or runtime scheduler change was introduced.

For each copy, seeded seven-ant runs compare all cells, food/chemical values, agent state, patch occupants, time, and display data exactly across 15 ticks, three resets, speed changes, forced births, and forced extinction. Additional tests check food sensing/uptake, parent-position inheritance, local reset, queued-birth reset cleanup, zero population, stable patch/Stock identity, and registration counts. Constructor/init multiplicity differs intentionally; legacy's duplicate turtle-food registrations are not retained. Cartesian and hex mixed-class factory tests prove one allocation/init and no retry on error.

Validation (Node v22.18.0):

These are controlled headless comparisons and canonical-page browser checks, not exhaustive certification of external saved apps, arbitrary topologies, physics settings, or every Studio import/UI path. The five unrelated full-suite failures remain open.

Next batch: Ani2 aligned lifecycle

The standalone Ani2 Project now selects lifecycle: "aligned". Patch and turtle constructors no longer call init() directly; the runtime invokes those hooks after allocation and turtle defaults. Ani2's legacy explicit setup() call is retained only for legacy mode, preventing a duplicate when the aligned dispatcher completes world setup. Its kernel/resource initialization remains in Main setup, after patch and turtle setup, without changing movement, resource, chooser, or stochastic rules.

Ani2 now uses public built-in state accessors (color, nextColor, and nextSize) rather than reaching into the base classes' private Stores. The upload default remains a 1000×1000 world. The deterministic dispatcher test uses a valid custom 12×12 uploaded configuration instead, and compares initial state, Next_Location trajectories, resources, cells, output, live parameters, and repeated-reset results with an in-test source-derived legacy version. It also checks hook counts, stable patch/Store identity, and a single ani2config listener after resets. This is headless model evidence only; no browser rendering or million-cell default-world run is claimed.

The depletion path also contained a pre-existing runtime exception: it passed an undefined id to Main when energy reached zero. It now reaps the turtle by this.id; a focused test forces the zero-energy path and confirms the Chrono state changes to Reaped. No other Ani2 rule or known defect was altered.

Diffuse and Dla aligned lifecycle

Both standalone Projects and the Studio library copies opt into aligned lifecycle ownership. Patch/turtle constructors no longer call init. Existing Studio Dla edits are retained: class-scoped DlaPatch.Status, public pending color/reporting in its listener, and turtle Status binding in init. Standalone Dla keeps its exported Status enum for compatibility.

Diffuse: heat aliases use public built-in accessors. One-time patch init registers heat's Store with synchReportAndVisitNext; this internal Store reference is required by that registration API. No new updater evaluation is added. The ineffective main.patchShift flag is removed (doPatchShift is the runtime's actual property). Main setup now owns the original pre-tick turtle step, preserving startup's pending heat/motion/heading and replaying it on reset. That replay intentionally repairs the old reset, which cleared the field but did not seed it as startup did. Population remains captured at initialization; an NTU parameter message does not resize it on reset.

The scientific timing is unchanged: coordinate diffuses current heat, patches dissipate next heat, then turtles schedule movement and overwrite the old-location patch's next heat with current heat + THT. Multiple colocated turtles overwrite rather than accumulate. The next heading is committed with movement at shift. The numerical regression checks this order, nonzero diffusion/loss, and wrapping. This migration does not make the solver an additive simultaneous heat model.

Dla: Main reset restores radius 0/count 1, and setup publishes CNT after initialization and reset. Patch reset uses its correct enum scope and restores empty current/pending colors before reseeding the center. This also handles a nonseed patch whose built-in color reset baseline was changed. Its status Store/listener is retained rather than reallocated. Public nextTheta replaces direct heading Store access. Birth, movement, neighborhood, and sticking rules are unchanged, including existing distance/collision/index behavior.

Evidence in nlapi-apps.test.mjs:

EGOL3 aligned lifecycle

Both standalone egol3/js and Studio Egol3.html opt into aligned lifecycle. Studio retains its class-scoped Egol3.ELState and per-patch enum binding; standalone retains its exported ELState. Neither patch constructor invokes init. Each constructor allocates the level Store, installs its positive-level scheduling callback, and synchronizes it once, so pre-init configured color assignment is safe. Patch init only enables shifting. Studio's unused turtle constructor no longer invokes its init hook.

Intentional lifecycle repairs:

Evidence and limits:

Additional API-level coverage:

The Follower test also records an existing app-level defect: Follower.init() registers a new MOD listener on each reset. Listener counts grow rather than remaining constant. The regression test captures that behavior to expose a future change, not to designate listener accumulation as a supported contract. One-time registration and repeatable initialization must be separated before claiming reset is free from duplicate listeners.

The headless loader evaluates embedded model classes against real API modules and supplies initialization messages locally. It is not a browser deployment or transport test. The tests cover Cartesian worlds; hex topology, collision accuracy, wrapped trail geometry, nonzero Fng diffusion, and all saved apps remain outside this batch's evidence.

The full regression run after the second batch has 93 passing tests and the same five pre-existing failures. No new failures were introduced.

Third batch: approved sampling and parsing contracts

The user approved these contracts before implementation. This batch repairs n_of, one_of, and parse in NLRoot, with 22 checks in utility tests. The new tests were run before the fixes: 20 failed and two already passed. All 22 pass after the repairs, together with the 31 earlier compatibility checks. The full suite now has 115 passes and the same five pre-existing failures, with no new failures. The focused command including the new utility checks is:

node --test testing/nlroot-utilities.test.mjs testing/nlapi-compatibility.test.mjs testing/nlapi-apps.test.mjs

Sampling

const candidates = [firstAgent, secondAgent, thirdAgent];
const pair = NLRoot.n_of(2, candidates);
const selected = NLRoot.one_of(candidates);

Token parsing

parse(text) accepts a string and returns an array of strings:

NLRoot.parse('alpha "beta gamma" ""');
// ["alpha", "beta gamma", ""]

These are utility repairs, not changes to the execution model. forward, fd, slash-mode shift hooks, tuple callbacks, configuration defaults, and reset semantics remain unchanged. The user explicitly chose to preserve that legacy behavior for now. A targeted search found no tracked NLRoot/APIRoot calls to these three utilities outside their declarations before this batch; external saved apps remain outside that evidence.

Next gates, before broader architectural changes:

  1. Sampling and parsing contracts are now approved, implemented, and tested. Use them in the reference chapters rather than the original Java-port logic.
  2. The second batch covers representative mixed patch/agent behavior, births, sensing, and trails. Add browser checks before any user-visible change, and extend coverage to the specific topology/physics affected by each repair.
  3. Decide a compatibility mechanism before repairing max_one_of_value, forward, fd, slash-mode shift hooks, or initialization/reset semantics. Fng already calls forward(1.0), so fixing its movement behavior is not a neutral cleanup.
  4. Agree on custom-state registration and public/internal API boundaries before refactoring their implementation or publishing them as stable guarantees.