Where is the CiviCRM ERD / data-dictionary?
You should use the API as the data dictionary. The API explorer (available in every installation) provides a convenient interface to browse the data dictionary.

The demo sites each have an API explorer and they are the authoritative public data dictionary for CiviCRM. For example  http://dmaster.demo.civicrm.org/civicrm/api/explorer (login first with username:demo and password:demo). Other versions are also available..

The entity select box shows a list of all available entities.  For each entity, the three most important actions from a 'data dictionary' perspective are


getfields - for the given entity, this action shows available fields 
getactions - for the given entity, this action shows available actions 
getoptions - for the given entity and field this action shows available options (only available for multiple choice fields).


Here are some examples of useful API calls:

To list all entities

civicrm_api3('Entity', 'get');

To list fields for an entity

civicrm_api3('[EntityName]', 'getfields');

To list options for a field (only available for multiple choice fields):

civicrm_api3('[EntityName]', 'getoptions', array( 'field' =&gt; "[FieldName]"));

To list actions for an entity:

civicrm_api3('[EntityName]', 'getactions');

FWIW, the above four API functions are used to build the API explorer, which is quite neat, IMO.

As you might expect, in most cases the API is a fairly close match to the database structure.  This database structure is defined in a series of XML files that you can find in our git repo (for example this xml file defines the table civicrm_group).

A couple of areas that merit a bit more explanation:


Custom data: At the database level, each custom set is a database table and each custom field is a database column.  All custom data is registered in two tables civicrm_custom_group and civicrm_custom_field.  These tables are exposed in the API as the entities CustomGroup and CustomField.
Options: At the database level, a lot of the simple drop-down options that you see in the user interface (for example activity status) are stored in the two tables civicrm_option_value and civicrm_option_group. These are exposed in the API as OptionValue and OptionGroup. The more complex options (for example membership status) typically  get their own table and API Entity.


To answer the second question, when you say "patch the data-dictionary", I'm not entirely sure what you mean, but if you were "refining the core" and wanted to for example, add/edit/remove a field, I would


Edit the xml file that creates the database table you are interested in
"Run GenCode.php" to rebuild the data files
Do various other things depending on what you changed!


Of course if you are going down this route, I would recommend discussing any changes with someone who has a deep understanding of CiviCRM and its data structures.