← SWIFT: decisões de suporte e projetos bancários
07 / 10 · 60 MIN

Oficina: dados de referência, deltas e ativação

Preparar atualizações reproduzíveis de dados de referência, separar receção e ativação e diagnosticar versões divergentes entre consumidores.

Definir o contrato da atualização

A página pública SwiftRef descreve entregas completas e incrementais. O exercício usa essa distinção para estudar uma decisão de engenharia: como substituir dados sem publicar um estado parcial. O formato Python desta aula é inventado pela DR. PARTY-A e ROUTE-OLD não são entradas de diretório nem instruções de encaminhamento. Antes de integrar um produto real, obter o contrato da entrega, significado dos campos, regras de sequência e calendário aplicável. Anotar também qual equipa publica o pacote, qual equipa o importa e quem decide a ativação. Uma transferência concluída demonstra receção de bytes; a utilização correta pelos consumidores exige evidência adicional.

Aplicar a cadeia e todas as operações

A base sintética está na versão 10. O delta declara base 10 e destino 11, altera a rota de A, elimina B e acrescenta C. O resultado esperado contém A com a nova rota e C, sem B. Receber um delta destinado a base 9 não autoriza mudar o rótulo para 10. Falta demonstrar o estado de partida. Também não se pode substituir a base inteira pelo conteúdo incremental, pois este pode omitir registos que permanecem válidos. Neste modelo, repetir o delta após publicar 11 é recusado. Prever estes resultados antes da execução torna visíveis os erros do importador.

Preservar a base perante falha

O programa prepara uma cópia e valida as operações antes de devolver o candidato. Uma identidade repetida, eliminação de registo ausente ou rota em falta provoca erro local. A base original continua intacta. Este comportamento evita que a terceira operação inválida deixe as primeiras duas publicadas. Não demonstra transações de base de dados, concorrência nem persistência após falha de energia: o exercício funciona em memória. Num desenho de produção, acrescentar os mecanismos adequados e ensaiar interrupções. O PM deve pedir o resultado esperado da falha, a responsabilidade de recuperação e a prova de que a versão anunciada corresponde aos dados realmente usados.

Distinguir os tempos e observar consumidores

No caso fictício, o pacote chega às 09:00, recebe aprovação às 09:30 e só pode ser ativado às 10:00. São três eventos diferentes. Guardar apenas a hora do download perde informação necessária. Depois da ativação, confirmar a versão carregada por cada instância e executar uma consulta conhecida. Ter o ficheiro 11 no disco não demonstra que um processo ainda ativo deixou de usar 10. Se houver rollback, identificar as decisões tomadas durante a janela afetada: repor dados anteriores não apaga efeitos já produzidos. Uma reconciliação pode continuar necessária depois da recuperação técnica.

Formato, identidade e acesso

Um padrão de caracteres pode verificar a forma de um BIC, mas não demonstra a existência ou estado do registo. A parte opcional de três caracteres pode identificar uma unidade; truncar para oito caracteres pode perder essa distinção. Consultar a referência adequada e conservar os atributos relevantes com a sua data. Para uma integração SwiftRef por API, o guia de acesso Live recomenda uma conta organizacional dedicada, separada da conta pessoal. No projeto, tratar a atribuição de direitos como uma dependência com responsável. O laboratório não cria contas, não consulta diretórios e não demonstra qualquer direito de acesso real.

Executar e preparar a passagem à operação

Reservar quinze minutos para prever as alterações, vinte para executar o programa e introduzir uma falha, quinze para comparar base e candidato e dez para explicar a recuperação. O código abaixo é completo e usa apenas a biblioteca padrão de Python. Guardar evidence.json com a versão do intérprete e hash do programa. O relatório inclui 35 verificações, incluindo as observações RMA da aula seguinte. Entregar também a lista de pressupostos e questões por resolver. Um colega deve conseguir repetir o caso sem depender de explicação oral. Se a prática for individual, registar autoavaliação, sem alegar aceitação independente da operação.

"""Original DR reference-data and RMA observation models. Python 3.13 stdlib.
python3 run.py --output evidence.json
No Swift SDK, API call, credentials, actual directory records or messages.
The delta format, activation window, cache TTL and decision labels are fictional.
"""
import argparse
import copy
import hashlib
import json
import sys
from pathlib import Path

checks=[]
def check(name, actual, expected):
    assert actual==expected,(name,actual,expected)
    checks.append(dict(name=name,actual=actual,expected=expected,passed=True))
def error(fn):
    try:fn()
    except ValueError as e:return str(e)
    raise AssertionError('Expected local model rejection')

def apply_delta(snapshot, delta):
    if delta['base']!=snapshot['version']:raise ValueError('wrong base')
    if delta['version']<=delta['base']:raise ValueError('non-increasing version')
    changed=copy.deepcopy(snapshot)
    seen=set()
    for op in delta['operations']:
        key=op['id']
        if key in seen:raise ValueError('duplicate operation identity')
        seen.add(key)
        if op['kind']=='delete':
            if key not in changed['records']:raise ValueError('delete absent record')
            del changed['records'][key]
        elif op['kind']=='upsert':
            if not op.get('route'):raise ValueError('missing route')
            changed['records'][key]=op['route']
        else:raise ValueError('unknown operation')
    changed['version']=delta['version']
    return changed

def activate(candidate, approved, now, effective_from):
    # Test record activation only, not a Swift schedule or bank instruction.
    return candidate if approved and now>=effective_from else None

def usable_cache(entry, request, now, ttl):
    # Query scope includes direction through ordered issuer/correspondent.
    key_fields=('environment','issuer','correspondent','service','message')
    return (all(entry[k]==request[k] for k in key_fields)
            and 0<=now-entry['observed_at']<ttl)

def classify(http,payload):
    # Original consumer decision labels, not Swift API response fields.
    if http!=200:return 'API_OBSERVATION_FAILED'
    if not isinstance(payload,dict):return 'INCOMPLETE_OBSERVATION'
    state=payload.get('authorization_status')
    if state=='AUTHORIZED':return 'RELATION_REPORTED_AUTHORIZED'
    if state=='NOT-AUTHORIZED':
        return 'RELATION_REPORTED_NOT_AUTHORIZED' if payload.get('reason') in {'REVOKED','REJECTED','EXPIRED','NON-EXISTENT'} else 'INCOMPLETE_OBSERVATION'
    return 'INCOMPLETE_OBSERVATION'

def main():
    base=dict(version=10,records={'PARTY-A':'ROUTE-OLD','PARTY-B':'ROUTE-B'})
    delta=dict(base=10,version=11,operations=[dict(kind='upsert',id='PARTY-A',route='ROUTE-NEW'),dict(kind='delete',id='PARTY-B'),dict(kind='upsert',id='PARTY-C',route='ROUTE-C')])
    next_state=apply_delta(base,delta)
    check('delta updates one record',next_state['records']['PARTY-A'],'ROUTE-NEW')
    check('delta applies deletion','PARTY-B' in next_state['records'],False)
    check('delta inserts record',next_state['records']['PARTY-C'],'ROUTE-C')
    check('base remains unchanged',base,dict(version=10,records={'PARTY-A':'ROUTE-OLD','PARTY-B':'ROUTE-B'}))
    check('version advances only after validation',next_state['version'],11)
    check('wrong baseline rejected',error(lambda:apply_delta(base,{**delta,'base':9})),'wrong base')
    check('same version rejected',error(lambda:apply_delta(base,{**delta,'version':10})),'non-increasing version')
    check('repeat delta rejected',error(lambda:apply_delta(next_state,delta)),'wrong base')
    bad={**delta,'operations':delta['operations']+[dict(kind='upsert',id='PARTY-A',route='OTHER')]}
    check('duplicate change identity rejected',error(lambda:apply_delta(base,bad)),'duplicate operation identity')
    check('failed candidate does not mutate active snapshot',base,dict(version=10,records={'PARTY-A':'ROUTE-OLD','PARTY-B':'ROUTE-B'}))
    check('absent deletion rejected',error(lambda:apply_delta(base,{**delta,'operations':[dict(kind='delete',id='ABSENT')]})),'delete absent record')
    check('missing route rejected',error(lambda:apply_delta(base,{**delta,'operations':[dict(kind='upsert',id='PARTY-A')]})),'missing route')
    check('future effective version held',activate(next_state,True,9,10),None)
    check('effective boundary activates',activate(next_state,True,10,10)['version'],11)
    check('unapproved version held',activate(next_state,False,10,10),None)
    req=dict(environment='LIVE',issuer='PARTY-A',correspondent='PARTY-B',service='DR-SERVICE',message='DR-TYPE-1')
    cached={**req,'observed_at':100,'state':'AUTHORIZED'}
    check('cache within local scope and TTL',usable_cache(cached,req,104,5),True)
    check('cache expires at exact local boundary',usable_cache(cached,req,105,5),False)
    check('future timestamp rejected',usable_cache(cached,req,99,5),False)
    for name,change in [('environment',{'environment':'PILOT'}),('issuer',{'issuer':'PARTY-C'}),('correspondent',{'correspondent':'PARTY-C'}),('service',{'service':'DR-OTHER'}),('message',{'message':'DR-TYPE-2'}),('direction',{'issuer':'PARTY-B','correspondent':'PARTY-A'})]:
        check('cache '+name+' mismatch rejected',usable_cache(cached,{**req,**change},104,5),False)
    check('HTTP success may report not authorized',classify(200,{'authorization_status':'NOT-AUTHORIZED','reason':'REVOKED'}),'RELATION_REPORTED_NOT_AUTHORIZED')
    check('HTTP success reports authorization only',classify(200,{'authorization_status':'AUTHORIZED'}),'RELATION_REPORTED_AUTHORIZED')
    for status in (401,403,429,503):
        check(str(status)+' is failed observation',classify(status,{}),'API_OBSERVATION_FAILED')
    check('missing status is incomplete',classify(200,{}),'INCOMPLETE_OBSERVATION')
    check('unknown status is incomplete',classify(200,{'authorization_status':'PENDING'}),'INCOMPLETE_OBSERVATION')
    check('negative state missing reason is incomplete locally',classify(200,{'authorization_status':'NOT-AUTHORIZED'}),'INCOMPLETE_OBSERVATION')
    check('non object is incomplete',classify(200,[]),'INCOMPLETE_OBSERVATION')
    check('request cache does not model settlement','settlement' in cached,False)
    output=dict(scope='Original in-memory synthetic models; not a SwiftRef file parser, RMA implementation, actual API query, directory validation, message authorization or settlement evidence.',python=sys.version.split()[0],runnerSha256=hashlib.sha256(Path(__file__).read_bytes()).hexdigest(),passed=len(checks),checks=checks)
    parser=argparse.ArgumentParser();parser.add_argument('--output',required=True)
    Path(parser.parse_args().output).write_text(json.dumps(output,indent=2)+'\n');print(json.dumps({'passed':len(checks),'scope':output['scope']}))
if __name__=='__main__':main()
NA PRÁTICA

Caso: duas instâncias anunciam release 11, mas uma mantém dados da versão 10 em memória. A verificação deve observar a versão carregada e um resultado conhecido por instância.

Armadilhas comuns

Ignorar eliminações; alterar a base declarada; publicar alterações parciais; tratar ficheiro no disco como prova da versão em utilização.

Tópicos relacionados: Identificadores, relações e dados de referência · Estados, reconciliação e recuperação sem duplicar · Continuidade e passagem à operação

Leva esta ideia contigo

Uma atualização é reproduzível quando a base, as operações, o momento de ativação e o resultado de cada consumidor estão identificados.

Criar conta

Referência: SwiftRef · DR Swift knowledge assessment2026.10; independent professional curriculum

SWIFT® é uma marca registada de S.W.I.F.T. SC. A dr.pt é uma plataforma de preparação independente e não está afiliada, associada, patrocinada, autorizada nem aprovada por Swift. Os conteúdos e as perguntas são originais, não são perguntas oficiais de exame, e concluir os nossos testes não atribui nem garante qualquer certificação. Os nomes são usados apenas para identificar o tema. Todas as outras marcas pertencem aos respetivos titulares.