Scan Surface Detection

The scan reads every workspace package's dependencies, framework hints, tsconfigs, and bin fields — then merges it all into flat root-level fields (`allDeps`, `stack.framework`, `stack.testing`) and loses the per-package identity. A customer with a Next.js frontend and an Express API backend sees one detected framework, one testing framework, one set of commands. The second surface is invisible.

verdict PASSscore 28 / 28findings 7 (0 risk · 1 debt · 6 obs)duration 32mrejection cycles 0shipped May 20, 2026surface cli

Pipeline timeline

Intent to proven code in 32m across Think, Plan, Build, and Verify.

Think
6m
Plan
6m
Build
12m
Verify
5m

Assertion ledger

28 claims, each independently verified. Showing 8 — show all →

IDSaysMatcher
A001Monorepo scans produce a surfaces array with all required fieldsverifiedok
A002Each surface reports the package name from package.jsonverifiedok
A003Each surface reports its source file countverifiedok
A004Monorepo packages include per-package language detectionverifiedok
A005Monorepo packages include per-package testing detectionverifiedok
A006Monorepo packages include script keys from package.jsonverifiedok
A007Monorepo packages include the bin field indicatorverifiedok
A008Single-repo projects produce an empty surfaces arrayverifiedok

Findings 7 total

obspackages/cli/tests/engine/detectors/surfaces.test.tsclosed
Contract A017 value 'my-package' doesn't match test fixture normalization result 'my-packagejs'
obspackages/cli/tests/engine/detectors/surfaces.test.tsclosed
A023 tests STRONG_FRAMEWORK_CONFIGS presence as proxy for FRAMEWORK_HINTS count — FRAMEWORK_HINTS is not exported
obspackages/cli/tests/engine/detectors/surfaces.test.tsclosed
A021 tests data shape availability, not actual terminal output containing 'Surfaces' string
debtpackages/cli/src/utils/displayNames.tsclosed
nuxt and astro missing from FRAMEWORK_DISPLAY_NAMES — surfaces display lowercase keys instead of 'Nuxt'/'Astro'
obspackages/cli/src/engine/detectors/surfaces.tsmonitor
deriveRawName @scope stripping handles segment-level scoped names but path-level scoped packages use last path segment after split, making the @scope branch in deriveRawName unreachable for standard monorepo layouts
+2more findings

Integrity seal

scopesha256:162c4c7fa2665...
contractsha256:b67dc39a8d0e2...
plansha256:2751ca167ce19...
specsha256:021e136ccf085...
build-reportsha256:eddeb74769ad7...
build-datasha256:8e988796c46a0...
verify-reportsha256:6d9d71d05ca39...
verify-datasha256:1c6f5cb864e17...
audit cmd$ ana proof audit scan-surface-detection   → all hashes match