Elimina i falsi "componenti mancanti" dal rilevamento delle family table

Il record "model_name" veniva preso per l'identita' del file, ma sui file
reali nomina quasi sempre un altro modello - tipicamente uno dei membri del
file stesso. Il parser esatto rifiutava percio' file perfettamente
leggibili, il chiamante ripiegava sull'euristica testuale e quella
estraeva codici inesistenti, riportati poi come componenti non trovati
nell'indice.

Il segnale ora richiede la conferma del nome proprio del modello
(objname): scatta solo se il file dichiara davvero se stesso come istanza.

Verificato contro le BOM esportate da Creo per 7 assiemi reali: 6 vengono
riprodotte byte per byte (3 di queste prima non si generavano affatto), e
la settima differisce per una sola parte, presente nella revisione di un
sotto-assieme che Creo ha caricato ma assente in quella piu' recente. La
verifica di completezza passa su tutti e 7 (prima 3 risultavano
incompleti), e tutti i 351 .asm di una cartella raw/ reale si leggono col
parser esatto, senza mai ricadere sull'euristica.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
davideandClaude Opus 5 committed 2026-09-22 10:47:08 +02:00
1 parent b136e7f49b
commit 0ae2a5e7cf
3 files changed
+100 -76

No files matched your search

+22 -13
View File
@@ -67,12 +67,13 @@ public static class AsmRecordReader
// codice cercato nell'indice sarebbe la stringa intera con le parentesi, mai trovata.
private static readonly Regex IstanzaConGenericoRegex = new(@"^([\x20-\x7e]+?)<([\x20-\x7e]+)>$", RegexOptions.Compiled);
// sintomo vero e proprio (docs/formato-asm-record.md §7): il file e' esso stesso
// un'istanza di family table (il suo "model_name" ha il suffisso "_C0n" delle istanze,
// stessa convenzione di SuffissoArrayFeatureRegex/ConfigName sopra) - "members" descrive
// solo questa rappresentazione, non le istanze sorelle elencate in "stamp". Verificato su
// 2546220101.asm: la BOM Creo reale mostra 4 istanze diverse, "members" ne restituisce
// silenziosamente solo una.
// Suffisso "_C0n" delle istanze di family table (stessa convenzione di
// SuffissoArrayFeatureRegex/ConfigName sopra). Usato insieme a OwnModelIdentityRegex per
// riconoscere un file che e' esso stesso un'istanza, il cui "members" descriverebbe solo
// quella rappresentazione invece delle istanze sorelle (docs/formato-asm-record.md §7).
// Da solo NON basta: su file reali quel record nomina spesso un altro modello (un membro
// del file, o un codice imparentato), non il file stesso - per quello serve la conferma
// del nome proprio (objname).
private static readonly Regex SuffissoIstanzaFamilyTableRegex = new(@"_C\d{2,}$", RegexOptions.Compiled);
// primo elemento dell'array "members": porta le chiavi per esteso.
@@ -118,13 +119,6 @@ public static class AsmRecordReader
{
string testo = Encoding.Latin1.GetString(dati);
var identita = OwnModelIdentityRegex.Match(testo);
if (identita.Success && SuffissoIstanzaFamilyTableRegex.IsMatch(identita.Groups[2].Value))
throw new InvalidDataException(
$"assieme con family table: il file e' esso stesso l'istanza '{identita.Groups[2].Value}', " +
"'members' descriverebbe solo questa rappresentazione, non le istanze sorelle - vedi " +
"docs/formato-asm-record.md §7");
var configNameMatches = ConfigNameRegex.Matches(testo);
int configNameGrezzi = ContaOccorrenze(testo, (char)0xe3 + "ConfigName\0");
if (configNameMatches.Count != configNameGrezzi)
@@ -171,6 +165,21 @@ public static class AsmRecordReader
if (grezzi.Count != conteggio)
throw new InvalidDataException($"attesi {conteggio} membri, trovati {grezzi.Count}: lettura disallineata");
// Il record "model_name" e' l'identita' del file solo se il nome proprio del modello
// (objname, §5) lo conferma: da solo nomina spesso un altro modello - un membro del
// file, o un modello imparentato - e in quei casi "members" e' gia' corretto. Vedi
// docs/formato-asm-record.md §7.
var identita = OwnModelIdentityRegex.Match(testo);
var nomeProprio = ObjNameRegex.Match(testo);
if (identita.Success && nomeProprio.Success
&& SuffissoIstanzaFamilyTableRegex.IsMatch(identita.Groups[2].Value)
&& string.Equals(SuffissoIstanzaFamilyTableRegex.Replace(identita.Groups[2].Value, ""),
nomeProprio.Groups[1].Value, StringComparison.OrdinalIgnoreCase))
throw new InvalidDataException(
$"assieme con family table: il file e' esso stesso l'istanza '{identita.Groups[2].Value}', " +
"'members' descriverebbe solo questa rappresentazione, non le istanze sorelle - vedi " +
"docs/formato-asm-record.md §7");
return grezzi.Select(g =>
{
if (istanze.TryGetValue(g.Id, out var nomeIstanza))