Core genome too short
Targeting Illumina reads with &gt;70X depth-of-coverage is a good place to start.  Once a robust database is established lower coverage isolates can be used effectively too.
More specific to individual SNPs... filtering on VCF QUAL value, Map Quality and/or AC value have shown to be useful.
Core genome will likely be around 1,000 SNPs, but it will depend on the lineage the reference belongs to and the aligned sample lineage.  If both are from the same lineage you're likely to be less than 700 SNPs.  When from different lineages SNP counts will obviously be higher in addition to the alignment error seen.
Pertaining to filtering individual SNPs...
vSNP is a tool developed for SNP analysis.  It can be applied to different specie types but was originally developed for use with TB complex isolates.  Code detail is here.
vSNP is a 2-step process.  First, generating VCF files.  Second, using those VCF files to output SNP tables and trees.  The goal of the script is to achieve a high resolution genotyping analysis that can be validated with minimal effort.  Some steps are included to help achieve this such as reference selection, automatic grouping and position filtering.
Pseudocode:
For set of VCF files created from the same reference...
def find_positions()
    AC=2
    QUAL &gt; 300 

For each found position...
def get_snps()
    AC=2 (solid call)
    QUAL &gt; 50
        THEN --&gt; SNP
    AC=1 (mix call)
    QUAL &gt; 150
        THEN --&gt; AMBIGIOUS
    AC=2
    QUAL &gt;= 50
       THEN --&gt; REF
    QUAL &lt; 50
       THEN --&gt; N
    ALT == &quot;None&quot;
       THEN --&gt; -

First find all possible positions that could be informative in all samples/VCF files: find_positions(), then define each position to be included in the alignment: get_snps().
Then it can be convenient to filter consistently poor alignment regions such as PPE/PGRS.