PROUST is a system which identifies the non-syntactic bugs in novices’ programs and provides novices with help as to the misconceptions under which they were laboring that caused the bugs. In this paper we will discuss the methods which PROUST uses to identify and diagnose non-syntactic bugs. Key in this enterprise is PROUST’s ability to cope with the significant variability exhibited by novices’ programs: novice programs are designed and implemented in a variety of different ways, and usually have numerous bugs. We argue that diagnostic techniques that attempt to reason from faulty behavior to bugs are not effective in the face of such variability. Rather, PROUST'S approach is to construct a causal model of the programmer’s intentions and their realization (or non-realization) in the code. This model serves as a framework for bug recognition, and allows PROUST to reason about the consequences of the programmer’s decisions in order to determine where errors were committed and why.