hen 0.23.0

Run protocol-aware API request collections from the command line or through MCP.
Documentation
# Missing Assertion Literal Plan

## Decision

- Canonical syntax: `^ & body.Item == missing`
- Also support inequality: `^ & body.Item != missing`
- Reuse the existing internal missing-path state in the assertion engine instead of adding a new runtime concept.
- Do not overload `===`.
- Do not add `undefined` in the first slice unless a compatibility need shows up later.

## Goal

Add a first-class `missing` literal for assertion comparisons so authors can explicitly assert that a response path is absent, while preserving the existing distinction between `missing` and `null`.

## Scope

This slice should cover:

- parser/runtime support for `missing` in assertions and guards
- focused runtime and verify coverage
- root docs and website docs
- at least one dedicated example
- VS Code hover/completion docs for the new literal

This slice should not cover:

- any `=== MISSING` special case
- an `undefined` alias
- changes to JSON literal parsing or schema declarations

## Implementation Plan

### 1. Assertion parser and runtime

Primary file: `src/request/assertion.rs`

Planned changes:

- Add a dedicated parse branch for bare `missing` before the current bare-word variable fallback.
- Map that branch onto the existing internal missing-path representation already used in mismatch reporting and `null` differentiation.
- Keep `==` and `!=` semantics unchanged; this should be a new literal, not a new operator.
- Ensure guarded assertions like `[ & body.user.avatar == missing ]` behave consistently with ordinary comparisons.
- Leave bare `undefined` on the existing variable-resolution path for now.

Why this seam:

- The runtime already distinguishes `Missing` from `null`; the missing piece is syntax, not evaluation machinery.
- Reusing the internal value avoids new comparison rules, new report shapes, and new error text.

### 2. Test coverage

Primary file: `src/request/assertion.rs`

Add focused unit coverage for:

- `^ & body.value == missing` passes when the field is absent
- `^ & body.value != missing` passes when the field is present
- `missing` stays distinct from `null`
- guard expressions can use `missing`
- bare `undefined` still resolves as a variable and is not treated as a literal

Add one verify-facing regression if needed in `tests/verify_cli.rs` to lock in that `hen verify` accepts the new literal and reports other assertion errors normally.

### 3. Root docs

Files:

- `syntax-reference.md`
- `README.md`

Planned updates:

- Expand the typed-literal wording from `true`, `false`, and `null` to include `missing`.
- Document that `missing` means the selected response path does not exist, and that it is different from `null`.
- Add one short example showing both cases:
  - `^ & body.deletedAt == null`
  - `^ & body.archivedAt == missing`
- Clarify that `===` remains schema/scalar validation only.

### 4. Website docs

Primary file:

- `website/docs/reference/captures-and-assertions.md`

Audit targets:

- `website/docs/reference/json-selection.md`
- any recipe page that discusses missing-vs-null behavior

Planned updates:

- Mirror the root assertion docs and add `missing` to the typed-literal explanation.
- Add a short note that missing paths are preserved distinctly during evaluation.
- Include one concrete absence assertion example.
- Update any wording that currently implies `null` is the only built-in absence-like comparison surface.

### 5. Examples

Preferred approach:

- Add a dedicated example file, likely `examples/missing_assertions.hen`.

Why a new example:

- The current open example `examples/map_request.hen` is about mapped requests, not path absence.
- A dedicated file keeps the missing-vs-null distinction easy to discover and avoids bending another example away from its main teaching goal.

Example should demonstrate:

- a field that is explicitly `null`
- a field that is absent
- `== missing`
- `!= missing`
- one short comment explaining the distinction

### 6. VS Code extension

Primary files:

- `editors/vscode-hen/reference.js`
- `editors/vscode-hen/server/server.js`
- `editors/vscode-hen/server/completion-data.js`

Planned updates:

- Add a reference entry for `missing` so hover text explains the literal and its difference from `null`.
- Add `missing` to the hover token recognition path in `server/server.js`.
- Update the `==` / `!=` operator docs to mention `missing` alongside `null` where relevant.
- Consider adding a second assertion snippet example that expands to `^ & body.field == missing`.

Non-goal for the first slice:

- special semantic-token styling for `missing`, unless it is trivial once hover support is in place.

### 7. Validation

Runtime and parser:

- run focused assertion unit tests in `src/request/assertion.rs`
- run the adjacent verify regression if one is added

Editor:

- `cd editors/vscode-hen && npm run build`

Website:

- `cd website && npm run typecheck`
- `cd website && npm run build`

## Main Unknowns And Questions

### 1. Compatibility risk: bare `missing` becomes reserved

Today, unknown bare operands fall through to variable lookup. After this change, bare `missing` in assertions will stop meaning "variable named missing" and start meaning the literal missing state.

Mitigation:

- document the change clearly
- keep `$missing` working for explicit variable references
- add one regression test so the new reservation is intentional and stable

### 2. Whether to support `missing` in guards immediately

Recommendation:

- yes, if the parser path is shared, because it keeps assertion expressions uniform

### 3. Whether to add `undefined` as an alias later

Recommendation:

- no for the first slice
- ship one canonical word first so docs, examples, and hover text stay crisp

## Success Criteria

- `^ & body.field == missing` works
- `^ & body.field != missing` works
- `missing` remains distinct from `null`
- `===` remains untouched
- docs, website docs, and one example all show the new syntax
- VS Code hover recognizes `missing`
- focused Rust tests, website checks, and extension build all pass