T-1VJD-aspect-layer-detection-base
State: closed/done · Impact: medium · Complexity: medium
@sksizer/detect-runners and @sksizer/manifest-graph each independently
re-parse package.json/Cargo.toml today for overlapping questions (“what
tasks exist” vs. “what technology is this”). Land the shared base layer —
collectAspects, reading every manifest kind once — as pure additive code
with no existing provider or consumer touched yet, so it can be reviewed in
isolation before anything depends on it.
detect-runners’s providers (cargo.ts, node-scripts.ts, moon.ts,
just.ts, mise.ts, make.ts, +12 more) each call their own
ctx.files()/ctx.readJson() for manifest presence/content.
manifest-graph’s walk.ts independently parses package.json/Cargo.toml
into its own ManifestInfo. project-facets.get.ts shells out to
moon query projects a second time for facts a moon provider could already
read. See
../decisions/D-LSLH-collapse-verbs-workflows-chain-hooks/detection-consolidation.md
§1 “Inventory” for the full accounting.
Proposed
Section titled “Proposed”A new @sksizer/detect-runners/aspects subpath exports collectAspects(root, opts): Promise<AspectCatalog> and the AspectFacts/AspectCatalog types
(detection-consolidation.md §2), built from the existing ProviderContext
memoized files()/readJson()/readText()/exists() primitives. Nothing
else changes yet — no provider, no consumer, no behavior change to
collect/tasks/discover.
Approach
Section titled “Approach”- Add
packages/ts/detect-runners/src/aspects.ts(or anaspect/subdir) implementingAspectFacts/AspectCatalog/collectAspectsper detection-consolidation.md §2’s shape (cargo, package.json, moon, justfile, mise, packageManager/lockfile, hookManagers, toolTrust, evidence). moon.roleis populated frommoon query projects, gated the sameallowExec-aware way the existing moon provider gates itself — computed once percollectAspects()call.- Export the subpath from the package’s
package.json(exportsmap) as@sksizer/detect-runners/aspects. - Add exhaustive unit tests against fixture directories (cargo-only, package.json-only, mixed, hook-manager markers, tool-trust markers).
| Area | Note |
|---|---|
packages/ts/detect-runners/src/aspects.ts | New: collectAspects, AspectFacts, AspectCatalog |
packages/ts/detect-runners/package.json | New ./aspects export subpath |
packages/ts/detect-runners/src/aspects.test.ts | New: fixture-driven coverage |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1:
collectAspects(root, {allowExec: false})against a fixture with onlyCargo.tomlreturnsAspectFacts.cargopopulated and every other manifest field absent, with no exec. - AC-2: A fixture with a
package.jsonscripts/dependenciespopulatesAspectFacts.packageJson(name, main, types, scripts, dependencies) without touchingCargo.toml. - AC-3:
moon.roleis populated only whenallowExec: true(orisRepoTrusted), matching the existing moon provider’s own exec gate. - AC-4: No existing
detect-runnersprovider, and nomanifest-graphor sdlc code, imports from the new subpath yet — this task ships dead code exercised only by its own tests. - AC-5:
bun test packages/ts/detect-runnerspasses standalone.
Out of scope
Section titled “Out of scope”- Rewiring any existing provider to consume
AspectFacts—T-6K39. - Moving
detectDeps/resolvePinnedManagerInstallinto this package —T-6K39. manifest-graph’swalk.tsadoption —T-3GMU.project-facets.get.ts’s shell-out removal —T-OUKL.
Dependencies
Section titled “Dependencies”- none
Discovery context
Section titled “Discovery context”Detection-consolidation research:
../decisions/D-LSLH-collapse-verbs-workflows-chain-hooks/detection-consolidation.md,
written to back D-LSLH-collapse-verbs-workflows-chain-hooks’s “The verb
vocabulary: aspect-detected defaults” section (T-VE84).