Skip to content

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.

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).

  1. Add VOCABULARY_NAMES = ['setup', 'fmt', 'fmt-check', 'lint', 'lint-fix', 'typecheck', 'test', 'test-int', 'test-e2e', 'build', 'clean', 'check'] and VOCABULARY_METADATA: Record<string, { writes: boolean }> (writes: true only for fmt and any -fix name). Add a CANDIDATE_NAMES: Record<string, string[]> table mapping each vocabulary name to the search terms node-scripts tasks 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).

  2. 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-derived allowExec as defaultSetup) and tasks(catalog), filters to CANDIDATE_NAMES[name] matches across every provider (the existing {just,moon,mise} restriction is dropped for the general case), prefers exactly one origin: 'declared' match, else exactly one origin: 'synthesized' match, else (name === 'setup' only) falls back to @sksizer/detect-runners’s own resolveInstall/ resolvePinnedManagerInstall, else {steps: [], layer: 'none'}. More than one match at a tier is an ambiguity → 'none', never a guess.

  3. Wire detectVocabulary into resolveWorkflow’s cascade (T-JIBO/ T-4OUZ’s primitive) as the layer tried between project/local and 'none', for name ∈ VOCABULARY_NAMES only (check excluded — T-DPG3). Every other name’s resolution is unaffected.

  4. Add the provenance field: ResolvedWorkflow/ResolvedStep’s layer: 'detected' case carries detectedVia so T-MVK5’s config explain/doctor wiring can render it without a second pass.

AreaNote
solutions/ontological/lib/config/workflows.tsVOCABULARY_NAMES, VOCABULARY_METADATA, CANDIDATE_NAMES, detectVocabulary, wired into the cascade
solutions/ontological/lib/config/verbs.tsdefaultSetup’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.tsNew cases: declared beats synthesized; a package.json "setup" script now counts (behavior widening); ambiguity → 'none'
  • AC-1: A crate with only a Cargo.toml resolves workflows.test to cargo test and workflows.fmt-check to cargo fmt -- --check, both layer: 'detected', detectedVia: {runner: 'cargo', origin: 'synthesized', ...}.
  • AC-2: A package with a package.json scripts.lint resolves workflows.lint to that script’s command, layer: 'detected', origin: 'declared' — and wins over a coincidentally-present cargo clippy synthesis in the same directory (declared beats synthesized).
  • AC-3: A project with a package.json "setup" script now resolves workflows.setup to it (today’s defaultSetup would skip straight to the install fallback because node-scripts is excluded from its search) — the documented widening.
  • AC-4: A directory with both a moon lint task and a package.json lint script (two declared matches) resolves workflows.lint to layer: 'none' — ambiguity, not a guess.
  • AC-5: bun test solutions/ontological/lib/config passes.
  • packages/ts/detect-runners/src/providers/cargo.ts’s VERBS table additions and the detect-deps.ts/pinned-manager.ts → @sksizer/detect-runners migration — both T-6K39/T-LCKH, not this task’s own work; check’s own default (T-DPG3); --strict/ skip-reporting semantics (T-DPG3); doctor’s writes warning (T-DPG3, since it needs T-4KYN’s hooks resolution to inspect a hook’s referenced verbs).

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).

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.

T-JIBO, T-4OUZ, T-1VJD, T-6K39, T-LCKH


← Back to Tasks