# vendor-noun-allowlist.txt — the register of vendor nouns engine core is
# permitted to contain (STORY-117 T-ENG-117, gap G15).
#
# The lint in package-ci.sh gate 3 fails when `claude` or `anthropic` (case
# insensitive) appears in core/ or plugins/ outside lib/runners/, the tests'
# fixtures, and this list. Adapters own vendor knowledge; core must not.
#
# FORMAT   <path-relative-to-engine-root> :: <extended-regex matched against the line>
#          Lines starting with # are comments. Every entry MUST carry a reason
#          in the comment block above it — an unexplained entry is a leak that
#          got waved through.
#
# THE RULE FOR ADDING ONE
# A vendor noun may live in core only as a DECLARATION — a default value, a
# legacy alias name, or prose in the shipped manual. It may never appear in
# LOGIC: no flag vocabulary, no message regexes, no settings formats, no
# provider branching. Those belong in lib/runners/<adapter>.sh, and a hit like
# that is a contract defect (ADR-026 "when to revisit"), not an allowlist entry.
#
# Anchoring on the line's content, not its number, is deliberate: the entry
# survives the file moving, and stops matching the moment the line is edited —
# which is exactly when it should be re-reviewed.
#
# RE-AUDIT 2026-08-20 (STORY-202 T-DOC-202) — a second real adapter now exists
# (lib/runners/aider.sh), so every entry justified by "only one client exists"
# was re-checked against that reality:
#   · The config-default table stands. Its justification was never "one client"
#     but "a default has to default to something", and claude remains the only
#     FULL-capability runner (aider verifies 3 of 8; ADR-026 A9) — the default
#     is still the right one, and core still only passes the value through.
#   · The legacy env aliases stand — they are a public operator contract,
#     independent of how many adapters exist.
#   · The command-manual entries stand as CONTENT debt, unchanged: the manual
#     still describes a Claude-Code-run workflow. Still owned by the STORY-118
#     repackaging follow-up; a second adapter existing makes the rewrite more
#     worthwhile, not differently scoped.
#   · No entry needed adding: the aider binding put all its vendor knowledge in
#     lib/runners/aider.sh, and gate 3 runs clean (package-ci.sh, this date).
#     AMENDED 2026-08-22 (BUG-023): true, but it was not a statement about what
#     the gate could SEE. Gate 3's noun set was the literal `claude|anthropic`,
#     so `aider` could not have tripped it however the binding was written.
#     The set is now DERIVED from the adapters present, so this note finally
#     says what it always appeared to say — and binding a new client extends
#     the gate automatically instead of silently widening the blind spot.
#     The one provider-shaped behaviour found in core — classify_failure's
#     HTTP-status regex reading a client's log (F11) — contains no vendor noun,
#     so it is invisible to this lint BY DESIGN; it is filed as STORY-226
#     T-ENG-226, not allowlisted.
#
# CLOSED 2026-08-21 (STORY-226 T-ENG-226) — that last item is fixed, not
# allowlisted, as the note said it should be. classify_failure's log read moved
# behind the runner seam as the optional `runner_classify_failure` (ADR-026 A10);
# the HTTP-status and credential-prose regexes now live in lib/runners/claude.sh
# and lib/runners/aider.sh, which this gate excludes because vendor knowledge is
# their job. The limitation stands and is worth restating: A PROVIDER-SHAPED
# ASSUMPTION NEED NOT CONTAIN A PROVIDER NOUN. This lint would not have caught
# F11 and will not catch the next one — only binding a genuinely foreign client
# does that (ADR-026 "when to revisit"). Do not read a clean gate 3 as proof that
# core knows nothing about a vendor.

# ── The config default table ─────────────────────────────────────────────────
# A default has to default to something, and the engine ships with the claude
# adapter as the only full-capability runner (ADR-026). Every one of these is
# overridable in harness.config.yaml; none is read as a provider decision by
# core, which only ever passes the value to the adapter loader.
core/orchestrator/lib/config-defaults.sh :: ^  CFG_RUNNERS_IMPLEMENTER_BIN="claude"$
core/orchestrator/lib/config-defaults.sh :: ^  CFG_RUNNERS_IMPLEMENTER_ADAPTER="claude"$
core/orchestrator/lib/config-defaults.sh :: ^  CFG_RUNNERS_RULES_FILE="CLAUDE.md"$
core/orchestrator/lib/config-defaults.sh :: ^  CFG_TOOLING_SKILL_DIRS="\.claude/skills"
core/orchestrator/lib/config-defaults.sh :: ^  CFG_COMMIT_CO_AUTHOR=

# The same default, expressed once more where the adapter loader resolves an
# unset role. Not logic: it is the fallback argument to cfg_get.
core/orchestrator/lib/runners.sh :: cfg_get runners\.implementer\.adapter claude

# ── Legacy env aliases (permanent public contract) ───────────────────────────
# ORCHESTRATOR_CLAUDE_BIN and CLAUDE_LIMIT_RESTART_DELAY_MINUTES are the names
# operators' scripts and CI already use. Renaming them would break consumers to
# win a lint; the alias table (config.sh header) documents both.
core/orchestrator/lib/config.sh :: ORCHESTRATOR_CLAUDE_BIN
core/orchestrator/lib/run-config.sh :: CLAUDE_LIMIT_RESTART_DELAY_MINUTES
core/orchestrator/orchestrate.sh :: set runners\.implementer\.bin \(or ORCHESTRATOR_CLAUDE_BIN\)

# ── The stream decoder and the write guard — CLOSED, not allowlisted ─────────
# Both used to need an entry here. STORY-198 T-ENG-198a (review findings B1/B2)
# moved them into the adapter that owns their protocol:
#   core/orchestrator/stream-format.js  → lib/runners/claude/stream-format.js
#   core/orchestrator/qa-write-guard.sh → lib/runners/claude/write-guard.sh
# lib/runners/ is excluded from the gate, so no entry is required for either.
# Do not re-add one: a vendor protocol reappearing in core/ is a contract
# defect, and these two are the worked example of taking the move instead.

# ── The shipped command manual ───────────────────────────────────────────────
# core/commands/*.md are prose specs a consuming project copies into its agent's
# command directory. They describe a workflow that, today, is run by Claude
# Code. This is real agnosticism debt — finalise-task.md even hardcodes the
# commit trailer that T-ENG-117 just made configurable — but it is CONTENT, not
# engine behaviour, and rewriting the manual is its own change.
# FOLLOW-UP: recorded in STORY-117 review notes; the doc rewrite belongs with
# STORY-118's standalone-engine work, where the manual is repackaged anyway.
core/commands/build-next.md :: CLAUDE\.md
core/commands/CONVENTIONS.md :: \.claude/commands/
core/commands/finalise-task.md :: Co-Authored-By: Claude
core/commands/handoff.md :: Claude Code session
core/commands/orchestrate.md :: Claude
core/commands/resume.md :: CLAUDE\.md

# ── Stack-pack image defaults (STORY-348 T-PB-348b) ─────────────────────────
# Each shipped pack's Dockerfile installs the implementer's agent client from
# npm, and the build ARG has to default to something. Claude Code is the only
# full-capability runner (ADR-026 A9), the same reason the config-default table
# above defaults to it. This is a DECLARATION only: the image never branches on
# the value, `AGENT_CLIENT_NPM=''` builds without a client (the CI scenarios use
# the fake runner), and any other npm package swaps the client at build time.
# Added 2026-10-09 when package-ci was brought green (fix/package-ci).
plugins/stack-node-pnpm/Dockerfile :: ^ARG AGENT_CLIENT_NPM=@anthropic-ai/claude-code$
plugins/stack-vue-ts/Dockerfile :: ^ARG AGENT_CLIENT_NPM=@anthropic-ai/claude-code$
plugins/stack-laravel/Dockerfile :: ^ARG AGENT_CLIENT_NPM=@anthropic-ai/claude-code$
plugins/stack-python-uv/Dockerfile :: ^ARG AGENT_CLIENT_NPM=@anthropic-ai/claude-code$
