gha-expression-proof 1.0.0

GitHub Actions expression evaluator and receipt generator for offline CI compatibility testing
Documentation
# gha-expression-proof Specification

## Goal

`gha-expression-proof` evaluates GitHub Actions expressions in offline tools. It is designed to sit between event fixture generation (`gha-eventsmith`) and workflow execution (`ci-forge`) so expression behavior can be tested and explained independently.

The implementation follows GitHub's Actions expression documentation:

- <https://docs.github.com/en/actions/reference/workflows-and-actions/expressions>
- <https://docs.github.com/en/actions/reference/workflows-and-actions/contexts>

## Commands

### `eval`

Evaluates one expression and emits a receipt.

```powershell
gha-expression-proof eval --expr "github.ref == 'refs/heads/main'" --github-context github-context.json
```

`--if-condition` applies GitHub's default status behavior for workflow `if:` fields: if the expression does not contain `success()`, `failure()`, `cancelled()`, or `always()`, the result is treated as `success() && <expr>`.

### `template`

Interpolates every `${{ ... }}` expression in a template string or template file.

```powershell
gha-expression-proof template --template "build-${{ github.sha }}" --github-context github-context.json
```

## Context Loading

- `--context <PATH>` loads a root context object. Keys become top-level expression contexts.
- `--github-context <PATH>` loads an Eventsmith-style `github-context.json` as the `github` context.
- `--event <PATH>` injects a JSON event payload into `github.event`.
- `--context-file NAME=PATH` loads one named JSON context.
- `--context-json NAME=JSON` loads one named inline JSON context.
- `--workspace <DIR>` enables `hashFiles()`.

## Value Semantics

- Missing properties resolve to an empty string.
- String equality is case-insensitive.
- `&&` and `||` short-circuit and return operand values, matching the common GitHub Actions ternary pattern.
- Truthiness follows the documented falsy set: `false`, `0`, `-0`, empty string, and `null` are falsy; arrays and objects are truthy.
- Object filters map over arrays and object values, enabling expressions like `github.event.issue.labels.*.name`.
- `hashFiles()` sorts matched file paths and returns a deterministic SHA-256 digest, or an empty string when nothing matches.

## Supported Functions

| Function | Notes |
| --- | --- |
| `contains(search, item)` | Case-insensitive string containment or array membership. |
| `startsWith(search, item)` | Case-insensitive string prefix check. |
| `endsWith(search, item)` | Case-insensitive string suffix check. |
| `format(template, ...)` | Supports `{0}` placeholders and escaped `{{` / `}}`. |
| `join(array, separator)` | Joins arrays after string coercion. |
| `toJSON(value)` | Pretty-prints JSON. |
| `fromJSON(value)` | Parses a JSON string into a typed value. |
| `hashFiles(patterns...)` | Offline workspace hashing. |
| `success()` | True when `--job-status success`. |
| `failure()` | True when `--job-status failure`. |
| `cancelled()` | True when `--job-status cancelled`. |
| `always()` | Always true. |
| `case(predicate, value, ..., default)` | Lazy conditional helper documented by GitHub. |

## Compatibility Promise

For the 1.x series:

- Receipt `schema_version = 1` remains backward compatible.
- Existing command-line flags keep their meaning.
- New functions or receipt fields may be added when they do not break existing consumers.
- Evaluation failures remain receipt-backed and exit nonzero.