One grammar for the profile language
- Context: reserved words spread over decoders, per-key checks, hand-written JSON schemas and reference pages let one word mean different things in different places, let a key be documented and not read or read and not documented, and let a typo load silently.
- Decision: one Go table,
builtin.Grammar(internal/intent/builtin/grammar*.go), is the only source of every reserved key of an intent and a workflow manifest, a step’s arguments,actions.toml,tasks.toml,views.toml,gates.toml,keys.toml,defaults.toml,labels.tomlandconfig.toml: its path, kind, values, default and one-line doc.builtin.Check, run by every loader, judgment blocks’ front matter included, validates kinds, enums and defaults against it; a decoder that checks a value itself takes the value set from the table (builtin.ValuesOf) and words the refusal as the table does. An unknown key or value is refused with a suggestion only when a close one exists (expr.Closest, the one similarity every surface uses), and never with a mode that sends or runs with no person approving. There are no aliases: a removed name is unknown like any other.profile schemawrites the JSON schemas from it, andmake docs-refwrites the reference pages, the profile language among them, one line per reserved word. Core words are neutral and name no provider; a plugin’s own words carry its slot’s prefix (pr.review,pr.reviewed) and its configuration lives under its id (github.*,slack.*). Every intent, workflow and built-in action says what it does in a requiredsummary, and the words of the built-in actions, the verbs, the views and the core keys’ help are the profile’sactions.toml,tasks.toml,views.tomlandkeys.toml. - Consequence: a word means one thing wherever it appears (
modeonly in an approval table,observefor a workflow that plans only,dry_runfor a draft that is never sent,runnerfor how a turn runs,stagefor the pass over a unit); a pull request fact has one name and one spelling in every slot (pr.repois owner/repo,pr.repo_namethe bare name,pr.stateGitHub’sOPEN,CLOSEDorMERGED); a new key is a row with its doc, and its schema and reference follow frommake docs-ref; an old configuration or manifest fails at load, naming each unknown key. - Enforced by:
TestCheckRefusesAnUnknownKey,TestCheckRefusesAnUnknownValue,TestCheckReadsKinds,TestGrammarDefaultsAreValid,TestEveryConfigKeyIsInTheGrammar,TestTheGrammarRefusesTheOldUserConfig,TestBundledProfileLoadsClean,TestManifestKeysAreInTheGrammar,TestGrammarDocIsCurrent,TestTheDecodersCheckValuesInTheTablesWords,TestNoGuessReleasesADraftOrARun,TestClosestGuessesNothingForAnOldName,TestPRFactsAreSpelledAlikeInEverySlot. See Profile first.