# 0.28.48 — Evolution Gate Auth Injection

## What Changed

Four built-in gate scripts that call the local Instar HTTP API now receive an
`$INSTAR_AUTH_TOKEN` environment variable when the scheduler runs them, and
send `Authorization: Bearer $INSTAR_AUTH_TOKEN` with their curl requests.

Affected gates: `evolution-proposal-evaluate`, `evolution-proposal-implement`,
`evolution-overdue-check`, `insight-harvest`.

Behind it: `JobScheduler.runGateAsync()` now builds a per-call env object,
merging `process.env` with `INSTAR_AUTH_TOKEN` when `scheduler.authToken` is
configured. `JobSchedulerConfig` gained an optional `authToken` field, wired
up from `instar.json` via `Config.ts`.

## Why

Three evolution jobs (`evolution-proposal-evaluate`,
`evolution-proposal-implement`, `evolution-overdue-check`) plus insight-harvest
were silently failing every gate check: they curled a localhost endpoint,
`authMiddleware` returned 401, and the downstream `python3 -c 'json.load(...)'`
crashed on invalid JSON. The job was then skipped — every cycle, no error
surface, no telemetry signal other than "this job never does anything."

The research cluster
`cluster-evolution-pipeline-jobs-permanently-skip-gate-scripts-missin` traced
this to the missing Authorization header and proposed the env-var injection
pattern.

## Side-Effects Review

### Intended
- Gates that depend on authenticated localhost endpoints now succeed when an
  `authToken` is configured.
- Four evolution-pipeline jobs begin firing actual work on next scheduler tick.

### Unintended — Risks Considered

**Env leak.** The auth token is exposed to gate shell commands via environment
variable. Any gate command inherits it. Gate commands are defined in
`src/commands/init.ts` (built-in) or `instar.json` (user-defined). In a
single-user local deployment the scope is identical to `process.env` — a gate
already has full shell access to the machine. No elevation.

**Gates that don't need auth.** Unaffected. The env var is present but unused
when the gate doesn't reference it. Curl without a bearer header still hits
allowlisted endpoints (`/health`, `/ping`) without issue.

**Configs without authToken.** The env var is not set. Gates that reference
`$INSTAR_AUTH_TOKEN` send `Authorization: Bearer ` (empty bearer), which
`authMiddleware` treats as unauthorized — same as before. No regression, no
new failure mode. Public-mode deployments still work because they don't have
`authToken` configured and the server doesn't require one.

**Token visibility in process listings.** `ps -eE` on Linux can expose
environment variables of running processes. The token is only present in the
gate child process for the duration of the gate (<10s, enforced by timeout).
The same token is already in `instar.json` on disk; `ps` leakage is a lesser
exposure than filesystem read.

### Not Unintended
- No breaking change for users without `authToken` configured.
- No schema migration — `JobSchedulerConfig.authToken` is optional.
- No change to gate timing, retry semantics, or failure-handling.
- No change to non-gate code paths (the token is only injected in
  `runGateAsync`, not in `runCommandAsync` or the main job command execution).

## Compatibility

- Backwards compatible. Existing `instar.json` without `authToken` unchanged
  behavior.
- Forwards compatible. When `instar init` runs, it generates `instar.json`
  with a fresh `authToken`, so new installations work out of the box.

## Verification Artifacts

- Build: `npm run build` — passes (tsc clean + manifest regenerated).
- Tests: `npm test -- JobScheduler.test.ts` — 47 tests pass including 2 new:
  1. Gate sees `token=<configured-value>` when `authToken` is set.
  2. Gate sees empty `token=` when `authToken` is unset.
- Manual: built-in manifest shows 4 updated gate definitions with the
  Authorization header.

## Summary of New Capabilities

Evolution pipeline jobs and insight-harvest now run to completion when an
auth token is configured — which is the default post-`instar init` state.
Previously-silent failures become visible work. No new user-facing commands
or config fields beyond the documented optional `authToken`.
