T-VE84-aspect-detected-defaults-verb-vocabulary
State: closed/done · Impact: medium · Complexity: large
Give twelve names (setup, fmt, fmt-check, lint, lint-fix,
typecheck, test, test-int, test-e2e, build, clean, check) a
'detected' resolution layer between project and none, backed by
@sksizer/detect-runners (already a dependency), generalizing
defaultSetup’s existing just/moon/mise-only heuristic to every provider and
every name in one pass. check is excluded from detection itself
(T-DPG3 gives it a fixed composition instead).
defaultSetup (verbs.ts) filters allTasks(catalog) to
{just,moon,mise} tasks named {setup,install,bootstrap} — deliberately
excluding node-scripts/cargo. This is the one existing case of the
mechanism; every other vocabulary name has no detected default at all. This
task now assumes the detection consolidation (T-1VJD, T-6K39,
T-LCKH) has already landed: it adds fmt/fmt-check/build/clean to
detect-runners’s cargo provider, deletes
solutions/ontological/lib/config/{detect-deps,pinned-manager}.ts, and moves
their logic into @sksizer/detect-runners as resolveInstall/
hasMissingDeps/resolvePinnedManagerInstall, and deletes
lib/services/project/detect-setup.ts — none of that is this task’s own
work any more.
Proposed
Section titled “Proposed”lib/config/workflows.ts gains VOCABULARY_NAMES (12 names),
VOCABULARY_METADATA (writes: boolean, true only for fmt and any
-fix name), a CANDIDATE_NAMES table (reusing S-0013’s own moon-task ↔
package.json-script mapping), and detectVocabulary(name, projectRoot, opts), wired into resolveWorkflow’s cascade as the layer tried between
project/local and 'none', for name ∈ VOCABULARY_NAMES only (check
excluded).
Approach
Section titled “Approach”-
Add
VOCABULARY_NAMES = ['setup', 'fmt', 'fmt-check', 'lint', 'lint-fix', 'typecheck', 'test', 'test-int', 'test-e2e', 'build', 'clean', 'check']andVOCABULARY_METADATA: Record<string, { writes: boolean }>(writes: trueonly forfmtand any-fixname). Add aCANDIDATE_NAMES: Record<string, string[]>table mapping each vocabulary name to the search termsnode-scriptstasks are matched against (fmt→['fmt','format'],fmt-check→['fmt-check','format:check', 'fmt:check'],lint-fix→['lint-fix','lint:fix'],test-int→['test-int','test:int','test:integration'],test-e2e→['test-e2e','test:e2e'], the rest map to themselves). -
Add a
detectVocabulary(name, projectRoot, opts)function returning:Promise<{steps: WorkflowStep[]layer: 'detected' | 'none'detectedVia?: { runner: string; origin: 'declared' | 'synthesized'; task: string }}>It calls
collect(projectRoot, { allowExec })(same trust-derivedallowExecasdefaultSetup) andtasks(catalog), filters toCANDIDATE_NAMES[name]matches across every provider (the existing{just,moon,mise}restriction is dropped for the general case), prefers exactly oneorigin: 'declared'match, else exactly oneorigin: 'synthesized'match, else (name ==='setup'only) falls back to@sksizer/detect-runners’s ownresolveInstall/resolvePinnedManagerInstall, else{steps: [], layer: 'none'}. More than one match at a tier is an ambiguity →'none', never a guess. -
Wire
detectVocabularyintoresolveWorkflow’s cascade (T-JIBO/T-4OUZ’s primitive) as the layer tried betweenproject/localand'none', forname ∈ VOCABULARY_NAMESonly (checkexcluded —T-DPG3). Every other name’s resolution is unaffected. -
Add the provenance field:
ResolvedWorkflow/ResolvedStep’slayer: 'detected'case carriesdetectedViasoT-MVK5’sconfig explain/doctorwiring can render it without a second pass.
| Area | Note |
|---|---|
solutions/ontological/lib/config/workflows.ts | VOCABULARY_NAMES, VOCABULARY_METADATA, CANDIDATE_NAMES, detectVocabulary, wired into the cascade |
solutions/ontological/lib/config/verbs.ts | defaultSetup’s just/moon/mise-only restriction removed — setup now goes through the general detectVocabulary path, falling back to @sksizer/detect-runners’s resolveInstall/resolvePinnedManagerInstall only when detection itself finds nothing |
solutions/ontological/lib/config/workflows.test.ts | New cases: declared beats synthesized; a package.json "setup" script now counts (behavior widening); ambiguity → 'none' |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1: A crate with only a
Cargo.tomlresolvesworkflows.testtocargo testandworkflows.fmt-checktocargo fmt -- --check, bothlayer: 'detected',detectedVia: {runner: 'cargo', origin: 'synthesized', ...}. - AC-2: A package with a
package.jsonscripts.lintresolvesworkflows.lintto that script’s command,layer: 'detected',origin: 'declared'— and wins over a coincidentally-present cargoclippysynthesis in the same directory (declared beats synthesized). - AC-3: A project with a
package.json"setup"script now resolvesworkflows.setupto it (today’sdefaultSetupwould skip straight to the install fallback becausenode-scriptsis excluded from its search) — the documented widening. - AC-4: A directory with both a moon
linttask and apackage.jsonlintscript (two declared matches) resolvesworkflows.linttolayer: 'none'— ambiguity, not a guess. - AC-5:
bun test solutions/ontological/lib/configpasses.
Out of scope
Section titled “Out of scope”packages/ts/detect-runners/src/providers/cargo.ts’sVERBStable additions and thedetect-deps.ts/pinned-manager.ts→@sksizer/detect-runnersmigration — bothT-6K39/T-LCKH, not this task’s own work;check’s own default (T-DPG3);--strict/ skip-reporting semantics (T-DPG3);doctor’swriteswarning (T-DPG3, since it needsT-4KYN’s hooks resolution to inspect a hook’s referenced verbs).
Dependencies
Section titled “Dependencies”T-JIBO, T-4OUZ (needs the merged workflows: resolver and its
layer provenance field to plug the new layer into); T-1VJD, T-6K39,
T-LCKH (the detection-consolidation stack — the cargo VERBS additions
and the resolveInstall/resolvePinnedManagerInstall consolidation this
task calls into must already be merged).
Discovery context
Section titled “Discovery context”Drawn from D-LSLH-collapse-verbs-workflows-chain-hooks’s “The verb
vocabulary: aspect-detected defaults” section and
../decisions/D-LSLH-collapse-verbs-workflows-chain-hooks/detection-consolidation.md
§7.
Depends on
Section titled “Depends on”T-JIBO, T-4OUZ, T-1VJD, T-6K39, T-LCKH