# Language Functionality Audit

Audit date: 2026-11-01

This audit reviews the implemented Craft++ language/runtime surfaces and the
checks available in this workspace. It records concrete defects fixed during
the audit and separates passing tests from behavior that could not be exercised
here. A passing Craft++ test does not establish full BYOND DM compatibility.

## Areas reviewed

| Area | Review and result |
|---|---|
| Lexer, parser, and compiler validation | The compiler validation executable ran 103 checks with no failures. The supported grammar remains Craft++'s indentation-based grammar; the compatibility matrix records DM syntax that is still partial. |
| Type paths and inheritance | Added `TypeRegistry.IsSubtypeOf()` for declared and unmaterialized slash paths. Native type checks now use inheritance for mob/client/vector/matrix/icon/sound/savefile/atom families, spatial indexing, location hooks, and network replication. Regression coverage checks custom paths that inherit from built-ins. |
| Built-in global and type APIs | Headless parity smoke passed: 182/182 global procedure names, 279/279 documented modern type fields, and 162/162 type-procedure names are registered. This checks routing/surface registration, not every argument and side-effect combination. |
| Runtime built-ins | In-process runtime validation ran 102 checks with no failures. The additional parity-audit test requiring xUnit output was skipped by the local in-process runner. |
| Lists and vectors | Fixed `newlist(n, ...)` to allocate nested lists and fixed object `Remove()` to remove one matching entry, matching global `Remove()` behavior. The smoke check covers negative and multidimensional sizes, vector mutation/copy, and list mutation. |
| Client and mob values | Client state remains per instance. Mob/client assignment is bidirectional and now works for custom types inheriting from `/mob` or `/client`. |
| Database query types | `/database/query` now inherits from `/database`; database dispatch uses type inheritance boundaries rather than string-prefix matching. |
| World, movement, and spatial behavior | Built-in subtype classification now follows declared inheritance for movement, turf lookup, bounds filtering, viewers, location hooks, and map replication. Runtime validation passed its spatial and movement checks. |
| Interpreter and IR VM dispatch | Both execution paths route native object methods through the shared dispatcher, preserving user-defined method precedence. IR now binds formal and named parameters, preserves supplied `args`, normalizes no-return proc calls to `null`, and resolves inherited methods from their declaring type. Broader differential coverage is still partial. |
| IDE and external services | The Windows-targeted IDE build is the UI compilation check. Live TCP listener, TLS, and host DLL behavior depend on OS/network/host permissions; several listener tests could not run in this sandbox. |

## Verification results

- Headless Release build: succeeded.
- Windows-targeted Release/IDE build: succeeded with 0 errors. Build warnings are the unavailable NuGet vulnerability endpoint (`NU1900`) and an existing `RemoteUpdater` entry-point warning (`CS8892`).
- Headless parity smoke: passed; reports 182/182 procedures, 279/279 modern type fields, and 162/162 type procedures registered.
- Runtime validation facts invoked in-process: 102 passed, 0 failed, 1 skipped.
- Main test facts invoked in-process: 835 passed, 4 failed due to denied local socket creation, 1 skipped because the custom runner does not expand one `MemberData` case. The four socket-dependent failures were `OpenPortAnyStartsManagedServerAndPublishesItsPort`, two `RemoteGameplayTests`, and `TcpTransportHardeningTests.ServerRaisesDisconnectedExactlyOnce`.
- The normal VSTest runner also aborts before execution because its own local TCP socket is denied by the environment.
- Compiler validation: 103 passed, 0 failed.

Latest audit checkpoint (Phases 17–50): headless Release build succeeded with
0 errors. Five focused regression cases for target-walk speed, `get_steps_to()`
distance limits, invalid step directions, tile-locked vector movement, and
tile-locked direct `Move()` all passed. This is targeted verification, not a
full-suite or BYOND differential run.

## Remaining scope

The compatibility matrix remains authoritative for known partial or missing
language/runtime behavior. Important unfinished areas include exact DM coercion
and error semantics, complete list and control-flow behavior, lifecycle and
tick scheduling, full BYOND resource/UI behavior, broader interpreter/IR
differential tests, and BYOND network protocol compatibility. The registration
counts above must not be read as complete behavioral coverage.

## Follow-up: IR procedure calls

The IR VM previously stored positional arguments under `param_0`, `param_1`,
while compiled procedure bodies read their declared parameter names. It also
could leave no value for a no-return proc call, and inherited source methods
were looked up under the runtime child's path rather than the method's
declaring type. The compiler now emits parameter-binding instructions; the VM
normalizes each proc call to one result (`null` on fallthrough), and inherited
method dispatch uses the declaring type. A focused IR regression covers all
three cases.

## Follow-up: named procedure arguments

The IR compiler previously emitted named arguments as assignment expressions,
which could mutate caller variables and passed values in the wrong order. Call
instructions now retain argument names as metadata; the VM binds names to
formal parameters for global and object procedures and preserves the supplied
values in `args`. A focused regression checks both procedure kinds and the
named `gradient()` built-in, including that `index = ...` does not mutate the
caller variable. Phases 1–4 below add coverage for defaults, `arglist()`
expansion, invalid names, and mixed binding. Named arguments to built-in
methods with type-specific argument normalization and broader DM call
semantics still need differential coverage.

## Built-in procedure audit cycle: phases 1–6

Each phase names one independently checked runtime contract. BYOND behavior is
checked against its DM Reference and Dream Maker guide; names listed by the
reference are not treated as proof of matching behavior.

1. **Procedure defaults:** IR now evaluates a parameter default only when its
   slot was omitted, and can read earlier bound parameters. Regression checks
   omitted, positional, named, and object-proc defaults.
2. **`arglist()`:** IR expands list entries as positional values and list
   associations as named arguments for user procs, object procs, and a
   built-in that accepts named arguments. IR list construction now preserves
   `list(key = value)` associations.
3. **Named argument validation:** interpreter and IR now raise a runtime error
   when a user proc receives an unknown named argument, matching the reference.
4. **Mixed positional/named binding:** remaining positional values now bind to
   the next unfilled formal parameter in the interpreter and IR.
5. **`min()` / `max()`:** comparison now rejects incompatible scalar types,
   permits null with numbers or text, and returns a new component-wise vector
   for vector inputs. Tests cover scalar, null, error, and vector cases. The
   BYOND reference specifies these accepted categories and copy semantics;
   vector component behavior follows the documented component-wise vector
   math model.
6. **`length()`:** audited against BYOND's byte-count rule for non-ASCII text,
   list entry count, file byte length, and vector order. Existing code and
   targeted regressions agree; no change was needed.

Reference pages consulted: [named arguments](https://ref.dm-lang.org/proc/arguments/named),
[`arglist()`](https://ref.dm-lang.org/proc/arglist),
[`min()`](https://ref.dm-lang.org/proc/min),
[`max()`](https://ref.dm-lang.org/proc/max),
[`length()`](https://ref.dm-lang.org/proc/length), and the
[Dream Maker guide](https://secure.byond.com/docs/guide/guide.pdf).

7. **`rand()`:** fixed one-argument negative bounds (`rand(-N)` now includes
   values from `-N` through zero) and inclusive upper-bound overflow at
   `int.MaxValue`; focused boundary checks pass.
8. **`prob()`:** zero, negative, 100, and greater-than-100 probability
   boundaries match the reference; its existing deterministic boundary test
   passes.
9. **`abs()`:** checked the numeric-only contract and existing negative-value
   regression; no change was needed.
10. **`pick()`:** checked the variadic and list forms, including empty lists and
    associative lists; the implementation's uniform one-argument list choice
    matches the documented behavior and focused tests pass.
11. **`log()`:** fixed the two-argument order to `log(base, value)` and added a
    regression for `log(2, 8) == 3`; the one-argument form remains the natural
    logarithm.
12. **`round(pixloc)`:** implemented floor and nearest-step rounding for
    absolute pixel x/y coordinates, including a vector step, while returning a
    new pixloc and leaving the input unchanged. Focused test passes.
13. **`clamp()` scalar:** fixed a tag mismatch that made numeric scalar calls
    return the original value; the regression now asserts the exact scalar and
    list output.
14. **`clamp()` text and vector:** added ordinal text clamping and component
    clamping for vectors with scalar or vector bounds. Focused tests pass.
15. **`text2num()`:** checked decimal-prefix parsing, null on no numeric prefix,
    radix bounds, sign/prefix handling, and large radix values. Existing
    regressions cover decimal and radix prefixes, including values beyond
    64-bit integer range; no change was needed.
16. **`num2text()`:** checked significant-figure formatting, normalized DM
    exponent spelling, and radix output against the reference examples and
    existing regression coverage; no change was needed.

17. **`text2ascii()`:** confirmed the index is a one-based UTF-8 byte position,
   while the result is the decoded Unicode code point. Extended the regression
   to verify indexing after both a multibyte BMP character and a four-byte
   supplementary character; targeted test passes.
18. **`ascii2text()`:** checked Unicode support against BYOND 513 release notes
   and the current reference. Valid BMP and supplementary code points convert
   correctly, and invalid surrogate values no longer leak a host exception;
   the two focused tests pass. Invalid-codepoint output is a defensive runtime
   choice because the reference specifies valid Unicode characters, not invalid
   inputs.
19. **`params2list()` / `list2params()`:** checked form-style `+` spaces,
   percent-escaped UTF-8, `&`/`;` separators, duplicate keys becoming lists,
   and object-reference round trips against the DM Reference and guide. The
   existing duplicate/encoding and object-reference tests pass; no change was
   needed.
20. **`url_encode()` / `url_decode()`:** verified query-string space encoding
   (`+`), escaped separators, full-URL space handling (`%20`), and decode
   round-trip. All three focused cases pass; no change was needed.

21. **`Move()` under tile movement:** BYOND requires `step_x`/`step_y` to stay
   grid-aligned in `TILE_MOVEMENT_MODE` and for `TILE_MOVER` atoms. Direct
   `Move()` arguments could bypass the lock and restore pixel offsets. The
   movement commit now zeroes those offsets for tile-locked movers; regression
   covers `Move(destination, dir, step_x, step_y)` in tile mode.
22. **`pixel_x` / `pixel_y`:** confirmed they are strictly visual and do not
   affect collision or map tile position. Existing regression explicitly sets
   a large visual offset and verifies the spatial position is unchanged.
23. **`step()` speed and vector form:** confirmed optional speed is in pixels
   (zero selects `step_size`) and vector form moves by pixel deltas. Existing
   numeric speed and pixel-collision cases pass.
24. **Pixel `Move()` slide / jump:** confirmed short in-tile moves can stop at
   obstacles and report the distance moved, while blocked jumps remain atomic.
   Existing focused collision tests pass.
25. **Invalid direction to `step()` / `get_step()`:** found an invalid
   direction such as zero mapped to `(0,0)`, causing `step()` to report success
   and `get_step()` to return the starting turf. Both now reject non-compass
   directions (`0` for `step`, null for `get_step`); regression passes.

References: [BYOND Pixel movement](https://ref.dm-lang.org/notes/pixel-movement),
[`step()`](https://ref.dm-lang.org/proc/step),
[`pixel_x`](https://ref.dm-lang.org/atom/var/pixel_x),
[`movement_mode`](https://ref.dm-lang.org/world/var/movement_mode), and the
[Dream Maker guide, movement chapter](https://secure.byond.com/docs/guide/guide.pdf).

26. **Vector `step()` with tile-locked movers:** the reference says
   `TILE_MOVEMENT_MODE` and `TILE_MOVER` require movement coordinates to stay
   tile-aligned, but the vector overload bypassed that rule and allowed
   sub-tile offsets. It now snaps the vector displacement to whole tile units
   and reports failure for a zero displacement; focused partial/full-tile cases
   are added.
27. **`locs` and turf `contents`:** verified overlapping physical bounds and
   `step_x`/`step_y` cause every covered turf to list the movable atom, while
   visual `pixel_x`/`pixel_y` do not. Existing footprint, offset, and contents
   synchronization regression passes.
28. **Pixel collision bounds:** checked collision uses the mover’s physical
   bound rectangle and respects non-square world tile dimensions. Existing
   dense obstacle and rectangular tile movement cases pass.
29. **`bounds()` / `obounds()`:** verified `bounds()` includes its reference
   and `obounds()` excludes it, with pixel rectangles used for the query.
   Existing focused regression passes.
30. **Map format and icon-size geometry:** checked top-down, isometric, and
   rectangular tile sizes update default bounds and physical footprint as the
   DM reference describes. Existing regression passes.

31. **`get_steps_to()` range cap:** fixed pathfinding that expanded its search
   limit based on the target distance, allowing arbitrarily distant routes.
   BYOND returns no path beyond twice `world.view`; an unset/empty view now
   uses the documented default radius of 5. Regression checks distance 11
   fails at the default and succeeds after setting view to 6.

32. **`step_towards()` / `step_to()` / `step_away()` speed:** BYOND gives
   these routines optional pixel speed arguments, but the implementation
   discarded them before calling `step()`. They now forward speed to shared
   movement; tests assert the resulting pixel offsets for each algorithm.
33. **`step_rand()` speed:** likewise now forwards its optional pixel speed;
   a regression checks the maximum displacement is exactly the requested
   speed independent of the random direction.

34. **`walk(Ref, Vector)`:** the reference documents a repeating pixel-vector
   overload. Source inspection shows the dispatcher converts every second
   argument to an integer direction and the scheduler stores only directions;
   a vector becomes zero and cancels/no-ops. This remains a concrete movement
   gap; add vector walk scheduling and test cancellation/lag/collision.
35. **`sleep()` timing:** BYOND specifies deciseconds independent of
   `world.tick_lag`. Craft++ currently multiplies the requested count by
   `tick_lag` and calls `Thread.Sleep`, so non-default tick lag changes the
   requested wall time and blocks the executing host thread. Replace with a
   scheduler yield and decisecond timer.
36. **`spawn` execution:** BYOND copies the proc and runs the spawned block
   independently, including special `spawn(-1)` ordering. Current
   `VisitSpawnStmt` awaits the delay and body inline using the same environment;
   it blocks the caller and does not copy local vars. Requires resumable proc
   frames and variable snapshot semantics.
37. **`input()` filters and verbs:** DM input can constrain type, null/cancel,
   and choices; verb args also support these types and defaults. Current input
   callback only returns text/default and receives no type/list filter. The UI
   callback and verb dispatcher need typed filtering and return-value parity.
38. **`call_ext()` / `load_ext()`:** confirmed BYOND loads external libraries
   and defines string and Byondapi ABIs, including async calls. Craft++ only
   invokes host-registered delegates. Native loading/marshalling is missing.
39. **`/database`:** Craft++ has a typed dispatch adapter interface, but no
   default SQLite provider; real operations fail without a host adapter. BYOND
   provides SQLite-backed connections and query execution. Implement an
   adapter and verify binding, row, blob, and lifecycle behavior.
40. **`/regex`:** Craft++ uses .NET Regex while DM documents its own pattern
   syntax, stateful global `Find()`, captures, and replacement groups. Audit
   every DM flag and pattern extension; do not claim parity from basic match /
   replace tests.
41. **Savefile compatibility:** runtime storage exists, but compatibility
   still needs DM directory/buffer operators, `cd`, `Find`, nested savefiles,
   `tmp`, `Read`/`Write`, resource cache, and BYOND serialization coverage.
42. **Verb argument binding:** parser metadata and input callbacks need a full
   chain audit so declared defaults, input types, `in` lists, `src in`/`usr in`
   constraints, `set` metadata, and `args` behave the same at invocation.
43. **Core coercion/error semantics:** the language supports broad expression
   syntax, but exact DM numeric/text/null coercions, single-precision numeric
   behavior, runtime error-to-exception conversion, and `world.Error()` flow
   remain an explicit differential test gap.
44. **Preprocessor and DME build rules:** includes and conditionals exist, but
   `#pragma`, warning controls, compiler macros, source-order semantics, and
   full Dream Maker project settings/include selection remain partial.
45. **Lifecycle and async events:** the reference defines object deletion,
   proc context, Login/Logout, world startup/error, waitfor/background, and
   event-order rules. Current implementations cover slices; complete ordering,
   nested sleep, deleted-src cancellation, and `usr` propagation need tests.
46. **Maps/assets:** DMM and DMI support is useful but partial. Required work:
   full map syntax/metadata round trips, DMI state/direction/frame selection,
   icon arithmetic/effects, resource caching, and boundary/error behavior.
47. **UI/client APIs:** Craft++ editor and client controls are native Craft++
   UI. BYOND skin parsing, browser controls/JS, `winset`/`winget`, output
   routing, and exact client events still require implementation or clear
   compatibility exclusions.
48. **Network interoperability:** Craft++ transport uses its own protocol;
   BYOND wire protocol and native resource/login flows are not implemented.
   Native BYOND clients and servers cannot interoperate with current builds.
49. **Interpreter/IR differential coverage:** each supported construct and
   built-in must have paired execution checks for outputs, mutation, side
   effects, errors, and event order. Current focused coverage does not establish
   whole-language equivalence.
50. **Native compiler/artifact compatibility:** Craft++ build artifacts are
   Craft++ archives rather than Dream Maker `.dmb`/`.rsc`; brace syntax is also
   not yet established as complete Dream Maker syntax. Producing native BYOND
   artifacts requires a separate compiler/format implementation.

51. **`walk(Ref, Vector)` implemented:** the BYOND vector overload now copies
   its 2D displacement at call time, runs asynchronously through the world
   scheduler at the requested lag, cancels/replaces other walks on that atom,
   routes every move through the normal `Move` override and collision path,
   and snaps tile-locked movement to tile increments. A scheduler regression
   verifies repeated pixel displacement after the caller mutates its source
   vector. Build and targeted test passed. Remaining P0 scheduler gaps include
   nonblocking `sleep()`, `spawn(-1)`, and exact event/cancellation behavior.
   This phase also corrected the supported part of `sleep()` timing: delay is
   now a fractional decisecond value independent of `world.tick_lag`; the
   host-thread blocking and resumable-proc semantics remain unfinished.

52. **`spawn` caller and locals:** normal nonnegative spawn now schedules a
   separate task and returns to the caller. Interpreter execution context uses
   async-flow-local proc/environment state; lexical local frames are copied
   shallowly, sharing object/list references. The IR VM also copies its local
   slot dictionary. Negative delays other than `-1` execute before the caller
   continues. Focused interpreter and IR regressions pass. `spawn(-1)`, exact
   zero-delay ordering, cancellation, deleted-src behavior, and scheduler-owned
   execution remain open.
53. **Regex flags and iteration:** `/regex` now applies the DM `m` flag and
   advances successive `Find()` calls when `g` is set, retaining the explicit
   start argument. A regression covers global scanning and multiline anchors.
   DM-specific character classes/lookbehind, byte indexing, and edge behavior
   across `Find_char`, `Match`, and replacement remain unfinished.
54. **Typed `input()` choices:** the parser now recognizes
   `input(...) as Type in List` as a filtered prompt rather than an ordinary
   membership comparison. The result must match a list choice and pass the
   requested type filter; the regression verifies numeric conversion, valid
   choices, rejection of a text choice under a mob filter, and `null|num`
   cancellation. Full native UI
   selection controls and typed verb-argument metadata/dispatch remain open.
55. **Verb parameter metadata:** parsed parameter type annotations and
   `in`/`out` modifiers are now retained on `ProcStmt` rather than discarded
   in parser-only dictionaries. A regression checks type retention. The verb
   UI/dispatcher still needs to consume that metadata and build typed prompts.
56. **Global `Find_char()` iteration:** `/regex.Find_char()` now honors the
   global flag across repeated calls on unchanged text, honors an explicit
   character start position, and searches by Unicode character offsets while
   converting to .NET's UTF-16 indices internally. The regression verifies
   successive matches after a supplementary Unicode character. Broader DM regex
   pattern and byte-index compatibility remains open.
57. **BYOND map loading in the client:** Dream Maker projects use `.dmm` map
   files, but project discovery, includes, and the map editor previously only
   treated Craft++ `.cpm`/`.cmap` files as maps. `.dmm` is now recognized by
   those paths and goes through the DMM-to-runtime converter. Network client
   attachment now batches its existing replication snapshot and renders once,
   avoiding a full map redraw for every object during initial load. A focused
   regression checks a multi-row map plus a non-origin block through parsing
   and preprocessor conversion. Initial replication still only contains the
   objects the server made visible to that client.

The concrete backlog and official reference links for these findings are in
[`BYOND_DM_PARITY_MATRIX.md`](BYOND_DM_PARITY_MATRIX.md), under “Specific
remaining gaps confirmed by source and reference review.”
