Table of Contents

BR-CHK — Regole di business del dominio Check / Verifica

Regole estratte dal dominio Check / Verifica di Infocad (registrazione di un CheckItem / verifica-controllo del patrimonio), ancorate al flusso pilota FLOW-CHK-001 (registrazione di una nuova verifica: costruzione DTO in scheda → controller → BL via .NET Remoting → DAL → stored procedure CHK_CREATECHECKITEM → tabella CHECK_ITEM + trigger di storico) e alla relativa evidenza. Sistema: Infocad (Descor), backend Oracle INFOCAD_TEST38, front-end ASP.NET Web Forms (VB.NET) CheckCenter + host applicativo Windows service InfocadServer (Controller → BL → DAL VB.NET) con hop .NET Remoting (WellKnownObjectMode.SingleCall), nessun ORM (stored procedure via DAL ExecuteNonQueryStoredProcedure).

Il dominio Check / Verifica è distinto dal dominio QualityCheck (BR-QC): qui l'entità è una singola verifica (CHECK_ITEM) con protocollo, tipo, stato, posizione (comprensorio/edificio/piano/vano o elemento generico via TABLENAME/ID_ELEMENT), data prevista, nota e score. Aspetti centrali: generazione server-side del protocollo, stato iniziale forzato a OPEN, id da sequenza + storico via trigger, e due difetti probabili già rilevati nel flusso (mapping ROOM_ID errato nel path attivo; DeleteHistoryByCheckID(21) hard-coded al Page_Load), oltre a una procedura citata ma assente dal catalogo (CHK_FINALDELETECHECKITEM).

Legenda enforcement: UI = validato solo lato interfaccia/code-behind · BL = logica applicativa (controller/BL/DAL) · DB = logica in stored procedure/trigger o constraint · mixed = più livelli. Legenda confidence: VERIFIED = catena di codice letta + controprova indipendente (sorgente DB da USER_SOURCE/USER_TRIGGERS riportata nell'evidenza del flusso, oppure catalogo procedure) · SUPPORTED = evidenza coerente ma un anello non eseguibile/riproducibile in questa sessione (nessun client Oracle disponibile) · INFERRED = dedotto dalla struttura, non testato.

⚠️ Nota di sicurezza (pattern TD-008): il grant applicativo 14020 è verificato solo lato UI (CheckItemDetail.ascx.vb:392). I CheckItemController/CheckItem_BL esposti via .NET Remoting non ri-verificano alcun grant (nessun HasUserGrant/CheckGrant nei sorgenti InfocadServer/CheckControllers e InfocadServer/CheckBL): qualunque client capace di raggiungere l'endpoint CheckItem_BL.rem può eseguire Insert/Update/Delete senza il grant.

⚠️ Nota DB: in questa sessione non è disponibile un client Oracle (sqlplus/sqlcl assenti); i sorgenti di stored procedure e trigger sono ripresi dall'evidenza VERIFIED del flusso FLOW-CHK-001 (lookup read-only USER_SOURCE/USER_TRIGGERS già eseguito). Il database-catalog.json è stato usato per confermare presenza/assenza delle procedure CHK_*.


Registro regole

ID Regola Tipo Enforcement Conf.
BR-CHK-001 Gate editing verifica: CanEdit = grant 14020 oppure SuperAdmin permission UI ⚠️ VERIFIED
BR-CHK-002 Grant 14020 non ri-verificato oltre il confine .NET Remoting (controller/BL) permission UI ⚠️ VERIFIED
BR-CHK-003 Create vs Update pilotato da ID_DTO (=0 ⇒ Insert; >0 ⇒ Update) state-transition UI/BL VERIFIED
BR-CHK-004 Stato iniziale forzato a OPEN dalla SP; lo stato scelto in UI è ignorato all'insert state-transition DB ⚠️ VERIFIED
BR-CHK-005 Protocollo generato server-side (CHK_GETNEWCHECKITEMPROTOCOL); quello in UI è ignorato dal DAL calculation DB/BL VERIFIED
BR-CHK-006 Formato protocollo = CInt(PPROTOCOL).ToString(regex) & suffix da CHECK_PROTOCOLFORMAT calculation DB/BL VERIFIED
BR-CHK-007 ID progressivo da SEQ_CHECK_ITEM via trigger BEFORE INSERT (NEXTVAL o allineamento) calculation DB VERIFIED
BR-CHK-008 Audit inline all'insert: LAST_UPDATED_BY=PUSERNAME, LAST_UPDATE_DATE=SYSDATE side-effect DB VERIFIED
BR-CHK-009 Storico automatico: trigger AFTER INSERT CHECK_ITEM_HISTORY_INS → riga su CHECK_HISTORY side-effect DB VERIFIED
BR-CHK-010 Ciclo di vita: cancellazione logica / restore / cancellazione definitiva via SP dedicate state-transition DB/BL SUPPORTED
BR-CHK-011 Nessuna validazione di dominio server-side (BL/DAL); eccezioni loggate e ri-lanciate validation BL ⚠️ VERIFIED
BR-CHK-012 DIFETTO: path attivo salva ROOM_ID = BuildingID (ci.BuildingID passato 2 volte) defect BL 🐞 VERIFIED
BR-CHK-013 DIFETTO: DeleteHistoryByCheckID(21) hard-coded in Page_Load cancella lo storico del check 21 a ogni load defect UI/BL 🐞 VERIFIED
BR-CHK-014 DIFETTO: CHK_FINALDELETECHECKITEM chiamata dal DAL ma assente dal catalogoFinalDelete fallisce a runtime defect DB/BL 🐞 SUPPORTED
BR-CHK-015 Campi non compilati dalla scheda assumono i default del DTO; EFF_CHECK_DATE persistito come 01/01/0001 data-quality UI/BL ⚠️ SUPPORTED

⚠️ = regola a rischio (solo-UI, solo-DB, hidden flag, date-logic app-side) · 🐞 = difetto probabile.


Dettaglio regole

BR-CHK-001 — Gate editing verifica: grant 14020 o SuperAdmin

  • Tipo: permission · Enforcement: UI ⚠️ · Confidence: VERIFIED · customer_specific: false
  • Statement: l'abilitazione all'editing/salvataggio di una verifica è concessa se l'utente ha il grant applicativo 14020 oppure è SuperAdmin; InitControls(CanEdit) abilita/disabilita i controlli di scheda.
  • Evidenza: InfocadWeb/WebMachine/CASSANDRA/CommonWeb/CheckCenter/UserControls/CheckItemDetail.ascx.vb:392-393
    392: Me.CanEdit = (HasUserGrant("14020") Or WS.SessionProfile.SuperAdmin)
    393: InitControls(Me.CanEdit)
    
  • Flag: solo-UI. Vedi BR-CHK-002 per la mancata ri-verifica server-side.

BR-CHK-002 — Grant non ri-verificato oltre .NET Remoting

  • Tipo: permission · Enforcement: UI ⚠️ (assenza di controllo BL) · Confidence: VERIFIED · customer_specific: false
  • Statement: la catena server-side CheckItemController.Insert/Update/FinalDelete/LogicalDelete/DeleteHistoryByCheckIDCheckItem_BL → DAL non effettua alcun controllo di grant/permessi: il controller si limita a inoltrare a Me.DAO (proxy remoting) e il BL delega al DAL. Il gate 14020 di BR-CHK-001 è quindi aggirabile da qualunque chiamante che raggiunga l'endpoint well-known CheckItem_BL.rem (SingleCall).
  • Evidenza:
    • assenza di controlli: grep -rniE 'HasUserGrant|HasGrant|CheckGrant|Permission' InfocadServer/CheckControllers InfocadServer/CheckBL0 risultati.
    • inoltro cieco controller: InfocadServer/CheckControllers/CheckItemController.vb:60-61
      60: Public Overloads Function Insert(ByVal dto As Common.DTO.DTOBase, ByVal username As String) As Integer ...
      61:     Return DirectCast(Me.DAO, ICheckItem_BL).Insert(dto, username)
      
    • registrazione endpoint: InfocadServer/Business/Start.vb:888
      888: RemotingConfiguration.RegisterWellKnownServiceType(GetType(Descor.Check.CheckBL.CheckItem_BL), "CheckItem_BL.rem", WellKnownObjectMode.SingleCall)
      
  • Flag: TD-008 (grant UI non ri-verificato dai servizi .NET Remoting).

BR-CHK-003 — Create vs Update pilotato da ID_DTO

  • Tipo: state-transition · Enforcement: UI/BL · Confidence: VERIFIED · customer_specific: false
  • Statement: al click su Salva, se ID_DTO > 0 la scheda instrada su Update() (verifica esistente), altrimenti su Insert() (nuova verifica). L'Update ricarica il DTO da DB (SelectById) e ri-applica i campi; l'Insert costruisce un DTO nuovo.
  • Evidenza: CheckItemDetail.ascx.vb:415-421
    415: Private Sub btnUpdate_Click(...) Handles btnUpdate.Click
    416:     If Me.ID_DTO > 0 Then
    417:         Update()
    418:     Else
    419:         Insert()
    

BR-CHK-004 — Stato iniziale forzato a OPEN; stato UI ignorato all'insert

  • Tipo: state-transition · Enforcement: DB ⚠️ (hidden flag / magic string) · Confidence: VERIFIED · customer_specific: false
  • Statement: alla creazione, la SP CHK_CREATECHECKITEM risolve lo stato iniziale con un lookup non parametrizzato SELECT ID_STATE FROM CHECK_STATE WHERE STATE='OPEN' e lo usa come STATE_ID. La scheda popola sì check.State.ID_DTO = ddlCheckState.SelectedValue (CheckItemDetail.ascx.vb:476), ma l'overload Insert del BL non passa lo stato al DAL (a differenza di Update, che passa ci.State.ID_DTO): lo stato scelto in UI è quindi ignorato in fase di insert.
  • Evidenza:
    • SP (sorgente DB, evidenza FLOW-CHK-001 B1): SELECT CHECK_STATE.ID_STATE INTO TMP_START_STATE FROM CHECK_STATE WHERE CHECK_STATE.STATE = 'OPEN';INSERT INTO CHECK_ITEM (... STATE_ID ...) VALUES (... TMP_START_STATE ...).
    • BL Insert (nessun parametro stato): InfocadServer/CheckBL/CheckItem_BL.vb:90-108 (lista argomenti passata al DAL priva di State.ID_DTO), contro Update che invece lo passa (:177).
  • Flag: magic string 'OPEN' in SP; hidden behaviour (la UI lascia scegliere uno stato che poi non ha effetto sulla creazione).

BR-CHK-005 — Protocollo generato server-side; protocollo UI ignorato dal DAL

  • Tipo: calculation · Enforcement: DB/BL · Confidence: VERIFIED · customer_specific: false
  • Statement: il protocollo della verifica è sempre generato lato server: il DAL chiama CHK_GETNEWCHECKITEMPROTOCOL (che legge formula/regex/suffisso da CHECK_PROTOCOLFORMAT), compone sProtocol e lo passa come PPROTOCOL alla SP di insert. Il valore protocol ricevuto dalla UI (lblProtValue.Text) è scartato: il parametro che lo usava è commentato e sostituito da sProtocol.
  • Evidenza: InfocadServer/CheckDAL/OracleODP/CheckItem_DAL.vb:305-321
    310: dl.ExecuteNonQueryStoredProcedure("CHK_GETNEWCHECKITEMPROTOCOL")
    315: sProtocol = String.Format("{0}{1}", CInt(sProtocol).ToString(Expression), Suffix)
    320: 'Dim protocolparam As New OracleParameter("PPROTOCOL", ... protocol ...)   ' <-- protocollo UI IGNORATO
    321: Dim protocolparam As New OracleParameter("PPROTOCOL", OracleDbType.Varchar2, sProtocol, ParameterDirection.Input)
    
    SP (evidenza FLOW-CHK-001 B2): SELECT PROTOCOLFORMULA, REGEXPRESSION, SUFFIX ... FROM CHECK_PROTOCOLFORMAT;

BR-CHK-006 — Composizione del protocollo (numero + regex + suffisso)

  • Tipo: calculation · Enforcement: DB/BL · Confidence: VERIFIED · customer_specific: false
  • Statement: il protocollo finale è composto dal numero progressivo (PPROTOCOL) formattato con l'espressione regex/format (PPROTOCOLREGEX) e concatenato al suffisso (PSUFFIX), entrambi provenienti da CHECK_PROTOCOLFORMAT. Il numero è convertito a intero prima della formattazione (CInt(sProtocol)), quindi un protocollo non numerico farebbe fallire la conversione.
  • Evidenza: CheckItem_DAL.vb:312-315 (composizione), :305-308 (parametri OUT PPROTOCOL/PPROTOCOLALGHORITM/PSUFFIX/PPROTOCOLREGEX).
  • Flag: CInt() su valore da DB — potenziale eccezione se il formato non è numerico (dipende dal dato di configurazione in CHECK_PROTOCOLFORMAT).

BR-CHK-007 — ID progressivo da sequenza via trigger BEFORE INSERT

  • Tipo: calculation · Enforcement: DB · Confidence: VERIFIED · customer_specific: false
  • Statement: l'ID_CHECK_ITEM è assegnato dal trigger BEFORE INSERT su CHECK_ITEM: se :NEW.ID_CHECK_ITEM è NULL prende SEQ_CHECK_ITEM.NEXTVAL, altrimenti riallinea la sequenza al valore fornito. La SP restituisce l'id via RETURNING ID_CHECK_ITEM INTO PNEWINDEX.
  • Evidenza: trigger CHECK_ITEM BEFORE INSERT (evidenza FLOW-CHK-001 B4):
    IF (:NEW."ID_CHECK_ITEM" IS NULL) THEN
      SELECT "SEQ_CHECK_ITEM".NEXTVAL INTO :NEW."ID_CHECK_ITEM" FROM DUAL;
    ELSE ... allinea sequenza ... END IF;
    
    DAL ritorno id: CheckItem_DAL.vb:345,378,380-382 (PNEWINDEX OUT → OracleDecimal.ToInt32).

BR-CHK-008 — Audit inline all'insert

  • Tipo: side-effect · Enforcement: DB · Confidence: VERIFIED · customer_specific: false
  • Statement: la SP di insert stampiglia LAST_UPDATED_BY = PUSERNAME (utente di sessione passato dalla UI) e LAST_UPDATE_DATE = SYSDATE direttamente nell'INSERT su CHECK_ITEM.
  • Evidenza: SP CHK_CREATECHECKITEM (evidenza FLOW-CHK-001 B1): INSERT INTO CHECK_ITEM (... LAST_UPDATED_BY, LAST_UPDATE_DATE) VALUES (... PUSERNAME, SYSDATE). Username origine UI: CheckItemDetail.ascx.vb:488 (checkItemCTRL.Insert(check, WS.SessionLogin.UserName)).

BR-CHK-009 — Storico automatico su insert (trigger)

  • Tipo: side-effect · Enforcement: DB · Confidence: VERIFIED · customer_specific: false
  • Statement: alla creazione di una verifica, il trigger AFTER INSERT CHECK_ITEM_HISTORY_INS scrive automaticamente una riga su CHECK_HISTORY con CHECK_ID, STATE_ID, DATE_TIME=SYSDATE, USERNAME, NOTE presi dal record inserito.
  • Evidenza: trigger CHECK_ITEM_HISTORY_INS (evidenza FLOW-CHK-001 B4):
    INSERT INTO CHECK_HISTORY(CHECK_ID, STATE_ID, DATE_TIME, USERNAME, NOTE)
    VALUES(:NEW.ID_CHECK_ITEM, :NEW.STATE_ID, SYSDATE, :NEW.LAST_UPDATED_BY, :NEW.NOTE);
    
  • Nota: analogamente, il cambio stato in Update produce storico via trigger UPDATE (CHECK_ITEM_HISTORY_UPD, citato nel flusso — non ri-letto in questa sessione).

BR-CHK-010 — Ciclo di vita: cancellazione logica / restore / cancellazione definitiva

  • Tipo: state-transition · Enforcement: DB/BL (mixed) · Confidence: SUPPORTED · customer_specific: false
  • Statement: una verifica può essere cancellata logicamente (CHK_LOGICALDELETECHECKITEM), ripristinata (CHK_RESTORECHEKITEM) o cancellata definitivamente (CHK_FINALDELETECHECKITEM, ma vedi BR-CHK-014). Le tre operazioni passano solo PIDCHECKITEM e ritornano sempre True lato DAL a prescindere dall'esito reale della SP.
  • Evidenza: CheckItem_DAL.vb:144-202
    151: dl.ExecuteNonQueryStoredProcedure("CHK_FINALDELETECHECKITEM")   ' FinalDelete
    171: dl.ExecuteNonQueryStoredProcedure("CHK_LOGICALDELETECHECKITEM") ' LogicalDelete
    192: dl.ExecuteNonQueryStoredProcedure("CHK_RESTORECHEKITEM")        ' Restore (nota il typo 'CHEK')
    153/173/194: Return True   ' esito non verificato
    
    Presenza SP nel catalogo: CHK_LOGICALDELETECHECKITEM, CHK_RESTORECHEKITEM presenti; CHK_FINALDELETECHECKITEM assente (vedi BR-CHK-014).
  • Flag: Return True fisso — la UI riceve "successo" anche se la SP non ha cancellato nulla. Il nome CHK_RESTORECHEKITEM contiene un refuso ("CHEK") ma coincide col nome effettivo in DB (non è un bug).

BR-CHK-011 — Assenza di validazione di dominio server-side

  • Tipo: validation · Enforcement: BL ⚠️ · Confidence: VERIFIED · customer_specific: false
  • Statement: né il BL né il DAL applicano validazioni di dominio (obbligatorietà, coerenza posizione, range score, esistenza tipo/stato): gli input arrivano dalla scheda tramite CInt(...)/CDate(...) e vengono passati as-is alla SP. Le eccezioni sono solo loggate (ExceptionLogger.LogException) e ri-lanciate.
  • Evidenza: CheckItem_BL.vb:88-110 (nessun controllo, solo mapping+delega); CheckItem_DAL.vb:384-386 (Catch ... LogException ... Throw). La sola "validazione" è il gate UI di BR-CHK-001.

BR-CHK-012 — DIFETTO: ROOM_ID salvato = BuildingID nel path attivo

  • Tipo: defect · Enforcement: BL 🐞 · Confidence: VERIFIED · customer_specific: false
  • Statement: nell'overload attivo usato dalla UI CheckItem_BL.Insert(dto, username), il valore ci.BuildingID viene passato due volte: come 6° argomento (buildingsId) e come 8° argomento, che nella firma del DAL è roomId → parametro PROOMID della SP. Di conseguenza la verifica creata dal CheckCenter memorizza ROOM_ID = BUILDING_ID invece del vano realmente selezionato (cmbRooms). L'overload senza username (Insert(dto)) passa correttamente ci.RoomID, ma non è il path della UI interattiva.
  • Evidenza:
    • firma DAL (8° param = roomIdPROOMID): CheckItem_DAL.vb:289 (ByVal roomId As Integer), :329 (New OracleParameter("PROOMID", ..., roomId, ...)).
    • overload attivo (bug), InfocadServer/CheckBL/CheckItem_BL.vb:88-98:
      88: Public Function Insert(ByVal dto As ..., ByVal username As String) As Integer ...
      95:     ci.DistrinctID,
      96:     ci.BuildingID,
      97:     ci.FloorID,
      97b:    ci.BuildingID,   ' 8° arg = roomId del DAL → dovrebbe essere ci.RoomID
      
      (righe 90-108: Protocol, RefProtocol, RefModule, CheckType.ID_DTO, DistrinctID, BuildingID, FloorID, BuildingID, ControllerID, ...)
    • overload corretto (non usato dalla UI): CheckItem_BL.vb:204 (ci.RoomID in 8ª posizione).
    • la UI usa l'overload con username: CheckItemDetail.ascx.vb:488.
  • Impatto: dato posizionale errato persistito (ROOM_ID), con effetti su filtri/report per vano. Da correggere sostituendo il secondo ci.BuildingID con ci.RoomID alla riga 97.

BR-CHK-013 — DIFETTO: DeleteHistoryByCheckID(21) hard-coded in Page_Load

  • Tipo: defect · Enforcement: UI/BL 🐞 (magic number) · Confidence: VERIFIED · customer_specific: false
  • Statement: a ogni caricamento della scheda CheckItemDetail, il Page_Load esegue incondizionatamente chkCTRL.DeleteHistoryByCheckID(21), che via BL→DAL invoca la SP CHK_DELETEHISTORYBYID cancellando lo storico (CHECK_HISTORY) del check con id 21 hard-coded. È codice di debug residuo con effetto di scrittura distruttiva su dati di un check specifico, eseguito anche in sola visualizzazione e a prescindere dal grant server-side (BR-CHK-002).
  • Evidenza: CheckItemDetail.ascx.vb:395-396
    395: Dim chkCTRL As New CheckItemController
    396: Dim retValue As Integer = chkCTRL.DeleteHistoryByCheckID(21)
    
    catena: CheckItemController.vb:85-86CheckItem_BL.vb:276-278CheckItem_DAL.vb:544-552 (CHK_DELETEHISTORYBYID).
  • Impatto: perdita ricorrente dello storico del check 21; chiamata eseguita a ogni postback/apertura scheda. Da rimuovere.
  • Tipo: defect · Enforcement: DB/BL 🐞 · Confidence: SUPPORTED · customer_specific: false
  • Statement: il DAL FinalDelete invoca la stored procedure CHK_FINALDELETECHECKITEM, ma tale procedura non è presente nel catalogo delle procedure CHK_* dello schema (database-catalog.json). Se effettivamente assente in DB, ogni chiamata a FinalDelete fallirebbe a runtime (es. PLS-00201: identifier must be declared / ORA-06550).
  • Evidenza:
    • chiamata: CheckItem_DAL.vb:151 (dl.ExecuteNonQueryStoredProcedure("CHK_FINALDELETECHECKITEM")).
    • assenza: elenco procedure CHK_* da docs/_generated/database-catalog.json — presenti CHK_LOGICALDELETECHECKITEM, CHK_RESTORECHEKITEM, CHK_CREATECHECKITEM, CHK_UPDATECHECKITEM, CHK_DELETEHISTORYBYID, CHK_GETNEWCHECKITEMPROTOCOL, CHK_GETPROTOCOLBYCHECKITEMID, … ma nessuna CHK_FINALDELETECHECKITEM.
  • Nota confidence: SUPPORTED e non VERIFIED perché in questa sessione non è disponibile un client Oracle per interrogare USER_OBJECTS/USER_PROCEDURES; l'assenza è confermata solo sul catalogo generato. Da verificare direttamente in DB.

BR-CHK-015 — Campi non compilati → default DTO; EFF_CHECK_DATE = 01/01/0001

  • Tipo: data-quality / date-logic · Enforcement: UI/BL ⚠️ · Confidence: SUPPORTED · customer_specific: false
  • Statement: la scheda in Insert() valorizza solo Protocol, RefModule, CheckType, State, DistrinctID, BuildingID, FloorID, RoomID, ExtimatedCheckDate, Note, Score. I campi CheckResult, Limitvalue, DocumentID, ControllerID, TableName, IdElement, EffectiveCheckDate non sono impostati e assumono i default del DTO (Integer=0, Boolean=False, Single=0, String=Nothing, DateTime=DateTime.MinValue). In particolare EffectiveCheckDate non valorizzata viene passata come 01/01/0001 e persistita in EFF_CHECK_DATE, valore-sentinella privo di significato di business.
  • Evidenza:
    • scheda: CheckItemDetail.ascx.vb:461-486 (campi valorizzati; EffectiveCheckDate è commentato, :485).
    • DTO: InfocadServer/CheckSharedObjects/Objects/CheckItem.vb:26-27 (_extimatedCheckDate/_effectiveCheckDate As DateTime), :31-33 (_checkResult As Boolean, _limitValue As Single, _documentId As Integer).
    • passaggio del default al DB: CheckItem_DAL.vb:336 (New OracleParameter("PEFFCHECKDATE", OracleDbType.Date, effectiveCheckDate, ...)).
  • Flag: date-logic app-side (data-sentinella 01/01/0001); da confermare se l'assenza di questi campi in creazione manuale è il comportamento atteso.

Note di copertura ed evidenza

  • Catena applicativa UI → Controller → (.NET Remoting) → BL → DAL letta riga per riga sui sorgenti CheckItemDetail.ascx.vb, CheckItemController.vb, CheckItem_BL.vb, CheckItem_DAL.vb, CheckItem.vb, Start.vb, DAOFactory.vb.
  • Sorgenti di stored procedure (CHK_CREATECHECKITEM, CHK_GETNEWCHECKITEMPROTOCOL) e trigger (CHECK_ITEM BEFORE INSERT, CHECK_ITEM_HISTORY_INS AFTER INSERT) ripresi dall'evidenza VERIFIED del flusso FLOW-CHK-001 (lookup read-only USER_SOURCE/USER_TRIGGERS).
  • Presenza/assenza delle procedure CHK_* confermata su docs/_generated/database-catalog.json.
  • Limite sessione: nessun client Oracle disponibile (sqlplus/sqlcl assenti); non è stato possibile ispezionare direttamente constraint/USER_OBJECTS per rafforzare BR-CHK-014 e i default di colonna.