# CLAUDE.md — ARIA

## What This Is

ARIA (Applied Reasoning and Insight Architecture) — an active knowledge and development discipline plugin for Claude Code. Three pillars: a five-phase knowledge lifecycle (capture → govern → promote → apply → refresh), decision discipline (Rule 22 enforcement at every edit), and codebase & task mapping (/codemap for repo traces, /stitch for cross-repo contract binding, /distill for task spec shaping). The "Applied" framing emphasizes the apply phase: trusted knowledge actively shapes the next decision via /context, /rules, /codemap, /stitch, /distill, and Rule 22 — not just stored and recalled.

**Repository:** GitHub (`mikeprasad/aria-knowledge`) — **public repo**

## Cowork Port (plugin-claude-cowork/)

The Claude Cowork port lives at `plugin-claude-cowork/` — consolidated into this repo in v2.20.0 (2026-05-24) from the previously standalone `mikeprasad/aria-cowork` (last standalone release: v1.1.0, 2026-05-19). **Current cowork release: v1.7.0** (2026-08-19, with aria-knowledge v2.46.3 — `/intake` absorbs `/clip`+`/clip-thread`+`/extract-doc` (breaking), `/audit-knowledge` gains Step 2f, `/interview` defaults to `guided`, working-rules preamble + `retrospect-patterns.md` land; 27 → 24 skills; tag `cowork-v1.7.0`, NOT marked Latest so the canonical release keeps the 6 stable aliases). Prior: v1.5.0 (2026-06-29, with aria-knowledge v2.38.0 — working-rules synced to canonical parity: added Rules 35/36/37, strengthened Rules 15/21; working-rules.md 34 → 37 rules; no skill change). Prior: v1.4.0 (2026-06-18, with aria-knowledge v2.31.0 — `/interview` skill ported, cowork-adapted; the one genuine parity gap with canonical v2.31.0, closed; summed-description cap-relief trim included). Prior: v1.3.0 (2026-06-11, with aria-knowledge v2.30.0 — `/foundational-review` + `/readiness-audit` ported; 2 audit aliases removed for cap relief). Prior: v1.2.0 (2026-06-10, with aria-knowledge v2.28.0 — `snap` mode parity; tag `cowork-v1.2.0` + GH release w/ `.plugin` asset). Prior: v1.1.5 (2026-06-04, with aria-knowledge ~v2.24.x — `/index` ephemeral-tag exclusion + `/wrapup` picker fix). Prior: v1.1.4 (2026-05-29, with aria-knowledge v2.20.3 — Opus 4.8 readiness: `working-rules.md` `Why` clause de-versioned, mirroring plugin-claude-code; Cowork is skills-only so the v2.20.3 hook hardening does not apply here). Prior coordinated cowork release: v1.1.3 (2026-05-25, with aria-knowledge v2.20.2 — wrapup/handoff spec fixes: closing-heading labeling correction + auto-mode extract-always-runs invariant). Both ports share the user's `~/Projects/knowledge/` folder and write to the same canonical config (`aria-config.md`) under an additive-only schema (per ADR-002). Edits to shared surfaces — `aria-config.md` field names, `template/rules/` content, `working-rules.md` rule numbering — must preserve cross-port compatibility. 27 skills (27 distinct; v1.3.0 removed the 2 aliases, v1.4.0 added `/interview`). Cowork-specific authoring constraints documented in `knowledge/guides/claude/cowork-plugin-validation.md`. **Cowork-specific release constraint**: aria-cowork release.sh enforces a 9000-char hard cap on summed SKILL.md description chars (empirical install-fail at 9233, documented v0.2.1 + v1.0.0); v2.20.1's trailing-parenthetical port-id uses a short form on cowork (`(Cowork variant — namespaced-only.)` ~36 chars) versus Code's verbose form (~96 chars), with the full ADR-094 narrative in the Runtime Gate body where no cap applies.

**Bidirectional feature flow (since v0.3.0 / v2.17.0):** Features may originate in either port and port to the other; plugin-claude-code remains the schema source-of-truth (output formats, knowledge-folder conventions, archive structures). v0.3.0's `/handoff brief` and `/intake doc` modes are the first cowork-originated features ported into aria-knowledge. See plugin-claude-cowork ADR-014 for the architectural rationale.

**Bare-slash ownership (ADR-094, v2.19.1):** When both ports are loaded in the same session (most common in Claude Desktop), 24 colliding skill names (`/handoff`, `/wrapup`, `/extract`, `/intake`, etc.) deterministically resolve to **plugin-claude-code** as canonical owner. plugin-claude-cowork's variants are namespaced-only (`/aria-cowork:handoff`, etc.). Each colliding skill carries a Runtime Gate in its body that surfaces a notification when invoked from the wrong runtime (Bash-availability is the fingerprint). The gate applies even in `auto` modes — auto's "implicit-yes" rule is suspended for the runtime-mismatch check per ADR-094 §Part 3. Edits affecting cross-port compatibility (description prepend conventions, gate clause text, anti-trigger language) should preserve this ownership rule. Full design: [`~/Projects/knowledge/projects/aria/decisions/094-bare-slash-canonical-owner-and-dual-runtime-gate.md`](../../knowledge/projects/aria/decisions/094-bare-slash-canonical-owner-and-dual-runtime-gate.md).

## Cursor Port (plugin-cursor-template/)

The Cursor port is a **repo skeleton** (not a Claude marketplace plugin). Users unzip `aria-knowledge-cursor-<version>.zip` into the root of their own project. **Current Cursor release: `2.46.2-cursor.0`** (2026-08-19, parity with plugin-claude-code v2.46.2; `.mdc` verified by recompiling `port-skills-to-mdc.py` and reproducing the committed files byte-for-byte). Prior: `2.30.0-cursor.0` (2026-06-11, parity with v2.30.0). Prior: `2.24.2-cursor.0` (2026-06-04, statusline-only alignment).

**What ships:** `.cursor/hooks.json`, `.cursor/rules/*.mdc` (5 compiled rule files), `.cursor/aria-knowledge.local.md`, root `AGENTS.md` (Cursor's equivalent of `CLAUDE.md`), `scripts/aria/*.sh`, and a root-level `knowledge/` mirror of `plugin-claude-code/template/`.

**Skill surface (27 commands in `aria-commands.mdc` + audits in `aria-audit.mdc`):** 22 core workflow commands + 3 aliases (documented in preambles) + 5 MCP-consuming skills (`/clip-thread`, `/extract-doc`, `/meeting-notes`, `/digest`, `/sync-decisions`) + `/help` + `/audit-share`. Includes v2.17.0 `/intake doc`, v2.20.2 wrapup/handoff auto-mode `/extract` invariants.

**Intentional Cursor divergences (do not port ADR-094 Runtime Gates per-skill):** aria-cowork is not loaded in typical Cursor sessions. A single preamble note in `aria-commands.mdc` replaces per-skill gates. Rule 22 uses an edit-intent marker (`record-edit-intent.sh`) — advisory `beforeFileEdit`, no transcript proof. No PreCompact; `stop` → `capture-task-boundary.sh` substitutes. MCP servers are user-configured in **Cursor Settings → MCP** (no bundled `.mcp.json` in the template). See `plugin-cursor-template/PORTING.md` and `plugin-cursor-template/audit/ARIA_CURSOR_AUDIT_REPORT.md` §5.

**Maintainer re-sync after canonical skill edits:**

```bash
python3 plugin-cursor-template/scripts/port-skills-to-mdc.py
./release-cursor.sh
```

`port-skills-to-mdc.py` strips Runtime Gate blocks, adapts paths (`AGENTS.md`, `.cursor/aria-knowledge.local.md`), and upserts MCP skill sections idempotently.

## Codex Port (plugin-openai-codex/)

The OpenAI Codex port lives at `plugin-openai-codex/` — an independent installable adapter that uses the shared ARIA knowledge folder and content schema while diverging on plugin manifest shape, hook registration, and tool-boundary behavior for Codex. **Current Codex release: `2.46.4-codex.0`** (2026-08-20; content parity with canonical, port suite 24/24. ⛔ Three canonical `post-*-check.sh` scripts were shipped here unwired and are REMOVED — Codex routes every hook through `bin/codex-hook.py`, which already inlines them as `tautology_message()`, `auto_prospect_message()` and `auto_retrospect_message()`. Do NOT re-copy them on a parity sync; see `PORTING.md`.) Prior: `2.30.0-codex.0` (2026-06-11, parity with v2.30.0 where Codex has an equivalent runtime surface). Wires MCP servers via `.mcp.json` (Codex manifest convention uses `mcp_servers` snake_case key vs. Claude's `mcpServers` camelCase — both are correct for their target runtime). Strips ADR-094 Runtime Gate sections from ported skills (gates are Bash-availability-fingerprint-dependent and don't fire in Codex). Ships `/foundational-review` + `/readiness-audit` with the bundled canonical process doc; keeps `/statusline` and `/aria-assist` as explicit non-equivalents for now (no Codex statusline/usage payload, no bundled launchd/headless scheduler path). Ships a port-specific test suite at `plugin-openai-codex/tests/run.sh` that release-codex.sh gates on (skills carry codex metadata, no ADR-094 gates leaked through, review skills present, `apply_patch` denial shape current, transcript reader doesn't scan without `turn_id`).

**Build with** `./release-codex.sh` from repo root. Reads version from `plugin-openai-codex/.codex-plugin/plugin.json` (single source of truth, strips `-codex.N` suffix for filename). Produces `aria-knowledge-codex-<canonical>.zip` + version-stable `aria-knowledge-codex.zip`. Verification gates: Codex port tests, port-drift report-only gate, MCP manifest present, `tests/` excluded from artifact, no junk, clean zip rebuild before archive creation.

## Antigravity Port (plugin-antigravity/)

The Antigravity IDE port lives at `plugin-antigravity/` — targets **Antigravity IDE** (VS Code fork) and **Antigravity CLI** (`agy`) from Google's Antigravity team. **Current Antigravity release: `2.46.2`** (2026-08-18, parity with plugin-claude-code v2.46.2; skill set identical to canonical's 36). Prior: `2.20.2` (2026-05-28, parity with v2.20.2; same-day refresh added native workflow + rules scaffolding and expanded plugin.json — commit `f635e61`). The setup skill's **Step 7ca** scaffolds `.agents/workflows/` (10 thin-shim workflows) and `.agents/rules/aria-rules.md` into the user's workspace, enabling **true native slash-command invocation** (`/setup`, `/handoff`, `/wrapup`, `/extract` fire as first-class Antigravity workflows) and **native Always-On rule enforcement** — distinct from Claude Code's hook-based enforcement model.

**Version sources (two, kept in sync by the maintainer):** `plugin-antigravity/plugin.json` carries the full standard plugin manifest including a `version` field (Antigravity's manifest schema ignores unknown fields, and the standard plugin shape is now used here for parity with sibling ports). `plugin-antigravity/version.txt` is a sidecar that `build.sh` auto-syncs from canonical `plugin-claude-code/.claude-plugin/plugin.json` — `bin/` scripts and the setup skill read from the sidecar. **Maintainer responsibility:** when bumping canonical version, also hand-bump `plugin-antigravity/plugin.json`'s `version` field. `build.sh` auto-syncs `version.txt` but does NOT touch `plugin.json` (it's in the preserved hand-authored files list per `build.sh` line 284). Candidate for `build.sh` automation later — flag as follow-up if the manual two-step becomes a friction point.

**Custom setup behavior is preserved via the overlay pattern.** `build.sh` (lines 120-145) copies canonical skills from `plugin-claude-code/skills/`, then applies `plugin-antigravity/overlays/skills/<name>/SKILL.md` overlays LAST — so port-specific bodies survive canonical resyncs. ⛔ **CORRECTED 2026-08-26 — this said "the setup skill currently has an overlay snapshot at `plugin-antigravity/overlays/skills/setup/SKILL.md` (byte-identical to the live file)". That file DOES NOT EXIST and there is no evidence it ever did.** Measured: `overlays/skills/` holds exactly three entries — `audit-config`, `audit-knowledge`, `snapshot`. So canonical's `setup/SKILL.md` flows straight through to this port with only the uniform path substitution applied, and there is no port-specific setup body to protect.

⚠ **Why that false claim mattered, and it is not a trivia correction.** It reads as "antigravity's setup is insulated from canonical", which is the opposite of true, and it was load-bearing while adding a Claude-Code-only step to canonical `/setup`: the natural fix looked like "edit the overlay", and there was none to edit. Creating one would have frozen antigravity's setup against every future canonical change — and its own drift detection is admitted future-work. The step was instead made **self-gating** on hook registration, which needs no overlay and is correct in every port. **Do not restore the overlay claim, and prefer a self-gating canonical step over a new overlay** unless a port genuinely needs a divergent body.

**Two-script model** (different from sibling ports' one-script model):
1. `plugin-antigravity/build.sh` — *regenerates* port content from canonical sources (copies skills from `plugin-claude-code/skills/`, applies overlays from `plugin-antigravity/overlays/`, syncs `version.txt`, patches setup/SKILL.md paths). Run when canonical sources change.
2. `release-antigravity.sh` (at repo root) — stages regenerated port content with junk exclusions and emits `aria-knowledge-antigravity-<version>.zip` + version-stable copy.

**Zip structure is flat (no top-level wrapper dir).** This differs from claude-code/codex/cursor zips which nest content under a plugin-name wrapper, matching Antigravity IDE's install machinery. `release-antigravity.sh` verifies this invariant (`wrapper` count must be 0).

## Project Structure

```
aria/
├── README.md          ← GitHub-facing intro
├── LICENSE            ← CC BY-NC-SA 4.0
├── CHANGELOG.md       ← Version history
├── CLAUDE.md          ← You are here
├── plugin-claude-code/            ← The installable plugin
│   ├── .claude-plugin/
│   │   └── plugin.json
│   ├── bin/           ← Hook scripts (bash)
│   ├── skills/        ← Skill definitions (SKILL.md files)
│   └── template/      ← Knowledge folder templates
├── plugin-openai-codex/      ← Codex port (independent installable unit)
│   ├── .codex-plugin/
│   │   └── plugin.json
│   ├── hooks.json     ← Codex hook registration
│   ├── bin/           ← Claude-standard scripts + Codex adapter
│   ├── commands/      ← Codex command entrypoints
│   ├── skills/        ← Copied ARIA skills (schema-compatible)
│   └── template/      ← Copied Claude-standard knowledge templates
├── plugin-claude-cowork/     ← Cowork port (skills-only; no hooks API in Cowork runtime)
│   ├── .claude-plugin/
│   │   └── plugin.json
│   ├── skills/        ← 26 skills (24 distinct + 2 aliases)
│   ├── template/      ← Knowledge folder templates (schema mirror of plugin-claude-code/)
│   ├── .mcp.json      ← 12 MCP servers across 4 categories
│   └── release.sh     ← Builds aria-cowork-<version>.plugin
├── plugin-cursor-template/   ← Cursor port (repo-skeleton, not a plugin install)
│   ├── .cursor/       ← Cursor-native config
│   │   ├── hooks.json
│   │   ├── aria-knowledge.local.md
│   │   └── rules/     ← 5 compiled .mdc files (27 commands in aria-commands + audits)
│   ├── AGENTS.md      ← Cursor's equivalent of CLAUDE.md (ships to user projects)
│   ├── QUICKSTART.md  ← Cursor-adapted quickstart
│   ├── PORTING.md     ← Maintainer drift tracking + skill→.mdc map
│   ├── knowledge/     ← Knowledge folder (hoisted to root, not under template/)
│   ├── scripts/aria/  ← Hook scripts (instead of bin/)
│   │   └── VERSION    ← Port version (e.g. 2.20.2-cursor.0)
│   ├── scripts/port-skills-to-mdc.py  ← Re-sync from plugin-claude-code/skills/
│   └── audit/         ← Frozen audit artifacts (2.16.1 baseline; see PORTING.md for current)
├── plugin-antigravity/         ← Antigravity IDE / CLI port (flat-zip install)
│   ├── plugin.json   ← Manifest (no version field per Antigravity docs)
│   ├── version.txt   ← Port version sidecar (source of truth — synced by build.sh)
│   ├── mcp_config.json
│   ├── hooks.json
│   ├── bin/          ← Canonical bin scripts + Antigravity adapter (bin/antigravity/)
│   ├── skills/       ← Regenerated from canonical via build.sh
│   ├── template/     ← Regenerated from canonical via build.sh
│   ├── overlays/     ← Per-skill overrides applied by build.sh
│   ├── build.sh      ← Regenerates port content from canonical sources
│   └── tests/        ← Port test suite (smoke + structural)
├── RELEASING.md                ← Build→publish flow + stable-alias asset contract (read before cutting a release)
├── publish-release.sh          ← Attaches all 6 stable aliases to the canonical release so site /latest/ links resolve
├── release.sh                  ← Builds claude-code zip (canonical)
├── release-codex.sh            ← Builds codex zip
├── release-cursor.sh           ← Builds cursor zip
├── release-antigravity.sh      ← Builds antigravity zip (flat layout)
└── docs/              ← Extended documentation (future)
```

## Key Conventions

- **`plugin-claude-code/` is the installable unit** — everything inside it is what users copy to their plugins directory
- **`plugin-openai-codex/` is the Codex installable unit** — independent adapter surface, same knowledge schema. Claude `plugin-claude-code/` remains the standard for template/content shape.
- **`plugin-cursor-template/` is the Cursor repo-skeleton** — not a plugin install. Users clone or unzip its contents into the root of their own project. Cursor compiles 29 commands (24 core + 5 MCP) into 5 `.cursor/rules/*.mdc` files because Cursor's Rules system doesn't have a one-skill-per-folder concept. Port version tracks canonical via `scripts/aria/VERSION` (currently `2.30.0-cursor.0`). Maintainer re-sync: `python3 plugin-cursor-template/scripts/port-skills-to-mdc.py`. ADR-094 Runtime Gates are omitted in Cursor. Knowledge folder schema stays compatible with `plugin-claude-code/template/`.
- **Template files** in `plugin-claude-code/template/` are either plugin-managed (diffable on `/setup`) or user-owned (created once, never overwritten). See `plugin-claude-code/skills/setup/SKILL.md` for the authoritative list.
- **Version** lives in `plugin-claude-code/.claude-plugin/plugin.json`
- **Hook scripts** in `plugin-claude-code/bin/` are bash — they read config from `~/.claude/aria-knowledge.local.md`
- **Skills** are markdown files — each skill is a `SKILL.md` with YAML frontmatter
- **Codex hooks** require Codex `plugin_hooks` enabled; the adapter reads `~/.codex/aria-knowledge.local.md` first, then falls back to `~/.claude/aria-knowledge.local.md`
- **`plugin-claude-cowork/` is the Claude Cowork installable unit** — sibling to plugin-claude-code/, both share schema-identical knowledge-folder outputs (per ADR-013). Cowork runtime is skills-only (no hooks API); enforcement is skill-embedded. Per ADR-094, bare-slash skill names resolve to plugin-claude-code as canonical owner when both ports are loaded in the same session; cowork-namespaced variants are `/aria-cowork:handoff` etc.
- **Cursor hooks** use `.cursor/hooks.json` and resolve script paths via `git rev-parse --show-toplevel`. Some Claude enforcement is weaker on Cursor (no transcript access, no documented pre-edit deny) — port uses an edit-intent marker file as the closest available mechanism. See `plugin-cursor-template/audit/ARIA_CURSOR_AUDIT_REPORT.md` §5.
- **`plugin-antigravity/` is the Antigravity IDE/CLI installable unit** — independent port targeting Google's Antigravity IDE (VS Code fork) and `agy` CLI. **Two version sources**: `plugin.json` carries the standard plugin manifest including `version` (Antigravity ignores unknown manifest fields); `version.txt` sidecar is auto-synced by `build.sh` from canonical and read by `bin/` scripts. Maintainer must hand-bump `plugin.json` on canonical bumps (`build.sh` preserves it). Two-script build model: `plugin-antigravity/build.sh` regenerates port content from canonical sources + applies overlays at `overlays/skills/<name>/SKILL.md`; `release-antigravity.sh` (repo root) zips. Zip layout is **flat** (no top-level wrapper dir) vs. sibling ports' wrapped layout. Setup skill's **Step 7ca** scaffolds Antigravity-native `.agents/workflows/` + `.agents/rules/` so slash commands fire as first-class workflows.

## Development Workflow

1. Edit files in `plugin-claude-code/`
2. To test, copy `plugin-claude-code/` to `~/.claude/plugins/marketplaces/local-desktop-app-uploads/aria-knowledge/`
3. Restart Claude Code to pick up changes

### Codex Port Workflow

1. Edit Codex adapter files in `plugin-openai-codex/`
2. Keep durable knowledge template/schema changes in sync with `plugin-claude-code/` — Claude remains the schema standard
3. Enable Codex plugin hooks with `codex features enable plugin_hooks` before testing automatic hooks
4. Install via `.agents/plugins/marketplace.json` or copy `plugin-openai-codex/` into a Codex local marketplace

### Cursor Port Workflow

1. Edit canonical skills in `plugin-claude-code/skills/` first (schema source-of-truth), then re-sync the Cursor port:
   ```bash
   python3 plugin-cursor-template/scripts/port-skills-to-mdc.py
   ```
2. Keep durable knowledge surfaces in sync with `plugin-claude-code/template/` — apply the same edits to `plugin-cursor-template/knowledge/` (root-level, not nested under `template/`). See `plugin-cursor-template/PORTING.md` §A for the lockstep file list.
3. The 5 `.mdc` rule files are *compiled* views of canonical `SKILL.md` bodies. `port-skills-to-mdc.py` refreshes `aria-commands.mdc` (core + MCP skills, wrapup/handoff patches, `/help` table) and strips ADR-094 Runtime Gates. Hand-edit `aria-audit.mdc`, `aria-context.mdc`, `aria-core.mdc`, or `aria-rule-22.mdc` when those surfaces change outside the scripted path.
4. Bump `plugin-cursor-template/scripts/aria/VERSION` (`<canonical>-cursor.0`) and run `./release-cursor.sh` from repo root. Zip: `aria-knowledge-cursor-<canonical>.zip`.
5. Users install by unzipping the artifact into the root of their own project, then restarting Cursor. End-user doc: `plugin-cursor-template/QUICKSTART.md`; project instructions file: `AGENTS.md` (not repo-root `CLAUDE.md`).

### Cowork Port Workflow

1. Edit Cowork-specific files in `plugin-claude-cowork/`. Most skills mirror `plugin-claude-code/` via ADR-013 schema-identical outputs; cowork-specific skills (`daily-audit`, cowork-modified `/extract-doc`, etc.) live only here.
2. Keep MCP-consuming skills (clip-thread, extract-doc, meeting-notes, digest, sync-decisions) byte-faithful between ports per ADR-014; plugin-claude-code remains schema source-of-truth.
3. Per ADR-094, when both ports load in the same session, bare-slash command names (`/handoff`, `/extract`, etc.) resolve to plugin-claude-code as canonical owner; cowork-namespaced variants are `/aria-cowork:handoff` etc.
4. Build with `./release.sh` in `plugin-claude-cowork/` — produces `aria-cowork-<version>.plugin`. Install by dragging into a Cowork conversation or via Settings → Plugins → Install from file.
5. Cowork runs as a skills-only plugin (no hooks API). The `/daily-audit` skill substitutes for SessionStart on first message.

### Antigravity Port Workflow

1. Edit canonical skills in `plugin-claude-code/skills/` first (schema source-of-truth). For Antigravity-specific adapter behavior, edit hand-authored files preserved by build.sh: `plugin.json`, `hooks.json`, `mcp_config.json`, `GEMINI.md`, `bin/antigravity/*`, `PORTING.md`, `README.md`, `SMOKE-TEST.md`. Place per-skill overrides in `plugin-antigravity/overlays/`.
2. Regenerate port content from canonical sources:
   ```bash
   ./plugin-antigravity/build.sh
   ```
   This copies skills/template from `plugin-claude-code/`, applies overlays, syncs `version.txt` from the canonical `plugin.json` version, and patches setup/SKILL.md to read version from the sidecar instead of JSON.
3. Bump `plugin-claude-code/.claude-plugin/plugin.json` version first (canonical), then re-run `build.sh` — `version.txt` syncs automatically. **Also hand-bump `plugin-antigravity/plugin.json`'s `version` field** — it's in build.sh's preserved hand-authored files list (line 284) and won't be touched automatically. Forgetting this creates silent drift between `version.txt` and `plugin.json`.
4. Build the release zip from repo root:
   ```bash
   ./release-antigravity.sh
   ```
   Produces `aria-knowledge-antigravity-<version>.zip` (flat layout) + version-stable `aria-knowledge-antigravity.zip`. Verification gates: `plugin.json` present, `version.txt` present, no top-level wrapper dir, no junk.
5. Users install per Antigravity IDE / CLI conventions; see `plugin-antigravity/README.md` and `plugin-antigravity/SMOKE-TEST.md`.

## Rules

- Follow the universal rules in `Projects/CLAUDE.md`
- **This is a public repository** — never commit personal information, API keys, secrets, credentials, internal URLs, or any sensitive data. Content here is visible to anyone on GitHub.
- **That rule is now mechanically enforced — `release.sh` Gate D (`plugin-claude-code/bin/check-public-hygiene.sh`, added 2026-08-25) is FATAL.** It fails a release when a private project identifier appears in **tracked** content. Why it exists: a repo-wide census that day found **113 occurrences across 35 files in all five ports** — client project directory names, a private domain with its file count, design-system artifact names inside the shipped Rule 22 template, and a portfolio inventory with per-repo commit counts. None malicious; every one entered as a worked example in a design doc or test fixture, and nothing connected "internal name" to "public artifact". ⛔ **Exit 2 means the gate's own self-test failed — that is NOT a clean result** and `release.sh` dies distinctly on it. ⚠ **Its bound, stated in its header: it detects the identifiers in its TERMS/CODES/ARTIFACTS lists, so a NEW client project is invisible until added there — add it when one appears.** Placeholders this repo uses: `proj-a` / `proj-b` / `proj-c`. ⚑ Three instrument lessons are baked in because each cost a re-census: patterns are **boundary-anchored** (an unanchored two-letter code plus a slash also matches the tail of `docs/` — 499 of those here). ⚑ Note this bullet cannot quote the banned forms literally: the gate scans every tracked file, so a specimen written here is itself a finding — which is how this very line first failed the gate, the scan is **case-insensitive** (the last real leak referenced two private projects by their UPPERCASE initials, which every case-sensitive sweep before it missed), and it scans **tracked files only** (an untracked scratch tree produced ten hits that could never ship, which is the noise that gets a gate muted).
- The plugin's own template content (working-rules, change-decision-framework, enforcement-mechanisms) is both shipped content AND documentation of how the plugin works — edits to these have dual impact
- Bump version in `plugin.json` when making release-worthy changes

## Knowledge Repository

Project-specific architecture decisions live in `~/Projects/knowledge/projects/aria/`:

- `decisions/002-knowledge-extraction-architecture.md` — task-based /extract + audit promotion model
- `decisions/006-full-rule22-format-every-edit.md` — full format on every edit (no compression)
- `decisions/008-skill-knowledge-connections.md` — skill-knowledge connection discovery + drift detection

Cross-project knowledge that applies to ARIA:
- `knowledge/rules/working-rules.md` — the 37 universal rules (ARIA's source of truth ships in plugin-claude-code/template)
- `knowledge/rules/change-decision-framework.md` — Rule 22 framework
- `knowledge/rules/enforcement-mechanisms.md` — enforcement tier model
- `knowledge/guides/claude/plugin-development.md` — Claude Code plugin patterns
- `knowledge/guides/claude/cowork-plugin-validation.md` — Claude Cowork plugin patterns (sibling guide; relevant if coordinating with aria-cowork or shipping a Cowork-side plugin)
- `plugin-cursor-template/PORTING.md` — Cursor skill→`.mdc` compilation map and drift tracking
- `plugin-cursor-template/audit/ARIA_CURSOR_AUDIT_REPORT.md` — Cursor enforcement-gap matrix (§5)

Pre-staged ADR candidates live in `~/Projects/knowledge/intake/decisions-backlog.md` — check there for what's currently queued for next `/audit-knowledge`. Themes queued here historically drift as ADRs promote; the live backlog is the source of truth.

Use `/context aria` to load relevant knowledge by project tag.

---

*Last reviewed: 2026-08-27 — plugin-claude-code **v2.48.2** (canonical + antigravity — **SHIPPED + PUSHED + GH-RELEASED + INSTALLED + LIVE-VERIFIED**; `origin/main`=`21b7a31`, verified by `ls-remote` SHA match **and** an ancestor check rather than the push exit code; `/releases/latest` = v2.48.2 with all 6 stable aliases, all 5 site `/latest/download/` links 200 **with a negative control returning 404**, and the **published** zip downloaded and found byte-identical to the local build): **four SESSION.md ledger defects, and three of the things this arc examined were themselves guards that could not fail.** **D1 — the demote gate destroyed live pickups.** Both skills said *never demote a `lastEvent: in-progress` marker, it carries no prompt* — false: `kt_ss_mark_inprogress` rewrites only front-matter and passes the body through with a bare `{ print }`, and `post-edit-check.sh` creates that state whenever a second session edits in a project holding a handoff. ⛔ **FOUR edit sites, not one** — the positive gate keyed on `handoff` in three places, so an `in-progress` entry never reached the demote path and **editing the clause alone was a measured no-op**. ⚑ Field evidence found mid-arc: this repo's own `SESSION.md` already carried a `## Pending handoffs` entry whose comment records a prior session hitting this case and preserving an opener **by hand** because the skill told it not to demote. **D2 — the matchers accepted only the format `ledger_add` writes.** THREE interlocking edits, and the third is the one that matters: **the write must replace the WORD, not an end-of-line-anchored phrase.** With the match loosened and the write left anchored, decorated headers MATCH and are never REWRITTEN — the same silent no-op relocated one layer in, now reading as "handled". ⚠ Measured correction to the spec's own table: a parenthetical after a **matching** sid already worked (not a defect), and a **truncated** sid is not fixed by the loosened match at all (the string is absent), so D2 closes **three** forms, not four. **D4 — a column-0 `### ` inside a stored prompt hijacked the block boundary.** ⛔⛔ **The obvious fix is strictly worse than the bug, measured not reasoned:** removing the reset unconditionally closes the leak AND swallows a live handoff whenever a consumed block lacks a terminator, because that reset is the only recovery path there — one fixture was reduced to its bare heading — **and it PASSES a leak-only fixture**, so a suite covering just the original bug certifies it. What ships is a **discriminated** boundary requiring BOTH conjuncts: a `^### ` line ends an open block only if it carries **≥2 `" · "` separators**. ⛔ The threshold is MEASURED, not chosen — across all 4,594 lines of every `SESSION.md` on one machine, 42 carry ≥2 separators, **26 are entry headers and 16 are non-header prose**, so the count ALONE is insufficient; **0 of those 16 begin with `#`**, so the conjunction has zero false positives. A token-shape test (`^### [^ ]+ · `) was tried first and **failed on 2 of 25** real headers, both hand-written with a parenthetical after the sid. ⚑ Failure direction is bounded by construction: a prose heading carrying 2 separators degrades to the OLD bounded leak, never to deletion. **D3 — a status verb outside `{unconsumed, consumed}` was stuck forever.** Closed set at the writer plus a hand fix of the one live entry. ⛔ **NOT a rejection branch — that would be unreachable code**, because `kt_ss_ledger_add:178` embeds the literal `unconsumed` and takes no status parameter and `mark_consumed:227` embeds `consumed`, so code structurally cannot emit a third verb; only a hand edit can. Asserted behaviourally on the emitted file with a dead-instrument control. ⚠ **Honest residual, ruled fine:** all three ledger checkpoints (`/handoff` `SKILL.md:234`, `/wrapup` `SKILL.md:203`, resume `session-start-check.sh:321`) count `unconsumed`, so an out-of-set verb is invisible to them as well as to both matchers — unactionable AND unreported. Three one-line additions would close it; unbuilt by design. ⛔ **A PRE-EXISTING ASSERTION WAS ACTIVELY GREEN ON THE BROKEN BEHAVIOUR AND WOULD HAVE BLOCKED ITS OWN REPAIR** — it tested that Step 6.5 contained the string `in-progress`, which the false rule and any correction both contain, so it passed either way; and had the corrected wording dropped the hyphenated form it would have **failed**, with its own message asserting the false premise. Second instance in two days (the first was `auto-modes.sh` assertion `I`). Rewritten two-sided — retired wording **absent**, condition **present** — on BOTH skills, plus a new `HCLAUSE` slice with its own floor, because **three of D1's four sites had no assertion at all**: `HSEC` covers only 3f's summary line, so `handoff/SKILL.md:227` sat outside every slice. ⚠ **The trap that bites the fix itself** (`own-comment-enters-the-text-its-guard-reads`): the new controls assert the retired wording is ABSENT while T1 must explain why it was wrong — so the replacement prose **describes** the retired claim and never reproduces it. **Validation:** `session-state.sh` 44 → 55, `wrapup-demotes-before-rewrite.sh` 9 → 14, full suite **38 suites / 0 failed / bare exit 0** matching the T0 baseline, and **11 of 11 mutations caught by their NAMED control**, each proven to have created its condition on disk, all files restored byte-identical. The unconditional-D4 mutation is caught by its new missing-terminator control **ALONE** — nothing else sees it. ⛔ **`/preflight` caught two real FAILs nothing else would have: Gate D (fatal, public repo) exited 1 on private identifiers in TRACKED content** added earlier in this same arc as worked examples — and **four** were fixed, not the two it named, because the others were bare forms its boundary-anchored pattern structurally cannot see; **and the D3 hand-fix was UNCOMMITTED in a different repo** (the Projects root), which no status, diff or suite inside this repo could ever have surfaced. ⛔ **`plugin-antigravity/build.sh` was shipping a DEAD FILE:** it copied `pre-bash-write-check.sh`, unregistered in that port's `hooks.json` **and** structurally broken there — the loop copies only `*.sh` while the wrapper shells out to `pre-bash-write-resolve.py`, so it would `exit 0` in silence, a FALSE PASS indistinguishable from a working guard. Now skipped, matching the two existing skip arms; its `plugin.json` was two minors stale and was hand-bumped. ⚑ **Three of my own instruments were wrong, each differently:** `grep -c '^### '` counted prose headings as entry headers and reported a file MIXED — the reachability probe confounded by the very defect it measured (corrected: no file on disk is mixed); a discriminator written from recollection failed on first contact with the corpus; and a "non-empty prompt block" count counted two ``` fence markers as content. ⚑ **And my mutation harness CLOBBERED `skills/wrapup/SKILL.md`** by keying backups on `os.path.basename` in a repo whose convention is one identically-named file per unit (`SKILL.md` per skill, `plugin.json` per port) — near-certain, not bad luck. Recovered with **zero residue** (`git diff --numstat` = exactly `1 1`, so the only difference from HEAD was the one intended line); the harness now asserts key **injectivity**, making the collision unrepresentable rather than merely absent. ⚠ Gate B **19,622 / 19,968 unchanged** (body-only skill edits, predicted then measured). Gate C reports antigravity drift across 13 skills — **expected**, the port caught up two minor versions via `build.sh` — **plus cowork drift that is NOT from this arc**; the ledger was deliberately **NOT** re-baselined so that signal survives. ⚠ **codex and cursor still carry the D1 clause** (hand-sync / `.mdc` recompile) — named residuals, deliberately not half-done. Docs: spec + plan both STAMPED SPENT at `docs/superpowers/{specs,plans}/2026-08-27-session-ledger-integrity*`; gates `knowledge/logs/prospect/2026-08-27-file-session-ledger-{integrity,plan-gate2,a1-delta-gate}.md`, retrospect `…/logs/retrospect/2026-08-27-range-session-ledger-integrity-v2482.md`, preflight `…/logs/preflight/2026-08-27-session-ledger-integrity-v2482.md`. — Prior: 2026-08-26 — plugin-claude-code **v2.47.0** (canonical only — **BUILT + INSTALLED LOCALLY, NOT pushed, NOT tagged, NOT GH-released**; 11 commits `51ae86e..a1988ee` on local `main`, which also carries one commit that is NOT part of this arc — `c77d62f`, a parallel session's Gate D fix): **ARIA's rules were reaching nobody, and the cause was the channel, not the rules.** `bin/session-start-check.sh` emitted **9,124 characters** of rules and directives on `systemMessage` — which renders to the user's terminal and **never enters model context**. ⛔ **So on a stock install, every user's working rules and user rules were generated, rendered, and discarded.** ⭐ **Measured two-sided in a single transcript, not inferred: FOUR `SessionStart` hooks ran side by side — lines 3–4 emitting `hookSpecificOutput.additionalContext` (the output-style plugin and **superpowers**) produced `hook_additional_context` records that reached the model; lines 5 and 7 emitting `systemMessage` (ARIA's among them) produced `hook_system_message` records that did not.** Same event, same session, different field, opposite outcome — and **superpowers was already solving the identical problem the identical way**, delivering its entire always-on skill text through the channel ARIA needed. ⛔ **The official hooks reference says `SessionStart` does NOT support `additionalContext`. That is FALSE for this build and is falsified by those two plugin hooks** — so, per the new canonical pattern `source-discredited-on-one-claim-still-cited-on-another`, **no other claim from that fetch is relied on anywhere in this arc**, including the one the design originally rested on. ⚑ **The maintainer was the OUTLIER, not the baseline:** this workspace carries **331 KB** of hand-built always-on context (`@.claude/discipline-index.md` 88 KB + `@.claude/project-index.md` 243 KB) plus a root `CLAUDE.md` citing **23 rules by number**; a stock install has none of it, and `/setup` deliberately writes no pointer (ADR at `skills/setup/SKILL.md:279`). ⭐ **And the fix is smaller than it looks for the affected population: a NEW user's undelivered payload is only ~409 tokens**, because four of the eight directives are config-gated off by default (`projects_enabled`, `session_start_project_picker`, `session_state`, `autonomy` — measured at `bin/config.sh:127-143`) — so the rules digest is **~80% of everything a new user gains**, and adding Unit 2 costs a fresh install **zero**. **SHIPPED (11 commits, tests 149 → 202, zero failures):** `rules/aria-rules.md`, a 38-rule digest derived from the **canonical** `template/rules/working-rules.md` — ⛔ **never an installed copy, which is user-owned and diverges by design (the maintainer's is 472 lines vs the template's 470, the delta being a personal Rule 18 annotation) and which a rule-count check CANNOT catch, since both have 38** · a **second** `SessionStart` hook `bin/session-start-rules.sh` on `additionalContext`, chosen over dual-field emission because that mechanism has **zero precedent across all 30 `bin/*.sh` and zero across six live hook emissions**, leaving `session-start-check.sh` byte-identical (AC8, `git diff --exit-code`) · re-injection after `/compact` · `template/index.md` + the active-context gate **tightened from file-existence to tag-content** (shipping the skeleton alone would make the old gate pass on day one and spend ~223 tok/session on a matcher that provably cannot fire) · a **default-no** `CLAUDE.md` rules-pointer offer that NARROWS the §279 ADR in place rather than reversing it · and a report of which features are off. ⛔⛔ **FOUR DEFECTS FOUND THAT WERE NOT IN SCOPE AND WOULD HAVE SHIPPED SILENTLY: (1) `kt_json_escape` ends with `tr '\n' ' '` — it STRIPS newlines, so the digest would have arrived as ONE RUN-ON LINE, valid JSON, exit 0, no signal; a new `kt_json_escape_multiline` sits beside it in `config.sh` and the original is byte-unchanged because four hooks depend on stripping. (2) `echo` then converted the escaped `\n` sequences BACK into real newlines — 83 lines of invalid JSON — because `echo`'s backslash handling is implementation-defined; `printf` is now used and the constraint is documented at the function, with the census idiom recorded after a one-idiom pass said four echo-emitters and a second found SIX. (3) `INSIGHT CAPTURE` wrote the star as literal `\xe2\x98\x85`, which is not an escape in a POSIX double-quoted string. (4) `MEMORY PATHWAY` routed notes to `/clip`, RETIRED into `/intake` in v2.33.0 and now in `skills/.archived/`.** ⚑ **(3) and (4) were invisible precisely BECAUSE nothing read the channel — fixing delivery is what exposed them**, and copying them verbatim would have been propagation rather than fidelity. ⛔ **A FALSE-GREEN GENERATOR IN THE HARNESS ITSELF: a test file that failed to PARSE made `tests/run.sh` print the error, skip the totals line, and EXIT 0** — a CI gate on it passed. Found when an apostrophe broke a quote. Now `sh -n` before sourcing; validated two-sided at an **identical pass count** in both arms (`202 passed, 1 failed` exit 1 with a deliberate break; `202 passed, 0 failed` exit 0 without), so the fix demonstrably adds a failure mode and nothing else. ⚠ **THE `TASK BUDGET` REWORK is the one deliberate AC8 exception.** Its long variant (fires only when the status-line meter is installed) directed the model to consult usage figures before deciding to continue, hand off, wrap up, or compact — **the exact behaviour Mike has repeatedly corrected** (*"usage measurements are wrong, ignore them and proceed"*), harmless only because the channel was unread. **Delivering it verbatim would have CAUSED it.** Reworked so the snapshot answers a usage question and explicitly does not decide one; the defective text is **removed** from the old hook, because a corrected behaviour one channel-flip from returning is not corrected. ⛔ **THREE OF MY OWN CLAIMS WERE CORRECTED BY MEASUREMENT, NOT REVIEW: the ledger "double-write" is an order-dependent RACE** (multiple `kt_artifact_record_ledger` callers are the design — three hooks already call it; the hazard is two hooks on the SAME trigger, where the first records and the second silently emits nothing) · **"copied verbatim" was asserted twice and wrong twice**, a 6-byte diff locating a dropped `now` (2 bytes were the trailing quote, 4 were the word) · and **`TASK BUDGET` read as PRESENT when it appeared only in a comment** — presence is not a call site. ⚠ **Unit 2 is DELIBERATELY PARTIAL: only the two pure-text directives shipped.** The tracked-artifacts and CODEMAP blocks stay in `session-start-check.sh` — the first because a second hook on the same trigger makes channel selection order-dependent, the second because ~70 lines of staleness logic would drift between copies. **Neither is fixed by copying; both are dissolved by the collapse.** ⭐ **THE END STATE IS RECORDED AT `docs/superpowers/specs/2026-08-25-always-on-rules-delivery-design.md` §8 — ONE hook emitting both channels, routed by audience, with `session-start-rules.sh` DELETED.** The two-hook split is a workaround for an unverified capability, not the target; §8.2 carries the exact transcript-classification recipe, which **needs a fresh session because hooks arm at session start**. ⚠ **Gates: `/prospect` on the spec and again on the plan** (both PROCEED-WITH-CHANGES; gate 2's blocking finding WAS the newline collapse, caught before any code) **and `/preflight` READY with two stated bounds** — P3 pending reinstall, **P6 partial at 2 of 50 assertions mutation-verified** (both load-bearing; 21 more via red→green; 27 structural doc assertions never observed failing). ⚠ Built from a **detached `git worktree`**, verified two-sided (packaged `skills/index/SKILL.md` matches COMMITTED and DIFFERS from the dirty tree), so a parallel session's uncommitted work stayed out of the artifact. ⛔ **CORRECTED 2026-08-26 — THE ARC IS NOT DONE, AND THIS ENTRY READ AS THOUGH IT WERE. `additionalContext` has an undocumented PER-EMISSION cap: the 19,557-char payload is delivered as a 2,000-char preview plus a file path (`K5=2000`, read out of the CLI binary), so **2 of 38 rules and 0 of 19 U-rule refs reach the model** — reproduced across NINE sessions, i.e. every session since install. §2.3 is therefore NOT fixed: `pre-edit-check.sh:362` still denies an Edit/Write without a `[Rule 22]` marker while its only instruction is still absent from context (this session hit that denial live, and could satisfy it only because THIS workspace's CLAUDE.md documents the marker independently). Stated fairly it is still a net gain, 0 → 2,000 delivered chars.** ⛔ **The "~3,040 tok/session, kept at 12 KB" figure below is a UNIT MISMATCH, not an error: 11,960 chars is `rules/aria-rules.md`, the ARTIFACT Mike ruled on; the EMISSION the cap applies to is 19,557 chars ≈ 4,900 tok.** ⛔ **The dual-field measurement CANNOT BE RUN as specified** — no hook emits both fields, and §8.2's pass criterion ("same `hookName`") is unsatisfiable by construction, because the `hook_additional_context` record is a per-session AGGREGATE under a generic name while `hook_system_message` records are per-hook. Corrected in place. ⭐ **And the file channel reaches SUBAGENTS while the hook channel does not** (measured from a subagent's own context, positive control firing) ⇒ **every delegated agent today runs with ZERO ARIA rules**, which is the strongest argument for a file channel and arrived by accident. Spec revised: new §2.6 (the measurement), new §10 (channel inventory + four candidate designs + recommendation), §10.6 (subagent reach), AC1 re-scoped to assert the LAST rule title, AC8 amended to name the one `d31493c` exception (a ruling already recorded in this very footer and never propagated to the spec), §8 marked superseded-in-priority, §6 stamped stale. Gate: `/prospect file` PROCEED-WITH-CHANGES, 11/11 validation checks, and it falsified the spec's own "2-3 emissions" — the minimal version is ONE, at 2,972 chars. Commits `1f60257`, `a1667b8`; gate log `knowledge/logs/prospect/2026-08-26-file-always-on-rules-delivery-cap.md`; two new canonical patterns. ⚠ **OWED: read the armed probe `~/.claude/rules/_probe-size.md` in a FRESH session to pin the cap, then DELETE it (it costs ~3.3k tok in every session in every project while armed) · the push · Mike's ruling on the option X/Z channel choice · the disclosed Advanced Options scope reduction · the `/audit` + `/audit-knowledge` review · the four port syncs.** — Prior: 2026-08-20 — plugin-claude-code **v2.46.4** + **v2.46.3** + plugin-claude-cowork **v1.7.0** (all SHIPPED + PUSHED + GH-RELEASED + INSTALLED; `origin/main`=`daec224`, `ls-remote`-verified; **v2.46.4 is Latest**, all 6 stable aliases attached, all 5 site `/latest/download/` links 200, and both published zips downloaded and content-verified rather than trusted). ⭐ **`check-port-drift.sh` reports 106 ok / 0 lag / 0 drifted / 0 missing across all four ports for the first time.** **v2.46.3 = a PORTS release.** antigravity, codex and cursor were each at or near content parity but **none had shipped** — antigravity was committed-and-never-pushed, codex and cursor sat **uncommitted in the shared working tree** from a session that had ended. ⛔ **"Committed" ≠ "pushed" ≠ "released"; I reported antigravity as done on the first of those three.** codex `2.36.0-codex.0`→`2.46.2-codex.0` (+7 skills, +6 hook scripts; its 35-vs-36 skill count is `/statusline`, documented at `PORTING.md:61-63` as deliberately unported and guarded by its own test). cursor `2.36.0`→`2.46.2-cursor.0`, verified by the **compiler itself** — re-running `port-skills-to-mdc.py` reproduced the committed `.mdc` byte-for-byte, with a positive control proving `git diff` could see a change at all. **cowork v1.5.0→v1.7.0 was the real work.** Its gap looked like "16 versions behind" and was **four items**, because most canonical releases since v2.38.0 are hooks/shell/`/auto`, none of which a skills-only runtime has — then a census widened it to **seven**, which is the lesson: ⛔ **classifying 16 releases by CHANGELOG HEADLINE missed the portable half of two of them.** v2.45.1's headline is its external-fetch hook (correctly N/A) and its *second* fix was `/interview asks adaptively by default` — a pure skill-body change to a skill cowork ships, measured canonical `guided`=8 vs cowork `guided`=**0**. v2.33.0's headline is the `/intake` consolidation and its second half is the `/audit-knowledge` **Step 2f** that makes clip-whole safe; porting the first without the second reintroduces the write-and-never-read dead-end v2.33.0 existed to close. Both shipped in v1.7.0, now canonical pattern **`changelog-headline-is-not-a-change-inventory`**. ⛔ **BREAKING in cowork: `/clip`, `/clip-thread`, `/extract-doc` are retired into `/intake`** (archived under `skills/.archived/` with pointer headers per Rule 6, triggers absorbed into `/intake`'s description so "clip this"/"save this link"/"archive this conversation" still route, `/help` repointed). Thread mode carries **cowork's own five steps in full**, not canonical's compressed three — cowork's `/clip-thread` held **15 MCP references** against `/intake`'s 2, and copying canonical would have silently dropped them. **Description budget 8,722 → 8,055 of 9,000** — the consolidation freed more than the absorbed triggers cost. ⛔⛔ **THE ROOT CAUSE WAS A DEAD DETECTOR, AND IT HAD TWO INDEPENDENT DEFECTS.** `plugin-claude-cowork/release.sh`'s template-parity check resolved `ARIA_KNOWLEDGE_TEMPLATE` to `<repo>/aria-knowledge/plugin/template` — a **doubled directory that has never existed** in this layout — and reported the miss through **`vlog`**, which prints nothing at normal verbosity, so a broken path and a clean result were indistinguishable. **That is why the rules drift accumulated unseen.** Fixing the path exposed the second: the drift counter used **`wc -l` on filtered diff output**, counting diff **METADATA** (`1c1`, `---`) alongside content, so a file whose only difference was the sanctioned `/setup` ↔ `/aria-setup` header still counted 2 and warned — **it flagged the exact divergence it exists to tolerate, on every plugin-managed rules file, every run.** Both fixed and **mutation-proven in three directions** (clean→clean · injected drift→named · broken path→warns at default verbosity); the checked set is now plugin-managed files only, with user-owned `aliases.md` deliberately dropped and a DO-NOT-RE-ADD comment. **v2.46.4** then carried four post-release fixes. ⛔ **`bin/pre-commit-preflight-check.sh` read the WRONG REPOSITORY:** a `cd` target that is not a directory blanked `REPO_DIR`, falling through to `"."` — the hook's own cwd — so it denied commits while citing staged files from a repo the command never named, contradicting the comment four lines above it and breaking section `[11]`'s stated contract. ⚑ **The test that should have caught it had CERTIFIED it as working:** `"nonexistent repo -> fail open"` asserted `""`, which is produced **both** by the intended branch **and** by the cwd fallback finding nothing staged — vacuous whenever green, red only when a developer happened to have files staged, which is exactly how it surfaced (while staging an unrelated deletion). Now runs from a fixture repo with `app.py` **staged**, so `""` proves the intended branch ran, plus an armed-fixture control; **147/0 with nothing staged and again with files staged**. ⛔ **Three unwired scripts removed from the codex port** (`post-edit-tautology-check.sh`, `post-plan-prospect-check.sh`, `post-push-retrospect-check.sh`) — shipped to users while referenced by nothing, because Codex routes every hook through `bin/codex-hook.py` where all three already live as functions, each verified **defined AND called** against a negative control. Censused as a class (27 scripts, exactly 3 with zero refs), verified safe four ways, and `PORTING.md` records the convention so a hand-sync does not re-copy them. ⛔ **A PUBLIC-HYGIENE LEAK was caught by a mechanical PRE-PUSH sweep, not by review** — internal project names in code comments across **all four ports** (6 occurrences in `lib-session-state.sh` + `extract-user-prose.py`); **canonical's were ALREADY public** and this release's port syncs would have propagated them to three more. Fixed in all four per Rule 38, which **falsified this release's own changelog claim** that canonical was byte-unchanged — corrected in the same commit rather than left to read plausibly and wrongly. ⚑ **One "defect" was RETRACTED on measurement:** I opened the drift-checker's lag line as noise ("a patch bump marks every port as lagging") and the data killed it — across the 11 canonical transitions v2.40.0→v2.46.3, **10 of 11 bumps carried change under `plugin-claude-code/{skills,template}`**, and **3 of 5 patch bumps did**, so severity-filtering is wrong in **both** directions and there is no well-defined portable surface to hash. Committed as a comment, **zero executable lines changed**. ⚑ **And my FIRST measurement of that was itself wrong** — three tags did not exist locally (`v2.43.1`, `v2.45.0`, `v2.46.3`, the last because `gh release create` made it remotely), so `git diff` errored and a **`2>/dev/null` turned it into a false 0**, reporting 7 of 13 bumps as carrying nothing. Third instance of that trap in one session. ⛔⛔ **RELEASE TRAP, LIVE AGAIN AND STILL NOT HYPOTHETICAL: `release.sh` STAGES FROM THE WORKING TREE**, and two `skills/index/SKILL.md` files (canonical + cowork) were uncommitted from another session throughout. Built from a **detached `git worktree`** both times and verified **two-sided**: packaged `85d1252945…` (= COMMITTED) ≠ dirty `4ba1f52ce2…`. ⛔ **NEW TRAP — cutting the cowork group tag nearly 404'd every site download button.** `/latest/` resolves to the newest release **across all tags**, and RELEASING.md's 2026-06-23 decision puts all 6 stable aliases on the canonical `v2.x` release only; a plain `gh release create cowork-v1.7.0` would have become Latest and broken all five links. **Pass `--latest=false`**, then verify — v2.46.4 confirmed still Latest and all five links 200 with a negative control returning 404. ⚠ **cowork's residual is SETTLED, not open** (Mike ruled won't-fix 2026-08-19): five canonical skills stay absent — `audit-style` and `audit-share` are **impossible** (a shell + a Python script over local session logs; git-native `ls-files`/`add`), `recap` and `roadmap` are **partially** portable (synthesis is git-free, only their git modes are not) and **do not fit the budget**, and `audit` is **fully portable and fits** but is excluded on value (it routes to four sub-audits and cowork has two). The deciding constraint is arithmetic: `audit`+`roadmap` = **9,019 against a 9,000 cap that fails the INSTALL at 9,233**, so exactly one of the five fits at all. ⛔ **`PORT-LEDGER.json` hashes files that EXIST and structurally cannot represent an unported skill**, which is why that residual lives in `plugin-claude-cowork/CLAUDE.md` and a clean drift report must not be read as meaning those five are done. — Prior: 2026-08-18 — plugin-claude-code **v2.46.2** (canonical only — **SHIPPED + PUSHED + GH-RELEASED + INSTALLED**; `origin/main`=`7e3d26f`, tag `v2.46.2` is **Latest**, 6 stable aliases attached + all 5 site `/latest/download/` links 200; installed copy verified **by md5 and by symbol grep**, not by release notes): **two guards that could never fire, and they share one mechanic — `git check-ignore` consults the INDEX, so it reports a TRACKED file as "not ignored."** ⛔ **FIX 1 — `bin/lib-session-state.sh` appended `SESSION.md` to a project's `.gitignore` on EVERY run, without limit.** The guard was `! git check-ignore -q SESSION.md`; for a **tracked** `SESSION.md` that exits 1, so the negation was always true. ⚑ **Measured 2026-08-17 and stronger than the handoff claimed: it exits 1 even when `SESSION.md` is ALREADY listed in `.gitignore`**, so the guard could never be satisfied and the append had no upper bound — one line per session per project, indefinitely. Live evidence: one project's `.gitignore` reached **4 duplicate lines** by 08-14, was cleaned in `3a77b34` with an explicit DO-NOT-ADD comment block, and had accumulated **2 more directly beneath that warning** by 08-16. ⛔ It also never read `session_state_tracked`, so the standing ruling that workspace repos deliberately **TRACK** `SESSION.md` had no effect here — v2.46.0 wired that knob into `wrapup/SKILL.md` and `handoff/SKILL.md` ONLY, and this shell library was a **THIRD code path nobody fixed**; the plugin's own docs already prescribed the right test (`git ls-files --error-unmatch`) at `wrapup/SKILL.md:202`, `handoff/SKILL.md:241` and `setup/SKILL.md:202`. ✅ Four guards now, each closing a different hole: honour `session_state_tracked` · is it a git repo · **is `SESSION.md` TRACKED** (an ignore rule is a **no-op on a tracked path**, so appending achieves nothing but growth) · is the line already present. Reads `${KT_SESSION_STATE_TRACKED:-}` rather than the bare form the calling hooks use — those are entry points that always source `config.sh` first, whereas this is a **library** that must stay safe when sourced alone (no file in the chain sets `set -u` today, measured; the defaulted form keeps that true if it ever changes). ✅ **Validated in throwaway git repos, four arms, with a control proving the tested guard is byte-present in the shipped library:** TRACKED → no write · UNTRACKED → exactly one line, idempotent over three runs · `session_state_tracked=true` → no write at all · variable UNSET → remaining guards hold in both tracked and untracked cases. Old guard then restored and observed **RED** on the tracked arm for the stated reason: **six runs, six lines**. ⛔ **Scope: canonical ONLY, per Mike's ruling** — all four runtimes carry this library and the four copies have **four DISTINCT md5s**, so this is four separate edits rather than one propagation; antigravity/codex/cursor stay tracked-drift. ⚠ The **cursor copy additionally had uncommitted changes from a parallel session**, so touching it would have clobbered in-flight work. ⛔ **FIX 2 — `check-port-drift.sh`'s lag line was measured against a FROZEN ledger pair, so it could not see drift** (`c6b9c90`, pushed separately). It compared a port's own `version` to its `parity_target` — both written together by `--update`, hence equal by construction at baseline time and never diverging as canonical moves on, leaving the line silent for the only lag that exists: the kind accruing AFTER a baseline. Measured: antigravity read **2.36.0/2.36.0** and reported nothing while canonical was **2.46.1**, nine minor versions ahead; and the one lag line that DID fire was a **constant** (cowork's independent 1.x scheme can never equal a 2.x target, so it flagged forever — a permanent signal is not a detector). ⚑ Corroboration found during the investigation itself: **v2.46.0 and v2.46.1 shipped while it was being written, ports fell two further versions behind, and Gate C reported nothing new.** ✅ Lag now compares `parity_target` to **LIVE canonical**; removing the port's own version as an operand dissolves cowork's false positive **without an exemption** (it was a symptom of comparing the wrong two things — Rule 38). ⛔ **The `/prospect` gate caught a defect this would otherwise have shipped:** `canonical_version()` is **tolerant by design** (empty when the manifest is absent — correct for its `--update` caller) and **NO test fixture creates a canonical manifest**, so empty as a comparison operand would have made *every* port report lag, invisibly, in every test. An unresolvable canonical now emits **no lag line at all**. ⚑ Same shape as Fix 1 and as the v2.45.1 fetch-gate bug: **a construct correct at its original call site, silently wrong at a new one** — now catalogued as canonical pattern `borrowed-pattern-wrong-branch` (three instances, two repositories, one session). ✅ `version_for_target_compare()` deleted (zero callers, grep-verified); the orphaned `_ver` read removed with a note on why the field is no longer consulted. ⚠ **Two existing test assertions went VACUOUS rather than red** once the port's own version left the comparison — they asserted an absence that became true by construction — so they were **replaced, not adjusted**; six assertions now cover behind/current/independent-scheme/baseline-excluded/absent-manifest/exit-code-unchanged, each **mutation-proven** to fail for its own named reason, script restored byte-identical via `cmp`. ✅ **Gate C's `TODO(v2.31.0): make fatal` RETIRED, not re-dated** — it had slipped **fifteen** minor versions, making it a false promise rather than a plan (Rule 37). Fatality now keys on a **declared SLA**: machinery that already exists, which `is_failure()` already tolerates as `undeclared`, so a port stays advisory until someone commits to its cadence and the gate bites per-port automatically when one is declared. `|| true` untouched — Gate C behaviour is unchanged. ⛔⛔ **RELEASE TRAP, LIVE THIS TIME, NOT HYPOTHETICAL: `release.sh` STAGES FROM THE WORKING TREE.** A parallel session had `plugin-claude-code/skills/index/SKILL.md` uncommitted, so a normal build would have shipped their in-flight file into a **public artifact with no error**. Built from a **detached `git worktree` at the release commit** and verified **two-sided**: the packaged copy is `85d1252945…` (= COMMITTED) and **differs** from the dirty working-tree `4ba1f52ce2…`. ⚑ The installed copy legitimately differing from source on that one file is itself the proof the worktree build worked. ⚠ **The fix is not live until the installed plugin is re-synced** — verify by **md5** (`lib-session-state.sh` is now `24cbb2ee352736dfd17a8afd811fc50d`, superseding the pre-fix `d2f37ce58bac9572fd73a26745573b99`) and by **grepping the SYMBOL across the installed tree**, never by trusting the release. Ports codex/cursor/antigravity/cowork tracked-drift. Plan `docs/superpowers/plans/2026-08-17-port-drift-live-canonical-lag.md`; prospect + retrospect logs + judgment ledger (3 entries, **all accepted by Mike 2026-08-17**) in the knowledge folder. — Prior: 2026-08-16 — plugin-claude-code **v2.46.1** (canonical only — **SHIPPED + PUSHED + GH-RELEASED**; `origin/main`=`1c22d32`, `ls-remote`-verified; tag `v2.46.1`, all 6 stable aliases attached and all 5 site `/latest/download/` links 200; the **published** zip was downloaded and content-verified — 528,450 B, `"version": "2.46.1"`, the new guard present, the old one absent, `tests/` excluded — and `cmp` byte-identical to the local build): **the preflight gate's admission test was a literal substring, and it was wrong in BOTH directions.** `case "$COMMAND" in *"git commit"*)`. A `git -C <repo> commit` contains `git -C … commit` and never the substring `git commit`, so the hook exited before reading anything — **the gate did not fire on scripted or `git -C` commits at all, including in a repository named by `preflight_deny_repos`, the strongest setting available.** Measured two-sided on one repo with one staged file: `cd <repo> && git commit` denied, `git -C <repo> commit` silent. ⚑ **The hook's own `REPO_DIR` resolver is written for exactly the `git -C` form and was therefore UNREACHABLE dead code — the guard had already exited on every command that would have needed it. That unreachable branch is what establishes the wider unit was intended**, rather than a narrowing someone chose and left undocumented. In the other direction `git commit-tree` **denied**, contradicting the comment directly above it, because `git commit` is a prefix of it. Replaced with an ERE encoding the actual grammar — `git`, then any number of option-like tokens, then `commit` as a whole word; `case` structurally cannot express "only option-like tokens between", and any pattern loose enough to admit `git -C /d commit` also admits `git status -m "commit "`. **Validation:** the ERE measured against **17** command forms *before* any edit (9 must-match incl. `-C`, `-c k=v`, `--no-pager`, compound `cd &&`, parenthesised subshell; 8 must-not-match) — 17/17. Seven new assertions; **five observed RED against unmodified HEAD and RED again under a mutation** reverting the guard, the hook restored **byte-identically via `cmp`** from a worktree backup (never `git checkout` — the tree holds a parallel session's uncommitted work). **146 passed / 0 failed** + **36 repro suites / 0 failed**, both bare exit codes. ⭐ **Then validated LIVE, two-sided, in the shipping session itself:** a real `git -C <path-matching-deny_repos> commit` through the Bash tool was **DENIED** by the hook, and `git commit-tree` **reached git** (its own `fatal: must give exactly one tree`) rather than being denied. ⛔ **That live check also falsified MY OWN recorded claim.** I had written — into this repo's config changelog and onto Mike's open-items list — that "hooks arm at SESSION START, so the newly installed guard is on disk and NOT active in this session." **False.** What arms at session start is the hook **REGISTRATION**; the registered command is `bash ${CLAUDE_PLUGIN_ROOT}/bin/…` and **bash reads the script from disk at EXECUTION time**, so replacing the file changes behaviour on the next invocation. **The lesson is not the mechanism — it is that I asserted a limitation instead of testing one that cost a single command.** "X is not active / cannot be verified from here" is a claim about the world; distinguish *I have not tested it* from *it cannot be tested*. ⚑ Two more traps the gates paid for: assertion `[15e]` (`git status -m "commit "` is silent) is **green in BOTH arms** and is therefore NOT landing evidence — the pre-mortem caught it mislabelled as a non-vacuity guard; and **`publish-release.sh` needs four port stable aliases at `REPO_ROOT` that are UNTRACKED and gitignored**, so the detached worktree that makes the BUILD safe would have made the PUBLISH attach an incomplete asset set — build in the worktree, copy out, **publish from the main root**. ⚠ **NOT changed: the `docs/` filter.** A commit whose staged set is *entirely* docs-filtered stays silent even in a gated repo, pinned by test `[14g]` as intended behaviour; re-measured and **narrower than previously recorded** — the early exit is on `[ -z "$CODE_FILES" ]`, so a **mixed** docs-plus-code commit still denies. Claude-Code-canonical: the hook exists in exactly one runtime (grep across all five `plugin-*/` trees returned 1), so no port propagation and no `PORT-LEDGER` change. Prospect: `knowledge/logs/prospect/2026-08-16-file-preflight-admission-guard-git-c.md`; retrospect: `knowledge/logs/retrospect/2026-08-16-range-preflight-admission-guard-v2461.md`. — Prior: 2026-08-16 — plugin-claude-code **v2.46.0** (canonical only — **SHIPPED + PUSHED + GH-RELEASED**; `origin/main`=`d541c3b`, 2 commits, **ls-remote-verified** rather than trusting the push exit code; tag `v2.46.0` is what `/releases/latest` resolves to, all 6 stable aliases attached and all 5 site `/latest/download/` links 200; the **published** zip was downloaded and content-verified — 527,842 B, `"version": "2.46.0"`, the new key present 4× in `bin/config.sh`, the `ls-files` fix present in **both** skills, and the old clause **absent** — rather than trusting the upload): **a config key, and a precondition that could never become true.** **Added `session_state_tracked` (default `false`).** `/wrapup` Step 6.5 and `/handoff` shared one **unconditional** instruction — gitignore `SESSION.md`, never stage it — whose stated rationale is that the file is ephemeral *because* `PROGRESS.md` is the durable log. ⛔ **That rationale does not hold in a repo with NO `PROGRESS.md`**, where `SESSION.md` *is* the durable log and the decision trail it carries lives in no repo at all, so an overwrite is unrecoverable. At the default nothing changes for existing users; at `true` both skills stop writing an ignore line, **stage** the file, and remove an existing ignore line (leaving one makes the config assert something git is not doing). Registered with the same **three** pieces as its sibling — parse, default, boolean validation — after a first pass added only the parse, which a grep of the *symbol* (not the file) caught as the declared-but-not-wired shape. Documented in `/setup` in both the schema block and the prose bullet, because **a key the wizard writes but never surfaces is the defect that surfaced this one.** **Fixed — the clause append-looped.** Its precondition asked *"does `.gitignore` already ignore `SESSION.md`?"*, and ⚑ **an ignore rule is a NO-OP on an already-tracked path**, so for a tracked file the answer is permanently "no" and every run appended another line — one observed `.gitignore` had reached **four** identical `SESSION.md` lines, and the resulting permanently-dirty `git status` is exactly the noise that trains a reader to stop looking. Now tests `git ls-files --error-unmatch`. **This is a real defect at EITHER setting of the new key.** ⚠ Both skills also record why `git check-ignore` cannot serve as that test: **it consults the index, so it reports a TRACKED file as *not ignored*** — an inversion that reads backwards until you know it, and precisely how a `.gitignore` and reality come to disagree with nothing erroring. **Validation:** `sh -n` clean; the key resolves `true` from a real config, defaults to `false` when absent, and falls back to `false` on a malformed value — **all three arms**, not just the happy path. Gate A suites pass; **Gate B 19,541 / 19,968** (unaffected by construction — the edits are skill **bodies** and the budget measures frontmatter descriptions). ⚑ **Built from a detached `git worktree` at the release commit, not the working tree** — a parallel session had **uncommitted** edits to `plugin-claude-code/skills/index/SKILL.md`, and `release.sh` stages from `REPO_ROOT`, so a normal build would have shipped another session's WIP into a public artifact. Verified two-sided: the worktree copy matched the **committed** file and **differed** from their dirty one. ⚑ **The origin is a correction worth keeping: I had recorded "the skill cannot be fixed in place — no source copy exists" as a MEASUREMENT, on the strength of one `ls` against one GUESSED path** (`aria-knowledge/skills/wrapup/`, missing the per-runtime `plugin-claude-code/` layer). It propagated to six surfaces before Mike corrected it in four words, and in one of them it *foreclosed the option that turned out to be correct*. **A negative claim must search the actual shape, not probe an assumed one — and calling it "measured" is what stops anyone re-checking.** ⚠ Measured scope: the clause is in **six** files — `wrapup` **and** `handoff` × claude-code, antigravity, codex (`plugin-claude-cowork` has none) — and only **claude-code** was fixed by ruling; the other two runtimes stay tracked-drift. — Prior: 2026-08-14 — plugin-claude-code **v2.45.1** (canonical only — **SHIPPED + PUSHED + GH-RELEASED + INSTALLED**; `origin/main`=`e186953`, 5 commits, ls-remote-verified; tag `v2.45.1` is **Latest**, all 6 stable aliases attached and all 5 site `/latest/download/` links 200; installed copy `cmp`-verified byte-identical to source on all 4 changed files, and installed **from the shipped zip**, not the worktree): **two bugfixes, and the release ceremony 2.45.0 never got.** ⛔ **v2.45.0 was pushed and installable but was NEVER GH-released and has NO CHANGELOG entry** — the file jumps 2.44.1 → 2.45.1, and `/latest/` sat on v2.44.1 for 12 days, meaning the site's download buttons served 2.44.1 the whole time. v2.45.1's CHANGELOG entry and release notes are written **self-contained** so nothing depends on that gap; reconstructing a retrospective 2.45.0 entry is left as a deliberate decision, not done silently. **Fix 1 — the external-fetch gate denied prose `WebSearch` queries.** The gate's contract is DOMAIN coverage, and its query branch reused the URL branch's domain shape `(w1|w2|w3|w4)\.[a-z]` against prose WORDS — "any query word followed by a dot and a lowercase letter" — matching every `guidelines.md` / `screening.md` / dotted path in a markdown corpus. Measured: **three consecutive literature searches denied in one session** citing unrelated documents; the entire match was the substring `guidelines.m` **seven times**, i.e. one common English word inside a FILENAME (isolated: `guidelines`→4 files, `screening`→0, `participation`→0). ⛔ **Word filtering CANNOT rescue it, and my own alternative died on the measurement that proves it: `/usr/share/dict/words` holds `guideline` and NOT `guidelines`, so every English PLURAL reads as a vendor stem — while `render` IS in the dictionary, so filtering would stop detecting `render.com`, a vendor the corpus really covers.** Wrong in both directions, which is what promoted the handoff's fix from plausible to correct. A query now gates only on a domain it NAMES; the explicit TLD allowlist is load-bearing (a generic `\.[a-z]{2,}` matches `screening.the`). Also repaired the reason text's retry promise, which was **structurally false** — the cooldown key was the four longest words, so REPHRASING minted a new key and denied again, the reason one denial became three. ⛔ **The handoff that diagnosed this was right on mechanism and WRONG on three things, each caught only by checking: (1) "exactly one copy on disk" — the SOURCE exists in the repo (it simply could not search `aria/`, which it admits); the two were byte-identical, no drift. (2) It never mentioned the TEST SUITE, which asserted the buggy behaviour as `[AC6]` — a bare vendor WORD denying was the deliberate v2.45.0 "vendor stems from prose" feature, so this fix is a capability NARROWING, not a pure repair. (3) Its suggested `cdc.gov` positive control would have MISLED — the corpus has zero `cdc.gov` mentions, so "allow" is correct there; used `atlassian.com` (8 files, exactly at the ambient cap) instead.** ⚑ **A 4th assertion did not fail — it began passing VACUOUSLY** (with prose never gated, "reordered query shares the cooldown" returns empty whether or not a cooldown exists); only the pre-edit RED run made it visible, and it is the tautology class `post-edit-tautology-check.sh` exists to catch. Rewritten to the narrowed contract + **3 new assertions** (prose-without-domain never denies · a file extension is not a TLD · prose and URL on one domain share one key) + a fixture trap holding `guidelines.md`/`screening.md` so the negative fails for the right reason. **139/0** (was 136); 3 stale assertions observed RED before any test edit; both new negatives observed RED under a mutation restored **byte-identical via `cmp`** from a worktree backup (never `git checkout`, which would have discarded uncommitted work). Live e2e: all three original denied queries now allow, prose naming a covered domain denies, **positive control still denies with real paths** — without it a fix that disabled the gate entirely looks identical to one that works. `EF_STOPWORDS` is now dead and marked so **with a Rule 37 removal trigger** rather than deleted (the `case` construct consuming it carries a measured parse trap). **Fix 2 — `/interview` asks adaptively by default.** It offered two cadences and *recommended* the all-at-once one in **3 of 4 cases**, so the effective default was a numbered wall answered by scrolling and quoting numbers — and a batch is derived before any answer arrives, so it kept asking what an earlier answer had already made irrelevant. Both user complaints were the **specified behaviour** of that mode, not a misfire. Default is now `guided`: dialogs of **1–4 questions** via the platform's question/picker affordance (named generically, as `/auto` Step 0¾ does, so a future port degrades instead of instructing an absent tool), each question carrying 2–4 suggested answers + always-available custom fill, re-derived after every dialog, cluster size gated on **mutual independence**. `--socratic` pins grain to exactly 1 (NOT a third cadence — `guided` at grain 1; the two cadences differ on **WHEN** questions are derived, not how many appear at once) with an explicit ban on re-litigating the pin; `--battery` is opt-in, offered once and only past ~12 questions. ⚑ `socratic` was **repurposed rather than aliased** — it strictly means one-at-a-time, so aliasing it to a mode that clusters up to four would be a name misstating its own scope; existing staged files carrying `cadence: socratic` came out correctly labelled. ⛔ **A public-hygiene leak was caught by a mechanical PRE-PUSH sweep, not by review: the shipped hook comment named two internal projects** (this repo's zero-internal-names invariant, swept at v2.29.0). The CHANGELOG had been genericized and the hook was missed — the file that actually ships. Forward-fixed in its own commit rather than amended (target was 2 commits back; a rebase in a shared working tree is the bigger risk). ⚑ Also caught: a verification grep that printed nothing **because its path was wrong**, which read as "0 leaks — clean"; re-run with a **positive control** (4 hits) before the 0 was believed. ⚠ **Gate C observation, NOT verified as a defect:** `check-port-drift.sh` hashes each port's OWN file against a recorded snapshot, so it detects "a port file changed" and produced **no signal at all** for "canonical changed, port did not" — the direction this arc moved. No version-pair line appeared in this run; its trigger conditions were not exhaustively checked. Ports codex/cursor/antigravity/cowork remain tracked-drift (the hook has no counterpart; `/interview` reaches them at the next parity pass). ⚠ **The one leg that CANNOT be closed from the authoring session: hooks arm at SESSION START, so the real-`WebSearch`-containing-"guidelines" check must run in a NEW session.** — Prior: 2026-08-10 — plugin-claude-code **v2.45.0** (canonical only — **SHIPPED + PUSHED + INSTALLED**; `origin/main`=`c60801e`, 8 commits, ls-remote-verified; installed copy `cmp`-verified byte-identical to the smoke-tested source): **a rule that already existed, made to fire mechanically.** New `bin/pre-external-fetch-check.sh` — a PreToolUse hook on `WebFetch|WebSearch` that denies the FIRST fetch per session per surface when a recorded local reference covers it, names the matched paths, and passes on retry. Origin: an agent hit a Bitbucket auth wall and fetched Atlassian's docs twice while `feedback_read_recorded_reference_before_probing_known_surface` sat in memory — a memory itself written after that same failure once before. **So this is not a missing rule; it is a rule nothing surfaces at the moment it applies**, and adding more prose is the intervention that already failed. **Two cheaper designs died on measurement:** the existing `lib-index-match.sh` returned 5 files on the real URL, **5/5 about *design* tokens** — `api`+`tokens` cleared the ≥2-tag floor by homonym and `bitbucket` was not among the 362 known tags, so no tag match could reach the file that helps despite 36 index references to it (guard scoped to the wrong unit: the index is drawn around topics, the need around surfaces); and a cached domain inventory costs **7.32 s** against a 5 s timeout — measuring which revealed the inventory was never needed, collapsing the cache, its invalidation, and a `/usr/share/dict/words` dependency. **Design:** registrable domain from a URL, dictionary-filtered vendor stems from prose (capped at 4, **sorted** so the cooldown key is stable across a retry), grepped across `$KT_KNOWLEDGE_FOLDER` **and** `~/.claude/projects/*/memory` — both required, since `atlassian.com` lives only in the first and `bitbucket.org` only in the second, and that memory hit *is* the governing rule. Ambient surfaces above `external_fetch_max_hits` (8) stay silent; `github.com` at 76 files is why the cap exists. **It is an INTERRUPT, not a verification** — it cannot confirm the file was read, and no AC claims otherwise. **Both prospect gates caught what the other structurally could not.** Spec-prospect falsified two assumptions inherited by copying a precedent's *structure without its history*: the cooldown idiom from `pre-explore-codemap-check.sh` writes unchecked, safe THERE because that hook is **advisory** — in a **denying** hook a failed write is `deny → retry → deny`, unbounded (**C1**: write and verify BEFORE denying, allow if it did not land); and this is the plugin's **second** denying hook, inheriting none of the deny-rate circuit breaker `pre-edit-check.sh` gained in v2.30.0 **because that deadlock had already happened in production** (**C2**). **C3** bounds the script's own runtime (`ARIA_EF_BUDGET_S`, seconds — `date +%s` is whole-second, so a `_MS` name would promise precision the mechanism lacks) rather than trusting undocumented PreToolUse timeout semantics. Plan-prospect caught that **AC12 would have reported the breaker working while it never ran** — two of its three denials collapse to ONE registrable domain, so the counter reached 2 and the "4th call not denied" assertion passed via the **cooldown**; fixed with a third covered surface and a direct assertion on the breaker's counter file. **Execution found three more, all by running rather than reading:** a `case` pattern's `)` inside `$( )` is ambiguous with the substitution terminator and `sh` failed to parse the whole file — **and the first isolation test PASSED because it dropped the `$( )`, removing the feature under test** (fixed with the POSIX leading-`(`); **AC5 was a tautology** (green with `index` deleted from the stopword list, because the fixture held nothing a leaked stem could match); and an AC12 assertion passed **vacuously** with no counter file in existence. **Validation:** 136 assertions, 6 mutations each confirmed landed and restored byte-identical via `cmp`, and a **live smoke on the real 223 MB corpus + 3 memory dirs denying the exact incident URL and naming `staging-postgres-mcp-and-bitbucket-auth.md` in 1.28 s** — the check a green fixture suite cannot substitute for. **Gates:** A green · B **19,362 / 19,968, byte-identical to before** (body-only skill edits leave the description budget untouched — predicted, then measured) · C report-only. Diff **+1,609 / −1**, the single deletion being the version bump. **Deliberately skipped with reasons:** `PORT-LEDGER` untouched (`--quiet` showed no undeclared drift; Code-canonical with no port counterpart, same posture as `audit-style`); no `intake/` exclusion despite the smoke denying `twilio.com` on a transcript capture — measured first (2 files there, cap bounds to 8), revisit trigger recorded instead. **One of my own recommendations was falsified before it shipped:** after `bitbucket` was promoted to a known tag I proposed "try `kt_index_match` first, fall back to host-grep" — measured 6 doc URLs and **4 of 6 return a confident 5-file result, 3 entirely wrong**; the fallback condition was "returns nothing" while the real failure mode is "returns 5 confident wrong files," which preempts it. Root cause: generalising from one query that worked *because its tag had just been promoted in the same session*. Ports codex/cursor/antigravity/cowork tracked-drift (Bash hook, no counterpart). Design record: `docs/superpowers/specs/2026-08-09-local-reference-before-external-fetch-design.md`; plan + rejected amendment: `docs/superpowers/plans/2026-08-09-local-reference-before-external-fetch.md`. — Prior: 2026-08-02 — plugin-claude-code **v2.44.1** (canonical only — **SHIPPED + PUSHED + GH-RELEASED**; `origin/main`=`b23a792`, tag `v2.44.1` is Latest, all 6 stable aliases attached + all 5 site `/latest/` links 200, and the **published zip content-verified** rather than trusted): **the pre-commit preflight gate got its repo dimension, and the cwd bug that made its deny patterns silently stop denying is fixed.** Surfaced by a routine `/setup` run (2.43.1 → 2.44.0) whose Step 7e sweep flagged `preflight_gate` / `preflight_deny_paths` absent from the live config — the root cause being that **`/setup`'s Advanced Options bundle had never offered them**, so the wizard wrote and validated keys it never surfaced. Both defects sat in code that had **never shipped** (2.44.0 was unpushed). **D1 — deny patterns were pathname-expanded against the hook's cwd:** `for pat in $KT_PREFLIGHT_DENY_PATHS` is unquoted, so from a repo root `src/*` became the **17 literal entry names** inside `src/` and a staged `src/components/Foo.jsx` matched none; from the directory holding the file, `*theme.css` collapsed to the bare basename. The gate silently stopped denying and **which files were protected depended on where the tool was** — fail-open, scope wrong rather than threshold wrong. Fixed by `set -f` placed after `STAGED` is captured (covers the docs-filter loop too; `case` glob-matching is unaffected, which is exactly the split wanted). **D2 — no repo dimension:** `REPO_DIR` is resolved solely to run `git diff --cached` and never enters matching, and staged paths are repo-relative, so `*my-repo/*` matches nothing ever. New **`preflight_deny_repos`** — comma-separated substrings matched against the resolved absolute git toplevel (resolved deliberately: `REPO_DIR` is `.` whenever the command carried no `cd`/`git -C`), an **escalation independent of the baseline** exactly like `deny_paths`, with a new `WHY_KEY` so the denial message names the key that actually decided. Substring not equality — it over-matches a same-named sibling, and for a gate that is the safe direction since under-matching is the silent-stop failure D1 proved. **Ruled spec-first by Mike** (4 questions): 2.44.1 patch-on-top, no rewrite of the unpushed 2.44.0 commits · clear the cwd-fragile live value · substring matching · **docs stay excluded**, so a docs-only commit in a gated repo still passes silently — pinned by test `[14g]` as intended behaviour rather than left to be rediscovered. **`/auto` now satisfies the gate instead of colliding with it:** it had zero gate awareness, and the failure mode was not a stalled arc but **three denials tripping the circuit breaker and degrading the gate to allow-with-warning for the whole session**. An arc runs `/preflight` for real before its first gated commit (session-scoped marker = one run per arc), with three shortcuts named and forbidden because each looks like progress — writing the marker file, flipping `preflight_gate: off`, letting the breaker do the work. A recorded FAIL satisfies the gate and is explicitly not a stop. **BREAKING (minor): `/auto preflight` retired** as an alias for `/auto config` — one word had come to name both a settings picker and a verification gate. Retired rather than repurposed (every candidate meaning is owned by `/preflight` or `/prospect`; a third spelling adds a word and no capability — verbatim the `loop` reasoning), and **tombstoned rather than deleted**, because bare removal lets the token fall through to `mode = arc` and `/auto full preflight` would launch an arc building something called "preflight". The picker's own "Guided pre-flight" wording — the source of the collision — is now "Guided setup". Also shipped: **`/audit-knowledge` re-verifies capture-derived findings against HEAD** before presenting them as live (a capture records a moment, not current state; two findings had been surfaced as live security hazards after a same-day commit closed both by name). **Gates:** A all suites pass · B **19,362 / 19,968** bytes · C report-only. **Tests: 105 plugin + 36 repro suites, 0 failed**, every new positive assertion observed RED first — and **two of them were tautologies on first write**, caught only by running them against pre-edit HEAD (`degrade` matched an unrelated "Degrade gracefully" paragraph; `pre-answered` matched a section heading). One further lesson recorded: adding prose **neutered an existing test** — assertion `Y`'s `|preflight` alternative began matching unconditionally once ~10 `/preflight` references landed; the guard did not change, its corpus did. v2.43.1 had never been released, so 2.44.1 carries it. Ports codex/cursor/antigravity/cowork tracked-drift (this hook exists only in plugin-claude-code, so nothing to propagate). Design record: `docs/superpowers/specs/2026-08-01-preflight-repo-scoping-and-glob-expansion-fix-design.md`. — Prior: 2026-07-30 — plugin-claude-code **v2.43.0** (canonical only — **SHIPPED**; gates A/B/C green, Gate B **18,814/18,944**): **`/auto` gains three orthogonal axes + seven always-on standing directives; three rules that prose could not hold become mechanical hooks; the ticket-vendor lock is gone; and SESSION.md holds several valid prompts again.** Basis was empirical — **75 real `/auto` invocations mined from 328 local session transcripts** showed the same clauses retyped nearly every run ("local only" ~20×, "use MCP/plugins" ~8×, "set a croncreate" ~10×, the gate chain spelled out longhand ~6×), all of which `/auto` already did. A default the user cannot see is a default the user retypes. **Three orthogonal axes, one word each:** authority `full` (everything **except push**, which D4 makes ungrantable; raises the fan-out stopgaps but does not remove them) · presence `attended`|`unattended` (is a human reachable — two-valued, **always stated in the arc contract**, asked by `config`, defaulting to `attended`; decides whether a non-blocking residual is surfaced live or batched to the handoff) · duration `continue`|`stop`; plus `tickets` (tracker-bound selection + per-commit ticket comments). **No `loop`** — it reduced to a strict alias for `unattended continue` once resume-arming moved to the presence axis, had already drifted against `full`, and was the worst mid-prose collision (`/auto fix the render **loop** bug`); tombstoned + assertion-guarded. **Modifiers are matched only at the ENDS of the invocation**, never mid-prose. **A bare `/auto` opens the `config` picker** rather than inferring a goal from `SESSION.md` — modifiers and toggles say *how*, never *what*. **New `plan` mode** (prospected cold-executable plan, stops before code — the mirror of `execute`) and `arc` promoted to an explicit keyword. **Standing Directives D1–D7:** 5h binds / **7d ignored** with a 90% arm and 95% pause (ask rather than infer when no statusline) · prose-first scheduled prompts · foundational-always · local-only, push never grantable · live-model at checkpoints · non-blocking stops never idle · **the judgment ledger** (any decision failing the validated/deterministic/traced/confirmed-after test is logged to `<knowledge_folder>/logs/auto/`, reported FIRST at close; an empty ledger is *stated*, so silence and zero stay distinguishable). **Three hooks replace prose that had already failed:** `pre-cron-check.sh` (denies a `/`-leading scheduled prompt on both scheduling verbs — the prose form shipped in v2.37.3 and was violated twice after), `pre-bash-write-check.sh` (warns when a shell command mutates a file in place, bypassing the Rule 22 gate — **narrowed by measuring 25,508 real Bash calls**: creation is not the lapse, in-place mutation is; fires on 0.674%, ~1 in 148), `post-edit-tautology-check.sh` (warns on assertions that cannot fail, Rule 36 — and **discloses its own blind spots**, since a guard quiet about what it cannot see becomes the false green it exists to catch). **Vendor declass:** `/auto` (7 sites incl. frontmatter every user loads each session), `/prospect` (20) and `/retrospect` (10) — canonical `ticket`/`--ticket-post`, **every legacy `linear` spelling kept as an accepted alias** since those are published CLI contract; the tracker is probed (`/digest`'s pattern) and `ticketing_plugins` honored, never verifying a mapped command is installed. **`durable: true` removed** from Step 6 — the tool documents it as inert; scheduling is now gated on **availability**, with `CronCreate` retained as the only mechanism present in every runtime (a persisted scheduled task is a Desktop surface — corrected mid-arc after being wrongly promoted to default). **SESSION.md:** a never-skip invariant in `/handoff` + `/wrapup` (skipping loses your own opener — the worst outcome), demote trigger widened to any differing *or absent* `sessionId`, `sessionId` now **required** (an absent value made the guard unevaluable, which read as "does not apply"), `in-progress` never demoted, **unconsumed prompts kept at full fidelity**, and `## Prior sessions` → **`## Pending handoffs`** (calling still-valid work "prior" is what made demotion read as a downgrade). That required fixing a **confirmed leak** in `kt_ss_ledger_prune` — boundaries are now **declared** by an explicit terminator, never inferred, with a first pass keeping the legacy rule for old files. **aria-atlas (`2bfb596`) carried the same defect class and worse:** its parser truncated a realistic opener to ONE line at a column-0 `##` inside the fenced prompt; fixed by fence **parity** after length-matching was implemented and rejected for regressing the 3-in-3 contract fixture. **Gate B went DOWN 18,938 → 18,787** — the rewritten `/auto` description returns 132 B while adding the vocabulary. New repros `cron-slash-guard` (11), `lapse-guards` (27), `hook-json-extraction` (8), `tracker-agnostic` (13); `auto-modes` 68 → 118, `session-state` 33 → 44; **37 repro suites + 70 plugin tests green**; aria-atlas 274/274. Every positive case observed RED first. Built brainstorm→spec→/prospect→plan→/prospect→TDD; the two gates caught six defects between them, incl. a BSD-sed incompatibility and an unsupported regex backreference found by *executing* the plan's own snippets. Ports: Claude-Code-canonical; codex/cursor/antigravity/cowork tracked-drift. — Prior: 2026-07-25 — plugin-claude-code **v2.42.0** (canonical only — **SHIPPED + PUSHED + GH-RELEASED**; `origin/main`=`606f4b9`, tag `v2.42.0`, all 6 stable aliases attached + all 5 site `/latest/` links 200-verified; reinstalled locally and verified end-to-end from the published zip): **Rule 35's quality bar now binds asking as well as deciding (filter clause + malformed-ask diagnostic + `autonomy` levels table), canonical Rule 38 "Close the class", Rule 18/38 foundational escalation + waiver, and `user-rules.md` finally loads every session** via a new always-on SessionStart U-rule header index (previously reachable only inside `/auto` and `/rules`). Template `user-rules.md` now ships empty; 6 sample-detection consumers converted to an empty-state test. Gate A 32 suites + 70 tests; Gate B unaffected. Rule 38 withheld from the 3 ports still lacking canonical 36–37. — Prior: 2026-07-19 — plugin-claude-code **v2.41.0** (canonical only — **SHIPPED + PUSHED + GH-RELEASED**; `origin/main`=`ebc94d3`, tag `v2.41.0`, all 6 stable aliases attached + all 5 site `/latest/` links 200-verified): **new `/audit usage` sub-audit — a plugin user can now generate a value/ROI report over their OWN knowledge corpus.** The user-facing counterpart to the author's published `docs/value-analysis.md` (an N=1 digest). Investigated first: no skill did this (verified across all 34 skills); **rejected `/stats` as host** (its Rules explicitly forbid heavy analysis + recommendations, which a value report is) and chose the existing **`/audit` umbrella dispatcher** — composition REDUCED scope vs a new top-level skill. Three layers: (1) **`bin/usage-metrics.sh`** — deterministic POSIX-sh emitter (sources `config.sh`, reads `KT_KNOWLEDGE_FOLDER`) printing a labeled block: prospect verdict distribution + month buckets, retrospect outcome distribution + per-fix-verdict rate + month buckets, canonical pattern count, per-content-dir corpus counts, skill-discovery byte surface, audit-pass count; zero-corpus / missing-folder → zeros / one error line, never crash. **Single source of truth for the value-analysis reproduction recipe**; grep keys (`overall_verdict:`/`overall_outcome:`) live-verified against the real 547/201-log corpus. (2) **`skills/audit-usage/SKILL.md`** — shells out once via `bash ${CLAUDE_PLUGIN_ROOT}/bin/usage-metrics.sh`, writes a **sample-size-honest** analysis to `references/usage-analysis.md` (stamped `synthesized_at` + `measured_at_corpus`): trend tables render only for months with ≥10 logs, a zero corpus stops with "run some cycles first" rather than fabricating. **Opt-in only** (never cadence-fired, like `/audit style`). (3) **dispatcher wiring** — `usage` added to the grammar/menu (opt 4)/`all` (4th leg + tally)/unknown-verb/never-auto rule/prose ("four sub-audits"). `PORT-LEDGER` unchanged (Code-canonical-only, no port counterpart — same as sibling `audit-style`). New `tests/test-usage-metrics.sh` (15 assertions); full suite 70/0. **Gate B surprise: measured skill-discovery surface 18,938 B — 6 bytes UNDER the 18,944 budget, so NO raise (measured, didn't assume the spec's pessimistic prediction); the NEXT skill WILL trip it (flagged in CHANGELOG + commit).** Built brainstorm→spec→plan→/prospect [PROCEED-WITH-CHANGES: both flagged risks — bin-idiom + `check-port-drift --update` — auto-sourced ✅; 2 amendments folded]→TDD inline (executing-plans; one shared-context cluster, not subagents). **Release ceremony Claude-Code-canonical (Mike's call):** push (`e7955d9..ebc94d3`, ls-remote-verified) → `gh release create v2.41.0` → `publish-release.sh --apply` (all 6 stable aliases, reusing 4 unchanged port zips; all 5 site `/latest/download/` links 200). Ports codex/cursor/antigravity/cowork tracked-drift (reach `/audit usage` at next parity pass). Prior: plugin-claude-code **v2.40.2** (canonical only — **SHIPPED + PUSHED + GH-RELEASED**; `origin/main`=`0584f24`, tag `v2.40.2`, all 6 stable aliases attached + `/latest/` 200-verified): **bugfix — `/prospect`, `/retrospect`, `/foundational-review`, `/readiness-audit` now resolve every log path from the configured `knowledge_folder`, never a phantom `~/knowledge/`.** Two long-standing defects in these four skills' log-write / pattern-library-read instructions: (1) a **phantom path literal** — the write target + related-detection glob resolved to a bare `~/knowledge/logs/…` tree *outside* the versioned knowledge repo, so prospect/retrospect logs silently accumulated unversioned (40 stranded logs were discovered + rescued into the real repo 2026-07-17); (2) a **nonexistent config field** — the resolve instruction cited `knowledge_root`, which does not exist in `aria-knowledge.local.md` (the real field is `knowledge_folder`). The Step-0.5 surfacing code already resolved `knowledge_folder` correctly (`<knowledge_folder>/index.md`) — only the write/read instructions were wrong. **Fix:** every `~/knowledge/` → `<knowledge_folder>/` and every `knowledge_root` → `knowledge_folder`, mirroring the already-working Step-0.5 idiom verbatim; a `/prospect` run now resolves to `<knowledge_folder>/logs/prospect/…`. Lazy-create + grandfathering preserved; per-port config-file *locations* (`~/.claude/…`, `~/.gemini/antigravity/…`, `<knowledge_folder>/aria-config.md`) preserved — only field *name* + path semantics corrected. **Applied identically across ALL ports** (claude-code + antigravity + openai-codex + claude-cowork skill bodies, per ADR-013 byte-faithful bug; **plus the cursor port's compiled `aria-commands.mdc` + knowledge-mirror `foundational-review-chain.md`** — caught by Mike's "check all ports" prompt, since Cursor compiles/mirrors rather than nesting under `skills/`) + the claude-code `plugin.json` description phantom-path. Scope-widened from "prospect/retrospect Step 6" to also `/foundational-review` + `/readiness-audit` via a whole-plugin residual sweep (those carried the same dead-field bug in `<knowledge_root>` placeholder form, incl. an *independent* log-write at `foundational-review-chain.md`). 24 files; CHANGELOGs left as historical record (Rule 6). Release ceremony Claude-Code-canonical (bump + tag + GH release + 6 aliases); other ports fixed on-disk, tracked-drift cadence unchanged. Interim behavioral guard (write to `~/Projects/knowledge/logs/…` regardless of a stale installed cache) remains valid until the installed plugin is reinstalled from this release. Prior: plugin-claude-code **v2.40.1** (canonical only — **SHIPPED + PUSHED + GH-RELEASED**; `origin/main`=`283f762`, tag `v2.40.1`, all 6 stable aliases attached + `/latest/` 200-verified): **two body-only changes — `/auto` now loads user-rules.md + `/audit style` card wording fix.** **(1) `/auto` Step 0.4 — load + apply the user's standing `user-rules.md` for the whole arc.** `/auto` was wired to Rule 35 (the plugin-managed decide-vs-ask *routing* policy) but had no awareness of `user-rules.md` (the user's own *substantive* standing rules) — so an autonomous arc could run without applying rules the user already wrote down. New Step 0.4 resolves `knowledge_folder` from `~/.claude/aria-knowledge.local.md` (same as `/rules`), reads `{knowledge_folder}/rules/user-rules.md` if present, and holds each real rule as a **binding constraint applied wherever contextually relevant** (where a user rule speaks to the situation, it governs). **One carve-out:** a user rule does not govern where applying it would be actively detrimental or contradicts validated empirical proof with critical impact — and even then it **escalates as a legitimate stop** (surface rule + opposing proof + impact), never a silent override. Missing/sample-only file = "no standing rules," never a stop. Compose-not-duplicate (loads + applies, never restates content); arc contract gains a "Standing rules loaded" line + a Notes bullet distinguishing the two rule sources. **(2) `/audit style` card wording "laws" → "Your Rules"** — the "Your Working Style" card (Step 5 Part B) used "law(s)" for a passed rule (headings like "Work Laws"); renamed the 3 headings to "Your Rules — Work / Design Taste / Writing Voice" + changed every remaining prose "law(s)" to "rule(s)"; v2.40.0 anti-ditto-copy procedure on #1 preserved. Driven via `/auto execute` (mechanical → /prospect PROCEED; pre-mortem falsified two plan assumptions before any edit: sibling ports are NOT version-locked [bumped only plugin-claude-code] + the other 3 ports have NO audit-style skill [Code-canonical per ADR-094]). Both body-only → Gate B skill-budget unaffected; `./release.sh` green. Also a separate `chore` (`283f762`): `.gitignore` now ignores `__pycache__/`/`*.pyc`/`.pytest_cache/` (codex-port test bytecode). Full ceremony: push (2 commits incl. the previously-unpushed v2.40.0 footer `3c1838b`) → `gh release create v2.40.1` → `publish-release.sh --apply` (6 aliases, all `/latest/` 200). Ports: codex/cursor/antigravity/cowork tracked-drift (both skills reach them at a parity pass). Prior: plugin-claude-code **v2.40.0** (canonical only — **SHIPPED + PUSHED + GH-RELEASED + WEBSITE-DEPLOYED**; `origin/main`=`ed9fe4e`, tag `v2.40.0`, all 6 release assets fresh + `/latest/` 200-verified, ariaknowledge.com updated to v2.40.0 + both new commands): **New `/audit` dispatcher + new `/audit style` log-mining sub-audit — ports two ditto ideas.** `/audit` is a thin umbrella router over the three sub-audits (`knowledge`/`config`/`style`), doing no scanning itself. `/audit style` mines the local session-log corpus (`~/.claude/projects/{cwd-encoded}/*.jsonl` via Bash + bundled `extract-user-prose.py`) for revealed working-style rules — proven by what you actually did, not invented — gated on a **fail-closed dated-receipts requirement**: a candidate rule ships only with ≥2 distinct sessions of dated verbatim quotes, no matter how plausible it otherwise reads. Surviving candidates stage to the rules backlog for normal audit review; opt-in; default writes nothing to memory. **Output surface (dogfood-refined):** every rule stated individually (passed + dropped, each with reasoning) + a **"Your Working Style"** card (Reasoning Type derived per-run from top rules with a hard anti-copy ban on ditto's naming shape; through-line; ARIA-unique elements a raw-log tool can't produce — corroboration-vs-existing-memory, inferred blind-spots, decision-discipline fingerprint from ADR/prospect/retrospect artifacts) written to `references/working-style/card-<date>.{html,md}`; single merged disposition gate (keep-staged [default] / promote-now / specify / cancel). **3 live-validated mechanisms:** skip `agent-*` subagent sessions (pre-filter before the over-cap count); reuse a prior external mine (e.g. an archived ditto run) as an incremental boundary → delta-only mining; `extract-user-prose.py` drops `<task-notification>`/system-notification blocks. Both skills carry the standard ADR-094 Runtime Gate (Cowork-native variants: `/aria-cowork:audit`, `/aria-cowork:audit-style`). Minor bump (new-capability skill surface). **Ports:** Claude-Code-canonical only this round; codex/cursor/antigravity/cowork tracked-drift (both ideas reach them at next parity pass). Also this arc: **codex-port test fix** (`ed9fe4e`) — `test_codex_port.py` pinned a stale version literal (`2.35.2-codex.0` vs manifest `2.36.0-codex.0`); replaced with a shape regex so it never re-stales; codex alias rebuilt + re-published to the release. ditto run archived at `knowledge/references/ditto-20260715/` (0 new rules vs the 400 hand-authored `feedback_*.md` — confirmed port-the-ideas-not-the-tool). Prior: plugin-claude-code **v2.39.1** (canonical only): **`/auto` Step 5 — dispatch-grain principle: once you fan out, one agent per shared-context cluster, not per item.** A body-only paragraph added to Step 5 ("Subagents & fan-out"), composing with (not overriding) Step 5's existing inline-first *whether*-to-delegate default: it governs the *grain* once delegating. The intuitive one-agent-per-item is usually the wrong default — it pays a **double cost**: redundant context re-loading (N agents re-derive the context their items share — spending the very context delegation meant to save) + seam-blindness (a per-item agent can't see neighbor items → locally-reasonable, globally-wrong at the seams: divergent identifiers, missed cross-item constraints). Default grain = one agent per cluster of items sharing a context (file neighborhood / repo / doc / domain), keyed on *what they share*, not *how many*. Split to per-item ONLY on one of three forces — **write-contention** (two agents can't edit one file set → serialize or split waves), **per-item auditability** (a clean per-task review gate a blended report would blur — code earns it, inline content usually doesn't), **context-ceiling** (cluster won't fit one agent's window with accuracy to spare). Distilled from Mike's refined hypothesis + `knowledge/approaches/parallel-subagent-orchestration.md`'s new "Default grain" thesis section (which reframes the doc's 10 patterns as evidence for it) + a one-bullet pointer in `mike-engineering-standards.md` §6. **Body-only edit — Gate B skill-discovery budget unaffected** (measures frontmatter descriptions only; live 17,721/18,944). Patch bump 2.39.0 → 2.39.1 (body/framing-only, per the v2.38.1 precedent). Ports: Claude-Code-canonical only; codex/cursor/antigravity/cowork tracked-drift (Step 5 reaches them at next parity pass). Local zip `aria-knowledge-plugin-2.39.1.zip` built, all gates green. Prior: plugin-claude-code **v2.39.0** (canonical only): **New `planning_paths` config key — the inverse of `critical_paths` for the Rule 22 hooks.** A user declares path patterns that DOWNGRADE an Edit/Write to the abbreviated `[Rule 22 · Planning]` marker (marker still required, only the format is lighter) — the mirror of `critical_paths` (which upgrades to full assessment). **Protect always wins:** the planning loop runs after the critical-paths loop and the EXPECTED decision only honors planning when `IS_PROTECTED=false`, so a both-critical-and-planning path correctly resolves to full assessment. Both hooks (`pre-`/`post-edit-check.sh`) also gain a built-in scaffold glob `*/.claude/skills/*/templates/*` so skill scaffold templates auto-downgrade with no config (closes the scaffold false-positive). `config.sh` parses `planning_paths:` (no default — empty = built-in glob only). Wired across `/setup` (config-write + validation + empty-sentinel), `CONFIG.md`, `QUICKSTART.md`; `/audit-config` Step 3b enumerates it automatically. New `tests/test-r22-planning-paths.sh` (10 assertions); full suite **55 passed, 0 failed**. Minor bump (new config-key capability every user inherits via `/setup` diff, per the v2.35.0 `autonomy`-key precedent). Ports: Claude-Code-canonical only (Bash hooks); codex/cursor/antigravity/cowork tracked-drift. (Feature was in-flight uncommitted work from a parallel session, completed + wired + verified this session.) NOT released/tagged this round. Prior: plugin-claude-code **v2.38.1** (canonical only): **Behavioral Foundation framing — strictness tiers + a genuine-ties tie-breaker.** Two additive paragraphs in `template/rules/working-rules.md`'s Behavioral Foundation, no new numbered rule / no renumber / rule count unchanged — making explicit what the ruleset already enforced implicitly: (1) **two strictness tiers** — gates (rigid; the verification/authorization rules e.g. 20/22/33/34/35; surface a blocking gate, never route around it) vs defaults (judgment-applies, deviate-and-say-why); when unsure, treat as a gate; (2) **tie-breaker for genuine ties** — equal-merit options prefer reversibility + audit trail, explicitly NOT a bias against irreversible choices (a clearly-correct irreversible option isn't a tie — it runs through Rule 35's authorization gate, surface-and-get-the-go-ahead). Distilled from `knowledge/approaches/portable-working-method.md`. Patch bump (framing-only, additive). Ports: Claude-Code-canonical only; codex/cursor/antigravity/cowork tracked-drift (reaches them at next template-sync). Also fixed the pre-existing stale count in the `plugin.json` description ("35 working rules" → 37, accurate since v2.38.0's Rules 36/37). NOT released/tagged this round. Prior: plugin-claude-code **v2.38.0** + plugin-claude-cowork **v1.5.0** (coordinated): **two new universal working-rules + two strengthened, synced to both Claude ports.** Distilled from Mike's `knowledge/approaches/mike-engineering-standards.md` via a gap-analysis against the enforced ruleset; only the *principle-level, domain-agnostic* items were universalized (mechanics like the `&& git commit` exit-trap stayed personal). **New Rule 36 — "a pass signal only counts if it can fail for the right reason"**: bind a gated conclusion to the load-bearing result, never a proxy (pipeline-last-command, transport status, absent-guard-a-negative-only-test-can't-detect); a validated confirmation isn't fully valid until its *failure* is equally understood + validated (both pass AND fail matching intended outcome); mechanical understanding of *why* it passes/fails is what makes validation generalize across contexts/variants. **New Rule 37 — "anything temporary names its own removal trigger up front"**: first justify temporary-ness vs a foundational alternative (Rule 18), then any temporary thing (code/doc/config/stub/deferral/flag/workaround) carries a documented context+trigger+condition+timing for removal at introduction, never a someday-ticket. **Strengthened Rule 15** (a guard test needs a positive case, not only a negative — RED→GREEN per guard) + **Rule 21** (full ADR shape: alternatives-with-rejection-rationale + multi-dimension consequences + the forward-looking downstream commitments the decision dictates). **Cowork sync also closed a real drift**: cowork's `working-rules.md` was missing Rule 35 entirely (a v2.35.0 tracked-drift gap) — brought to full canonical parity (35+36+37), preserving only the `/aria-setup` header divergence. working-rules.md 35→**37 rules** (all count refs synced); Gate B budget 17186/18944 (rules are template content, not frontmatter — unaffected); cowork description cap 8863/9000 (unaffected). Minor bump (new universal rules = capability surface every user inherits, per v2.35.0 precedent). Ports: synced to **plugin-claude-code + plugin-claude-cowork** only this round; codex/cursor/antigravity stay tracked-drift (rules reach them via template sync at next parity pass). Prior: plugin-claude-code **v2.37.3**: **/stitch trigger reframe + /auto fork/cron sharpening (2 commits).** (1) **`/stitch` no longer keys "does this apply?" on git-repo count** — the load-bearing condition is **≥2 distinct codebases bound by a shared contract** (separate repos OR a monorepo `contract/` → `ios/`+`android/`+`backend/` seam). Reframed across the `group-loader` shared block (byte-identical in `/stitch` + `/distill`; scan now detects `contract`/`openapi`/`proto`/`graphql` + `ios`/`android`/FastAPI markers), the stitch-specific hard stop, and `/context`'s skip parenthetical. The old "requires a multi-repo group" hard stop would have wrongly rejected a monorepo keystone. (2) **`/auto`** — cron resume prompts MUST lead with prose (a leading `/command` parses as unknown and silently discards the mandate; cross-refs the Step 3¾ rule); + a **"measure before escalating"** ratchet (a reactive fix-forward cascade is a smell to probe the dissolving upstream change, not a load-bearing fork to escalate). Prose/body-only, additive; **no description-frontmatter change** (skill-discovery budget 17186/18944, unaffected). Also bundles the prior **handoff fence fix** (`a113b59`, all 4 ports — `'Read on resume:'` moved INSIDE the opener fence so it survives copy-paste). Gates: 55/55 tests green, budget PASS, no new port drift. Commits `a113b59` + `ad46525` on `main`. Claude-Code-canonical for the /stitch+/auto edits (ports tracked-drift); handoff fix already applied to all 4 ports. Prior: plugin-claude-code **v2.37.2** (committed, UNRELEASED): **`/auto` context-window self-restart — an unattended `continue` arc survives the context wall.** New opt-in trailing flag `self-restart` (invocation-scoped, gated on `continue` AND the flag; default OFF = behavior unchanged) plus a shipped external wrapper `plugin-claude-code/bin/auto-runloop.sh`. The problem: an unattended `/auto … continue` run previously HALTED at the 90%-context wall until a human restarted it (a cron can't help — it re-enters the *same* full session; and the skill/hook **cannot** issue `/clear`, both verified live this arc). The fix splits responsibility: at the context wall under the flag, the skill (new **Step 3¾**) runs `/extract` → `/handoff` (prose-first self-sufficient opener → `SESSION.md`) → writes a one-line **restart-signal file** (`<cwd>/.claude/auto-restart-requested` = opener path; marked `[SELFRESTART-PRE]`) → stops cleanly (it NEVER `/clear`s). The wrapper — an **exit-driven loop** — watches for that signal on process exit, consumes it (crash-safe), and relaunches a **FRESH** `claude -p --dangerously-skip-permissions` headless process (clean context, exits with a status code the loop reads), looping until an arc completes with no signal. **Headless `-p` is load-bearing** (interactive `claude "prompt"` never self-exits → loop hangs); verified vs the official CLI ref. **Two-gate permission honesty** (documented as a copy-when-needed example in the skill's Notes, NOT applied to live settings): the wrapper clears the `permissions.allow` gate via an allowlist rule, but the **auto-mode classifier is a SECOND gate** that `permissions.allow` does NOT override — so run it with auto mode OFF or via org `autoMode` trust. **Validation:** new repro `auto-runloop.sh` (mock-claude drives the loop, 10/10) + `auto-modes.sh` SR block (68/68); 26 repros + 55 plugin-tests green, no regressions; frontmatter untouched (Gate B skill budget unaffected); **live end-to-end smoke PASSED** (real `claude -p` exit 0, file created, prose-first guard held, no spurious restart on a done task). Built brainstorm→design→/prospect [PROCEED-WITH-CHANGES: SHRINK signal contract to one-line + headless-not-interactive]→TDD (RED→GREEN both pieces)→live smoke. Patch bump 2.37.1→2.37.2 (additive, opt-in, zero default change); commit `173e723` on `main` (UNPUSHED) + this footer follow-up. Claude-Code-canonical (Bash + CLI); other ports tracked-drift. Prior: plugin-claude-code **v2.37.1** (TAGGED + GH-RELEASED): **lateral orientation pair — new `/roadmap` skill + `/recap project` mode.** **New skill `/roadmap`** — a per-project feature roadmap rendered as a `Feature / Band / Status` grid (Band = Shipped/Current/Next/Later, the version-trajectory axis; Status = one of ✓done / ◐in-progress / ⛔blocked / ▷buildable), **synthesized from CLAUDE.md + PROGRESS.md** and **persisted to a committed `ROADMAP.md`** with **source-stamp staleness-aware refresh** (`synthesized_at` + `synthesized_from_commit` in frontmatter; stale ⇔ any source mtime > stamp OR `git log <commit>..HEAD` non-empty; **render-then-offer** — shows the persisted grid then offers a refresh when stale, writes only on `y`/`/roadmap refresh`, never auto-commits). **Buildable is the only inference** (▷ ⇔ Band=Next ∧ no blocker found; ⛔ cites its blocker phrase; evidence blocks below the grid keep it falsifiable; overridable). Modes: `/roadmap` (nearest), `/roadmap <name>` (a `projects_list` tag — verbatim `/recap` resolver, read-only on the roster, unknown tag lists tags), `/roadmap refresh [<name>]`. **Hand-authored guard:** a `ROADMAP.md` with no `synthesized_at` stamp (e.g. df's tracked portfolio roadmap) is treated as hand-authored — notify + render as-is + never overwrite without `/roadmap refresh`. **Reuses two in-family templates, no new machinery** — `/codemap`'s persist+`allowed-tools: Read, Glob, Grep, Bash, Write` pattern and `/recap`'s `projects_list` resolver. New repro `roadmap-modes.sh` (29 assertions green); full suite 26 repro-suites + 55 plugin-tests green; skill-discovery budget 17664/18944 (no re-baseline). Built brainstorm→spec→/prospect [PROCEED-WITH-CHANGES: confirmed reuse templates + caught the df portfolio collision]→plan→/prospect [PROCEED-WITH-CHANGES: caught an empty+stale PORT-LEDGER, corrected to a version-bump]→TDD execute→live-data dogfood (df no-clobber verified; conservative buildable correctly showed zero false-greens). **Also in v2.37.1: `/recap project` mode — lateral cross-project orientation.** A trailing second arg selects breadth: `/recap project` (current session's main project, Step-1 walk-up from cwd) · `/recap project <name>` (a named project — the `<name>:` tag in `projects_list`; unknown tag lists tags, no fuzzy match) · `/recap project all` (roster glance across every `projects_list` entry). **Reuses canonical surfaces, no new machinery:** roster from `projects_list` read as `/aria-assist` reads it (**read-only on it**); per-project state from `SESSION.md` (`lastEvent` + next-prompt) + `PROGRESS.md` (latest arc + open items); git rows (`log -1`/`status --short`) only when the dir is a git repo AND Bash is available — silently omitted otherwise (per-project version of the Runtime-Gate Bash check); all reads tolerant (missing/malformed → blank row, never throws). **Two output shapes:** single-project = full orientation in the standard `What/Where/Status` table with an indented `↳` context sub-row per item; roster = terse rows + one ~6-word in-flight fragment, recency-sorted, `+N more (older)` tail. Always prints the resolved path (single)/roster total (all). Escalation offer (never auto-run): single→`/retrospect`, roster→`/aria-assist`. **Read-only preserved** (`allowed-tools: Read, Glob, Grep, Bash`). `recap-modes.sh` +9-assertion group G (22 green); full suite 45 green, all 25 repros green. **Ports:** Claude-Code-canonical only — codex/cursor/antigravity/cowork tracked-drift. **Now tagged + GH-released as part of v2.37.1** (the lateral-orientation pair shipped together). Built execute-mode via `/auto` (spec → /prospect [PROCEED, 4/4 pre-validated] → plan → execute → gates). Prior: plugin-claude-code **v2.37.0**: **New skill `/auto` — the entry point for an autonomous execution arc.** A single `/auto` drives the full gate chain (brainstorm→spec→/prospect→plan→/prospect→TDD→/retrospect) under the Rule 35 posture without per-step approval, deciding objectively-validatable forks itself and stopping only on a load-bearing fork or an ungranted approval. **Three modes:** `/auto [goal] [continue|stop]` (full arc; `continue` keeps finding new work after the queue for unattended/overnight, `stop` checkpoints+handoff — default), `/auto execute <plan|spec|linear-id>` (skip ideation), `/auto config` (alias `preflight` — guided one-knob-at-a-time picker, per-run, never persists; the answer to "I won't remember the knobs" — recognition-not-recall). **Option A — explicit override of the `autonomy` config:** runs fully autonomous regardless of the standing posture (incl. `default`); **never writes config** (`/setup` is the sole writer of the `autonomy` key — one writer, no drift); the invocation IS the grant. Named `/auto` for uniformity with Claude Code's "auto mode." **Compose-not-duplicate:** the decide-vs-ask logic stays in Rule 35 (the skill instantiates the routing table, never re-lists it); the skill adds only operational discipline (pre-answered never-stops, verify-before-trust, budget-binding usage→cron/context→handoff, work-selection, three fan-out stopgaps, optional resume-cron, knowledge-capture). **Absorbed the prior paste-at-top-of-session mandate** (`knowledge/AUTONOMOUS-SESSION-TEMPLATE.md`, now a tombstone) as single source of truth — coverage verified 43/43 by a mechanical claim-by-claim diff. **Three orthogonal fan-out stopgaps** against usage runaway (the NEED-IT gate is a per-spawn check, NOT a budget ceiling): Workflow opt-in (count-burst, hard-OFF by default), budget-fraction pre-flight gate (spend-burst, ~25%/burst overridable), cumulative per-arc subagent cap (~10, drip). Resume cron fires **+5 min after** the 5-hour reset (avoids firing into a not-yet-reset window). New repro `auto-modes.sh` (61 assertions); skill-reviewer Pass; dogfood-validated live (the `config` walkthrough ran end-to-end). **Ports:** Claude-Code-canonical only — codex/cursor/antigravity/cowork stay 2.36.0 tracked-drift (Cowork's summed-description cap is already at ~9,389/9,000 *before* `/auto`; propagation needs a dedicated Cowork trim pass). Built via `skill-creator` + `skill-reviewer`; tag [v2.37.0] + GH release + 6 stable aliases (200-verified) + README + aria-site (v2.37.0 badge + `/auto` on feature-list, deployed live). Prior: plugin-claude-code **v2.35.0**: **Rule 35 (decision routing) + `autonomy` config posture — the ask-vs-decide policy is now binding, not hand-restated.** The decision-routing policy (investigate-first; spend the human's scarce decision budget only on what the agent can't resolve) lived only in ~14 non-binding `feedback` memories, so it had to be re-typed each session. Now: **Rule 35** in the plugin-managed `template/rules/working-rules.md` (universal) consolidates the calibration — decision-budget economics + routing table (resolvable→investigate→act · objectively-validatable→decide+show · mechanical/already-decided→act · intent/preference/no-gainable-visibility→ask · ungranted-explicit-approval→ask) + sequential composition; the validatable-decision bar is the existing Rules 13/14/18 (referenced, not duplicated). The **`autonomy` config key** (`default`|`balanced`|`autonomous`, ship default `default`) gates a scaled SessionStart directive: `default` injects nothing (zero behavior/context cost — safe failure mode); `balanced` = light investigate-first; `autonomous` = full posture (decide validatable forks yourself vs 13/14/18, gates-as-checks-not-stops, stop only on no-visibility judgment call or ungranted approval). Parsed by `config.sh` (auto-wires Step 7e; hook reads `$KT_AUTONOMY`), surfaced in `/setup`. New repro `autonomy-posture.sh` (Rule 35 + default-no-inject + balanced/autonomous emission via the picker-gating KT_CONFIG-stub technique); 22 suites green. Built brainstorm→spec→prospect→plan→prospect→execute; an execution-time refactor moved the parse from inline-sed to config.sh (cleaner, single-source, auto-recognized by 7e). Distribution: every existing user gets a Rule 35 diff on next `/setup` (intended). Rule 35 reaches all ports via the shared template; the injection is Claude-Code-canonical. Prior: plugin-claude-code **v2.34.0**: **New skill `/recap` — read-only orientation.** A scannable `What / Where / Status` table of *what just happened*, to situate the current reader at a glance — the orient-side counterpart to `/handoff` (packages for the *next* reader), and distinct from `/retrospect` (recap summarizes, never validates; may *offer* to escalate). Five modes by input: `/recap` (this session, conversation synthesis) · `arc` (last product arc from the nearest PROGRESS.md heading; states the inferred boundary) · `commit [<hash>]` (`git show`) · `push` (`git log @{push}..HEAD` — what I sent up) · `pull` (`git log ORIG_HEAD..HEAD`, reflog fallback, always prints the resolved range — what came down to me). push vs pull surfaced as opposites. **Read-only by construction:** `allowed-tools: Read, Glob, Grep, Bash` — Write/Edit excluded so the runtime can't write even if prose drifts; the one pure-read skill in the family. New repro `recap-modes.sh` (5 modes + pull resolution + table + no-Write invariant); 21 suites green. Built brainstorm→spec→prospect→plan→prospect→execute; both prospects PROCEED (the 2 inherently-soft modes — pull-fallback, arc-boundary — made safe by transparency: each prints/states its inferred scope). Claude-Code-canonical (git modes Bash-native); not added to other ports this round. Prior: plugin-claude-code **v2.33.0**: **`/intake` consolidation — `/clip`, `/clip-thread`, `/extract-doc` retired into `/intake`; clippings review gap closed.** `/intake` now dispatches by input shape: a single URL/text **clips whole** → `intake/clippings/`; files/dirs/globs **bulk-scan** → backlogs; `/intake extract <src>` **decomposes** (incl. a `~~docs`-MCP doc, absorbing the former extract-doc); `/intake doc <src>` = the 5-section reflection artifact; `/intake thread <id>` pulls a chat/email thread via MCP (absorbing the former thread-capture; auto-detects a chat URL). Only `extract`/`doc`/`thread` need a keyword. **Behavior change:** a bare URL CLIPS WHOLE now (was: mine-to-backlogs); mine via `/intake extract <url>` or let audit decompose later. The 3 retired skills moved to `skills/.archived/` with pointer headers (per Rule 6); their triggers absorbed into `/intake`'s description so discovery survives; bare-slash collision set 24 → 21. **`/audit-knowledge` Step 2f (Review Clippings) NEW** — audit never scanned `intake/clippings/`, so clipped/hand-dropped items were never reviewed (`/clip`'s "reviewed at next audit" was a dead-end, caught at spec-prospect); Step 2f scans clippings → backlogs → ledger-clear. MCP modes Code-native once authed (authenticate prompt, not Cowork redirect). New repro `intake-dispatch.sh` (grammar precedence + Step 2f + retirement + no-dangling-ref gate); 20 suites green. Built brainstorm→spec→prospect→plan→prospect→execute; the spec-prospect caught the audit-clippings dead-end (turning the consolidation into also a bug-fix), the plan-prospect confirmed `release.sh` Gate B's glob auto-excludes `.archived/`. Claude-Code-canonical; bare-slash removal to propagate to other ports at next parity pass. Prior: plugin-claude-code **v2.32.0**: **SESSION.md multi-session ledger + nested-workspace routing fix** (Claude-Code-only; gated on `session_state`). A project's `SESSION.md` now holds N sessions instead of last-writer-wins clobbering: the newest unconsumed handoff stays in the front-matter + `## Next session prompt` (aria-atlas's single-active view, unchanged), while prior sessions are demoted into a new `## Prior sessions` body section the atlas parser ignores by construction (it stops at the first `## ` after the prompt — zero atlas changes, no fixture changes, only a new `handoff-multi-session.SESSION.md` fixture added). **Keep-until-consumed:** `/handoff` demotes the prior active entry (`kt_ss_ledger_add`, single-line prompt) + prunes already-consumed entries (`kt_ss_ledger_prune`); a resume stamps the prior handoff `consumed` via `kt_ss_ledger_mark_consumed` inside `post-edit-check.sh`'s existing once-per-(session,project) guard (fires once per resumed root, not per edit); `/wrapup` prunes without adding itself. Nothing unconsumed is silently lost — time never evicts (latched-state discipline); the new `session_stale_days` config key (default 7) instead triggers a "still relevant? [resume/archive/keep]" prompt at session start. **Routing fix:** `kt_ss_find_root` now skips a workspace-index root marked `aria_workspace_root: true` (CLAUDE.md line) or `.aria-workspace-root` (sentinel) and walks to the nearer real sub-project root — closing the bug that wrote a spurious `SESSION.md` at nested containers. New repro sections I/J/K/L (routing/ledger/consume/atlas-isolation guard); 19 repro suites green. Built brainstorm→spec→prospect→plan→prospect→execute; TDD on the `## Prior sessions` body-awk caught 2 portability bugs (multi-line `awk -v`; heading-to-stdout). **Ports:** Claude-Code-canonical only; cowork/codex/cursor/antigravity tracked-drift (SESSION.md producer is Bash + Claude-Code-only since v2.22.0). Prior: plugin-claude-code **v2.30.0**: **structural consolidation — self-enforcing gates replace prose-and-vigilance.** A foundational review found the two highest-stakes surfaces (Rule 22 enforcement; the five-port distribution) governed by hand-vigilance, both having already produced their failure class twice. Three additions, no user-visible change but a degraded-mode banner: (1) **deny-rate circuit breaker** in `pre-edit-check.sh` — a per-session counter (`${TMPDIR}/aria-r22-denies-<session_id>`; transcript-basename fallback; disabled if neither resolves) trips after **3 consecutive denials with zero intervening compliant edits**, degrading to allow-with-loud-`systemMessage` instead of deadlocking; a compliant edit resets it (self-healing under any future transcript-format change; supersedes per-model parser patches). (2) **release gates** in `release.sh` (parity with `release-codex.sh`): Gate A runs both test suites, Gate B enforces an `ARIA_SKILL_BUDGET` skill-discovery byte budget (**default 18944**, re-baselined from 16384 after v2.29.0's two review skills; live ≈17979), Gate C runs the drift checker report-only (TODO v2.31.0: fatal); also fixed a latent bug where the canonical zip shipped `plugin-claude-code/tests/` (added `--exclude='tests/'` + verify + clean rebuild). (3) **machine-readable port-parity ledger** `PORT-LEDGER.json` + `bin/check-port-drift.sh` (per-surface sha256 + version-pair trap; modes table/`--quiet`/`--update`) replacing prose tracked-drift narration; `sla` ships `undeclared` (a separate gated decision). New repros (`r22-circuit-breaker`, `port-drift-check`); 19 repro suites + 35 plugin tests green. **Ports:** Claude-Code-canonical only; cowork/codex/cursor/antigravity tracked-drift, now recorded in the ledger (no re-sync this release). Prior: plugin-claude-code **v2.29.0**: **two new review skills — `/foundational-review` + `/readiness-audit`.** Productizes the foundational review chain as Code-canonical skills that **transclude** a plugin-bundled, genericized canonical process doc (`skills/foundational-review/foundational-review-chain.md`) rather than forking it — both read it at Step 1, preferring a user's richer `<knowledge_root>/approaches/foundational-review-chain.md` copy when present, else the bundled one (self-contained on fresh installs, no broken reference). `/foundational-review <scope-root> [--decision …] [--extend]` is **decision-anchored** (verdict + premises + sections A–F + irreversibility inventory → design spec → cold-executable plan w/ owner routing → composed `/prospect` with amendments applied in place → paste-ready kickoff; **redirects** to `/prospect` or `/readiness-audit` if no irreversible decision is named). `/readiness-audit <scope-root> [--for …]` is the recurring surface sibling (controller **re-verifies every load-bearing agent claim** + correction trail, **read-only probes + mandatory `git diff --stat` artifact check**, tiered evidence-celled findings Tier 0/High/Med/Low, phased remediation — findings are not a shipping list). The effort-ladder + coupling-mechanism grouping heuristic were folded in from `Projects/fable5-prompts.md` (which stays the per-session tracker + copy-paste source, now pointing at the skills); the 2026-06-10 "productize fable5-prompts as a skill" idea was marked Superseded. `/help` (command table + Model Recommendations row) + README (prose + capability table) updated. **Public-hygiene:** all shipped files genericized — zero internal project/session names (verified by sweep). **Ports:** Claude-Code-canonical only; cowork/codex/cursor/antigravity tracked-drift (cowork's 9000-char summed-description cap is full — a cowork variant needs a coordinated trim pass). Prior: plugin-claude-code **v2.28.1**: **statusline reasoning-effort suffix.** The `/effort` level now renders as a compact letter after the model name (`Opus 4.8 (1M) H` at high; mapping `L`·`M`·`H`·`XH`·`MX`, max→`MX` to dodge medium's `M`). `statusline-meter.sh` parses the CC statusline JSON's `.effort.level` (verified exposed via claude-code-guide → official docs: reflects live mid-session `/effort`, absent when the model has no effort param). Display-only — `$model` stays bare so the state-snapshot (consumed by usage-inject + SessionStart readers) keeps the raw model name. `/statusline` skill example (`Fable 5 H`) + bullet + demo payload + script header updated. **Claude-Code-only** (status line is a Code feature); re-run `/statusline` to refresh the installed mirror `~/.claude/aria-statusline-meter.sh`. Prior: plugin-claude-code **v2.28.0** RELEASED + plugin-claude-cowork **v1.2.0** RELEASED (both tagged + GH releases w/ assets; `main` pushed `59d2237..bce3dd8`): **`snap` mode for `/wrapup` + `/handoff`.** A new mode = **`auto` + one swap**: runs the full silent close-out/handoff (PROGRESS/CLAUDE/memory/commit + handoff's next-session opener) but archives the transcript via `/snapshot` for later extraction **instead of** running `/extract` now — for when context is high and a live `/extract` would risk compaction mid-synthesis. Defining override is the capture step (wrapup Step 8 / handoff Step 6: snap→`/snapshot`, auto→`/extract`); every per-step auto-conditional now reads `auto (or snap)`; invariant = snap **defers, never drops** capture (the snapshot always runs, no skip path). `/help` advertises `[auto|snap]` / `[auto|brief|snap]`. **Cowork v1.2.0** ports snap with adaptations: namespaced `/aria-cowork:snapshot`, **no Bash dependency** (cowork's 3-path snapshot), terser descriptions to clear the 9000-char summed-description cap (build at 8972; `release.sh` preflight caught a 9143 overage → 2 trim passes — trust the build gate, not a hand count), + fixed a pre-existing `/handoff` Step-7 duplicated-checklist-row bug. **Not ported (tracked-drift):** cowork's `/handoff` model-recommendation rubric (Suggested-next-session + Fable-5 prose); codex/cursor/antigravity all tracked-drift. Also: the dangling **v2.27.2** docs-footer commit (`ffbc47d`) was finally pushed in this arc (it had been committed-but-unpushed despite the footer claiming "pushed"). Prior: plugin-claude-code **v2.27.2** (canonical only — pushed 2026-06-10 in the v2.28.0 arc): **Fable 5 readiness.** Mike's Claude Code default is now Fable 5 (`claude-fable-5[1m]`, 1M context, tier above Opus, $10/$50). Runtime is already model-agnostic (statusline reads `model.display_name`; usage/context hooks are percentage-based), so this was docs-only: `/handoff` + `/help` model-tier prose gained `Fable` as the top tier (de-version lists, effort ladder, advisory notes; rubric/table rows unchanged per minimal-touch); `/statusline` example refreshed to "Fable 5". **v2.27.2 corrected v2.27.1**: window size is NOT the Fable-vs-Opus differentiator (both are 1M) — re-anchored on capability/judgment (Fable for extreme difficulty; Opus 4.8 the default at half the price). plugin-antigravity skill mirror = tracked-drift (carry both 2.27.1 + 2.27.2 framing at next parity pass); cowork/codex/cursor have no model tables. Prior same-day: plugin-claude-code **v2.27.0 RELEASED** (tag + GH release w/ zip; also retro-tagged + GH-released the dangling **v2.26.0** picker version). **ARIA Assist morning-run schedule surfaces in aria-atlas (read-only).** `pm-schedule.sh`/`pm-morning-run.sh` write a global `<pm_digest_dir>/.aria-assist.json` overlay (via new `apm_write_assist_status` jq deep-merge helper in `pm-lib.sh`) — `schedule` section (enabled/time/label) on install/uninstall + `lastRun` per run; aria-atlas reads it for a read-only "Morning run" card (toggle stays aria-side; atlas never shells to `launchctl`). **Fix:** `pm-schedule.sh` octal crash at hours ≥ 08 (`printf '%d'` on leading-zero hour → base-10 `$((10#$HOUR))`; latent at the 07:30 default). **Fix:** removed `/wrapup` token from `/handoff` description (slash-picker pollution). **Test:** revived the `pm-*` repro harness into `plugin-claude-code/tests/` (shipped untested since v2.25.0; 35 assertions). Canonical only; codex/cursor/antigravity stay 2.24.2 tracked-drift (schedule is Bash + macOS launchd). aria-atlas reader/endpoint/card live in the aria-atlas repo (local/unpushed). Prior: 2026-06-06 — plugin-claude-code v2.25.2 (**Superpowers recommended as a `/setup` companion**): new Step 5c detects/recommends [Superpowers](https://github.com/obra/superpowers) as the complementary process-discipline layer to ARIA's knowledge+edit discipline — strongly recommended but optional, no skill gated on it (verified install `superpowers@claude-plugins-official`); + README "Works Well With Superpowers" section. **v2.25.1** (**SessionStart injection trimmed ~11%**, ~588 B / ~147 tok, zero enforcement change): TASK BUDGET branch-gated on statusline-installed (was emitting both exists/not-exists branches every session) + CODEMAP report shows full detail for stale maps only, collapsing current maps to a `+N current` tail. Also `docs/value-analysis.md` evidence-digest refreshed to the current corpus (171 `/prospect` + 68 `/retrospect` logs; two-stream promotion model; corrected cost surface). Canonical port only; codex/cursor/antigravity tracked-drift for a parity pass. Prior: 2026-06-05 — plugin-claude-code v2.24.3 (**runtime-aware statusline account resolution + staleness/scope guards**, ADR-099): shared `kt_resolve_account` (in `config.sh`, byte-mirrored into the standalone-copied meter) keys the usage snapshot by the real **per-user** account under Claude-Desktop hosting — where `~/.claude.json` is the CLI login, not the session account — falling back to `~/.claude.json` for the CLI (v2.24.2 unchanged). Inject hook + SessionStart reader use it too; inject gains 5h/7d `resets_at` staleness + context `session_id`/null guards; `/statusline` wires `refreshInterval:30`; snapshot adds `runtime`/`session_id`/`seven_day_resets_at`; email renders only on the CLI runtime. **Ports:** statusline ships only in plugin-claude-code; **plugin-antigravity is exempt** (targets `~/.gemini/antigravity.json`, no Claude-Desktop hosting), codex/cursor/cowork don't ship the scripts. Resolver live-validated in-session; real-runtime meter/inject check is post-merge. Prior: 2026-06-04 — plugin-claude-code v2.24.2 (per-account statusline usage-state scoping — fixes cross-account false usage alerts by keying the snapshot on `oauthAccount.accountUuid` read from `~/.claude.json`, plus account email as the last status-line segment). Prior same-day: v2.24.1 (statusline model-label trim + am/pm reset clocks). **Cursor port 2.24.2-cursor.0** tracks canonical v2.24.2 (2026-06-04, statusline-only delta — not ported). **Cursor port 2.24.1-cursor.0 SHIPPED** (2026-06-04): full parity pass to canonical v2.24.1 — hooks (`afterFileEdit` auto-prospect, `afterShellExecution` auto-retrospect, `subagentStart`/`subagentStop`), SESSION.md piggyback, config keys; **`port-skills-to-mdc.py` rewritten for full `.mdc` regeneration** (retrospect caught incremental script's silent drift); release `aria-knowledge-cursor-2.24.1.zip`; commit `8bb1fc1` local/unpushed. Prior: 2026-06-01 — plugin-claude-code v2.22.2 (**auto-prospect & auto-retrospect hooks**, Claude Code only, opt-in default off: `post-plan-prospect-check.sh` [PostToolUse:Write] offers/runs `/prospect file <path>` on a plan written to `docs/plans/` or `docs/superpowers/plans/` when `auto_prospect` is `nudge`/`run`; `post-push-retrospect-check.sh` [PostToolUse:Bash] offers/runs `/retrospect range <old>..<new>` on a qualifying `git push` when `auto_retrospect` is `nudge`/`run`; + 4 config keys `auto_prospect`/`auto_retrospect`/`retrospect_min_commits`/`retrospect_branches`; other 4 ports tracked-drift). v2.22.1 (**SESSION.md producer dogfood fixes**: `/wrapup`+`/handoff` Step 1 disambiguates the active project when cwd is a multi-project/workspace root; `SESSION.md` is now gitignored + never committed by the producer). v2.22.0 (**SESSION.md producer**, Claude Code only: `/wrapup` + `/handoff` write a per-project `SESSION.md` across an `in-progress`/`wrapup`/`handoff` lifecycle, gated on the new `session_state` config key [default off, surfaced in `/setup`]; a flag-gated `session-start-check.sh` instruction offers resume [auto-resume on the `handoff` keyword] then light-touch-marks `in-progress`; contract at `aria-atlas/docs/TEMPLATE_SESSION.md`, consumed read-only by aria-atlas; the live-session JSON registry is intentionally not built; other 4 ports tracked-drift, not re-synced). Prior: 2026-05-31 — plugin-claude-code v2.21.0 (**subagent knowledge capture**: new `SubagentStop` archive hook [`bin/subagent-stop-capture.sh`, archives `agent_transcript_path` to `intake/subagent-captures/`, sticky retention] + `SubagentStart` self-report hook [`bin/subagent-start-selfreport.sh`] + 3 `subagent_capture*` config keys + `/audit-knowledge` Step 2e + `/extract` Step 2.5 sweep-all; plus `/wrapup` description picker fix; tag `v2.21.0` + public GH release; validated end-to-end in production; Claude Code only). **All 5 ports synced to 2.24.2 parity** (`origin/main` `7bcdf57` + tags `v2.24.2` / `cowork-v1.1.5`): plugin-claude-cowork v1.1.5, plugin-openai-codex 2.24.2-codex.0, plugin-antigravity 2.24.2, plugin-cursor-template 2.24.2-cursor.0.*

*Session 2026-08-26 (later) — **the cap is not a constant, and that is why this arc did not converge.** Read out of the LIVE binary (`~/.local/share/claude/versions/2.1.245`, Bun-compiled with the JS embedded; ⛔ the homebrew `cli.js` is **2.0.8** and reading it would have been the same wrong-unit error a third time): `Rae(toolName, maxResultSizeChars, ceiling, skipAggregate)` returns `min(maxResultSizeChars, ceiling)` unless a **per-tool override map keyed by TOOL NAME** — behind the gate `"tengu_velvet_ibis"` — supplies a value. ✅ `K5 = 2000` and `V5 = "<persisted-output>"` **confirmed**. ⇒ **The threshold is PER-TOOL and (strong inference, not measured — `tengu_*` is this binary's gate namespace and no settings key exists; a gate fetch was not observed) REMOTELY MUTABLE.** Three consequences: it is *structural* confirmation that the Bash-tool probes never transferred (corroborated in-session — a **26,389 B** Bash result came back whole while a **19,557 ch** hook payload was wrapped, and later a 47.7 KB Bash result WAS wrapped, bracketing that consumer separately); the gate is **not a user lever**; and ⛔ **no payload may be sized against the cap, so locating it exactly would not make a hook design safe.** ⭐ **The composition measurement that replaces the four candidate designs:** the emission is assembled at `bin/session-start-rules.sh:35-39` and is **61% static / 39% computed** — static digest 11,960 ch (**12,166 B, already under probe A's proven 13,101 B** — ⚠ and that comparison is exactly the reasoning the 2026-08-27 correction below invalidates: "under the proven floor" was treated as the safety test, when the floor was never the constraint) plus 7,598 ch of blocks computed from `autonomy`, `session_state`, the project tag index and `user-rules.md`. ⛔ **So option Z is NOT a superset of the hook channel** — a file written once cannot carry a config-conditional block — and the split is by **MUTABILITY**, not by audience (§8.1) or fidelity (§10.3): the file carries the *behaviour*, the hook carries only the resolved *values*, which makes hook truncation non-damaging instead of cap-fitted. ✅ **PROBE RESULTS.** Probe A: all eight sentinels incl. the tail at 13,051 ⇒ the user-scope `~/.claude/rules/*.md` channel carries **13,101 B** (was 2,338 B, a 5.6× improvement). ⛔ **SUPERSEDED — do not quote this as the channel's capacity. 13,101 B is a FLOOR: the largest payload probe A happened to test.** A probe that fully delivers proves the channel carries *at least* that much and says nothing about the ceiling. ⛔⛔ **The live defect this file had until 2026-08-27 was not a missing measurement — it was PROPAGATION: probe C's result is recorded in `docs/superpowers/plans/2026-08-26-rules-file-hook-split.md:253` as "the channel at 32,056 B in one file and 34,394 B aggregate", and 32,056 already appears elsewhere in THIS footer — so both numbers sat in one always-loaded file with the stale one stated as the capacity.** A stale sentence reads exactly like a current one. **Authoritative figures: 32,056 B single-file, 34,394 B aggregate (probe C).** ⚑ Independently corroborated 2026-08-27 by a different instrument — not a sentinel-gradient probe file but the running session's own context: **29,875 B across three files delivered in full**, verified by three **tail sentinels**, one per file, *including the last file in alphabetical load order* (which is what rules out an aggregate budget exhausting mid-directory), plus a **38-of-38 rule census with section membership** on the 21 KB `aria-rules.md` (Coding 1–18 · Process 19 20 21 22 27 36 37 · Meta 23 24 25 26 28 29 30 31 32 33 34 35 38), which catches a mid-file hole *and* a reorder that tail sentinels alone cannot. **29,875 is LOWER than probe C's figure and is not a replacement for it** — its value is being obtained a different way, at zero cost, from a session's delivered context rather than from an armed probe file. ⚠ Every one of these is a floor, and per this same arc's binary read the cap machinery is per-tool and plausibly remotely mutable, so any figure here measures a moment. ⛔⛔ **AND THE SHARPER FINDING, which is not about size at all: this channel loads ONCE at session start, so a rule added mid-session is silently absent from every running session** — measured live, a parallel session grew `user-rules.md` from 19 to **25** U-rules at 20:19 and **U20–U25 were not in the running session's context**, with no marker of any kind. That is a *temporal* gap, and unlike the digest's 240-byte truncation (which appends `…`) it announces nothing. It also means the directory now stands at **31,822 B, above the verified figure and unverified.** Probe B: `PROBE-B-QX7K` **absent** ⇒ the `claudeMd` settings key is **inert at user scope and fails SILENTLY** — no warning, no error, no log line; readable only because probe A was the positive control in the same arm. ⛔ **A claim made and retracted inside this one session: "Z is unproven by 51%" compared probe A's capacity against the hook's *composed* emission rather than against what a file would carry (12,166 B). Same wrong-unit shape as probe A itself, in the session that named the pattern.** ⛔ **RULED (Mike): the file channel is `~/.claude/rules/`, not the `CLAUDE.md` `@`-import** — accepting one probe session in exchange for never writing the user's repo. ⏳ **PROBE C ARMED** at `~/.claude/rules/_probe-c-size.md`, **32,056 B**, nine markers at **703 / 4,052 / 8,067 / 12,008 / 16,023 / 20,038 / 24,053 / 28,068 / TAIL 32,009** — deliberately ABOVE the ~25,800 B worst case so a pass settles the channel permanently. ⚠ It costs ~8k tok in EVERY session in EVERY project until deleted: `rm ~/.claude/rules/_probe-c-size.md`. ✅ **AC1's GUARD IS BUILT** (`eb82199`) — 11 assertions in `plugin-claude-code/tests/test-aria-rules-digest.sh`: a positive control on the needle, a deterministic worst-case fixture proven to carry all six conditional blocks, a downward-only ratchet at **20,322** normalised codepoints, and the last-rule-title check on the minimal AND worst-case paths. Suite **213 passed / 0 failed, bare exit 0**. ⛔ **The FIRST version survived its own mutation:** it counted raw characters, and the payload interpolates the knowledge-folder path **3 times**, so the total tracked the temp-dir path length (21,074 at a 144-char path vs 20,942 at 100 — exactly 3× the difference); `wc -m` was no better, counting bytes under `LC_ALL=C`. The measure is now jq's literal string split, path- AND locale-independent. ⚑ **Four of seven mutation attempts were unfaithful** (a no-op insert, a `sed` that never matched, and twice truncating a variable after its value had been copied out) — every one caught by proving the condition was created, **none by re-reading**. ⛔ **NEW DEFECT FOUND, not fixed, Mike's call: `bin/pre-bash-write-check.sh`'s temp-path exemption tests whether the COMMAND STRING MENTIONS a temp path, not whether the MUTATION TARGET is one.** Proven three ways: `sed -i` on a tracked `.sh` **warns**; the identical edit in a command that also references a scratchpad path is **silent**; `cat >>` into a tracked `.sh` **warns**. ⚑ The irony is what makes it matter — **backup-to-scratchpad-then-mutate is the safe pattern this workspace's own discipline mandates**, so doing the careful thing silences the hook, and its measured 0.674% fire rate is therefore an **underestimate** (the corpus cannot have counted what the hook was blind to). It is a false NEGATIVE, so the KILL-not-loosen rule (which governs false positives) does not bind; the fix is narrowing the exemption to the resolved target. ⚠ Also: the harness's own bash-first directive rides along with **auto mode** (`steerOnly`) — same instruction block also serves bypass-permissions mode and a `bashFirst` flag — so under auto mode it actively pushes the shell edits that trip that hook. Commits `eb82199` (guard) + `f1fcc29` (spec). ⚠ **19 ahead of `origin/main`, NOT pushed.** ⚠ CODEMAP.md is **37 days** old against a 14-day threshold.*

*Session 2026-08-26 (later still) — **`/auto`'s modifier surface carried two defects; both fixed in canonical, neither live.** ⛔ **F2 — three knobs documented in Step 5 were in no parser list.** `workflow`, `fanout=<pct>` and `agents=<N>` are described there as invocation overrides for the three fan-out stopgaps, and appeared in no modifier bullet, no `argument-hint` and no `description`. Under the skill's own ENDS scan an unrecognised token ends the modifier run, so typing one **dropped the opt-in AND put a stray word in the goal** — `/auto full workflow audit X` yielded goal *"workflow audit X"* with Workflow still hard-OFF. ⚑ It **failed safe** (tighter defaults held, nothing errored), which is exactly why it survived in shipped docs: a knob that silently keeps its default is indistinguishable from one you never reached for. Also corrected the axis count — the description said "one word per axis" then listed three plus two loose extras; there are **six** (authority · presence · duration · work-source · context-recovery · fan-out). **Ruled ENDS-only and uniform, NOT a second key=value-anywhere rule:** a general `<word>=<value>` scan would eat a legitimate goal like *"fix the assertion that checks count=20"*, which is the mis-parse the ENDS rule exists to prevent; `=`-bearing tokens are collision-free by shape and need no rule of their own. ⛔ **F4 — the Runtime Gate offered a handoff to a skill that exists in no port.** It named a Cowork counterpart of `/auto` four times and, on `y`, said it would invoke it via the `Skill` tool. Verified absent in `plugin-claude-cowork/skills` with a positive control, in source and in the installed tree. Cause: the section was doing two jobs — ADR-094's gate exists for the **24 colliding names**, where the point is offering the runtime-appropriate variant, and this skill is Code-only with no counterpart, so it is not in the collision set. **The dead redirect is what a colliding-name template produces when applied to a non-colliding name.** Rewritten as a Bash **capability precondition**: the check is unchanged, the stop branch now routes to the four Cowork gates that do exist (`prospect`, `retrospect`, `handoff`, `wrapup`), and the proceed branch gained the honesty instruction it lacked — never report a Bash-backed step as done when it did not run. `y`/`n` kept for family uniformity with the question polarised to *"Stop here?"*, so `n` still means *run it anyway*; phrasing it "proceed anyway?" would have inverted `n` for this skill alone. ⛔⛔ **A PRE-EXISTING ASSERTION WAS CERTIFYING THE DEFECT: `tests/repros/auto-modes.sh` assertion `I` required the skill to NAME the dead variant**, so it would have gone red for anyone who fixed the redirect. Found only because the green arm failed at 155/1. It came from the colliding-name template rather than a measurement; replaced (not deleted) with the fact that is true — the skill declares itself Code-only. ⚑ **This is the inverse of ordinary test rot: a vacuous assertion goes quietly green and protects nothing, while this one went actively green on a broken behaviour and would have BLOCKED the repair. Both are invisible until you fix the code — which is why the green arm is not a formality.** ⚑ Also self-caught: my own `FG5` emitted five failures for one defect (a per-gate loop plus a redundant summary covering 2 of 4); collapsed to one assertion naming every miss. **Gates:** Gate B measured before and after rather than assumed — **19,552 → 19,622 B of 19,968, headroom 346** (the `description` IS counted; `argument-hint` is not, `release.sh:78` stops at the next top-level key, so the hint edits were free). auto-modes **146 → 156**; two-sided via a scratch mirror tree running the edited suite against the committed pre-edit file — **151 passed / 5 failed**, each for its own named reason, GREEN 156/0. `FG3` passes in **both** arms and is labelled in-file as a non-regression guard against an over-broad deletion, **not landing evidence**. Full plugin suite 253/0, repro set 37 suites/0, all bare exit 0. Commits `d6fd0fa` (F2/F3) + `7ec3ca7` (F4), staged by exact path. ⚠ **NEITHER FIX IS LIVE** — measured in the installed plugin: 4 dead refs remain, `fanout=` absent from `argument-hint`, description still undercounts the axes. A surgical copy of `skills/auto/SKILL.md` makes them live; a full re-install also lands 42 other commits. ⚠ **NOT pushed** — 44 ahead of `origin/main`, 42 of them another arc's. ⚠ Ports: F2/F3 reach antigravity and cursor when their build scripts next run (`build.sh` copies canonical `skills/` and has no `auto` overlay; cursor recompiles via `port-skills-to-mdc.py`); codex is hand-sync; **F4 needs no propagation — those ports strip ADR-094 gates, censused 0**. ⚠ **A `/wrapup` conflict left unresolved rather than actioned: `session_state_tracked` is global-`true`, but this repo ignores `SESSION.md` at `.gitignore:17`, is public, and has a fatal Gate D on home paths.** The skill's true-branch would delete that ignore line and stage session state into a public artifact; not done, and `.gitignore` was concurrently dirty. This is the documented global-knob defect firing where the consequence is publication. ⚠ Unretrospected: `d6fd0fa~1..7ec3ca7`.*
