Interação nativa & ações seguras no editor
O tdmcp agora pode pedir uma decisão destrutiva dentro do TouchDesigner sem manter a request HTTP original aberta. A Wave 1 adiciona um broker pequeno e autenticado, além de ações estruturadas que continuam funcionando com TDMCP_BRIDGE_ALLOW_EXEC=0.
Inbox nativa de decisões
O bridge de runtime tem uma página de parâmetros customizados chamada Interactions. Uma exclusão ou sobrescrita entra na fila, retorna como request ID opaco e é apresentada no frame seguinte do TouchDesigner. Selecione uma opção em Choice e pulse Apply Choice. Safe Close cancela com segurança: prompts destrutivos/de arquivo resolvem como Keep, enquanto consentimento OAuth resolve como Deny.
A inbox é não modal de propósito. Ela não chama ui.messageBox no callback do Web Server DAT, portanto nenhum prompt segura a request original além do timeout HTTP normal do cliente. Só um prompt é apresentado por vez; fila, TTL e registros retidos têm limites.
Todo encerramento inseguro significa Keep: timeout, close/cancel, perda do cliente, UI ausente, Perform Mode, headless, falha de agendamento ou consumo duplicado. Um prompt autoriza exatamente um alvo, uma única vez. Ele não executa Python, não recebe callables e não aprova outro operador ou arquivo.
Panic, blackout e outros caminhos de emergência não usam nem esperam o broker.
Delete / Bypass / Keep
delete_td_node com mode: "delete" apresenta exatamente:
- Delete — destrói o operador depois do consentimento;
- Bypass — liga a flag de bypass e preserva o operador;
- Keep — não altera o operador.
O prompt mostra path, tipo e nome do operador e resume o impacto local. O resultado traz decisão, path original/final, ação aplicada, política de confirmação, request ID e o nome de undo por request quando o build live o expõe.
Migração do comportamento antigo de delete
Chamadas existentes com { path, mode } continuam válidas, mas o default seguro mudou:
mode: "delete"agora exige consentimento nativo e retorna Keep quando a UI não consegue decidir;mode: "bypass"continua imediato e reversível;TDMCP_YOLO=1é a única política de skip no nível da tool. Ela aparece no resultado comoconfirmation_policy: "yolo"; ausência de UI nunca vira aprovação.
Reinstale ou recarregue o bridge de runtime com este código antes de usar o novo fluxo. Um bridge antigo sem o broker falha em vez de voltar ao delete legado sem confirmação.
Delete dentro de batch não pode pausar o batch para consentimento na UI. Um delete legado em batch agora retorna Keep com ok: false. Use o fluxo isolado de delete_td_node para consentimento nativo, ou torne a política do batch explícita com mode: "bypass" ou confirmation_policy: "yolo".
Delete não é intrinsecamente “impossível de desfazer”. A mutação REST final já passa pelo wrapper ui.undo do bridge. Um probe live confirmou que blocos aninhados comuns podem virar um único item com o nome do bloco externo, mas também mostrou que criar um annotateCOMP fecha/substitui o bloco externo do caller. Portanto ainda não é seguro habilitar um único undo para qualquer tool MCP de alto nível.
Save e Save As
save_td_project salva o .toe atual ou recebe um path absoluto .toe para Save As. Um alvo diferente já existente exige uma decisão Overwrite / Keep do broker. Não há diálogo de arquivo, load, quit nem fallback para raw Python.
Sucesso só é retornado depois que o arquivo aparece no disco. Projetos sem nome exigem um path de Save As. O ticket fica vinculado ao path normalizado e não pode autorizar outro arquivo.
Primitives conscientes do editor
get_editor_contextretorna projeto/build, Perform Mode, panes, o Network Editor explicitamente ativo, owner/current/selected, rollover de operador e parâmetro e viewport. Campos indisponíveis ficam ausentes ou nulos com warnings; a topologia não é despejada.pulse_td_parameterresolve operador e parâmetro, verifica o estiloPulse, chama.pulse()e retorna erros tipados para operador inválido, parâmetro ausente ou tipo incorreto.edit_td_node_metadataedita nome, parent, posição exata, cor, comentário e flags graváveis suportadas. Faz readback e rollback em falha parcial. Moves copiam e validam o destino antes de destruir a origem.create_td_nodeaceitaplacement: "auto" | "explicit",node_x/node_yexatos eviewer. Omissão preserva o drop antigo do TD; nodes idempotentes reutilizados preservam o layout existente.
Estado do undo
O bridge mantém um bloco de undo por request REST mutante. As novas mutações de metadata, Pulse, create e delete final recebem receipts úteis. O receipt agora traz o item nativo realmente visível no topo quando exatamente um item foi adicionado; quando o TouchDesigner troca o nome pelo built-in Delete Node ou Change Bypass Flag, a resposta raw do bridge informa separadamente o nome pedido pelo wrapper.
A validação live no TouchDesigner 2025.32820 provou que um bloco externo comum consegue desfazer e refazer duas edições aninhadas como um único item e que o finally fecha o bloco após uma exceção. Ela também reproduziu o blocker: criar um annotateCOMP dentro do bloco externo criou sua própria entrada Add Annotate, fechou/substituiu o bloco externo e fez o endBlock() do caller falhar. Transações entre requests e undo de uma tool MCP inteira seguem retidos até existir um protocolo de ownership que sobreviva ao undo específico de operadores, cancelamentos e timeouts sem deixar transação órfã.
Undo/redo automatizado de um item também está HELD. Um probe live com dois itens provou que este build expõe o stack do mais novo para o mais antigo (stack[0]) e que undo/redo nativo funciona, mas o probe de identidade mostrou que cada leitura retorna uma nova string simples. Duas ações diferentes podem se chamar Delete Node ou Change Bypass Flag; depois de uma edição interveniente do artista, um teste só por label ainda pode casar e desfazer a ação errada (ABA com o mesmo label). Contagens reduzem, mas não eliminam essa ambiguidade. Nenhuma tool ou route pública é registrada até o TD expor identidade estável ou um protocolo mais forte e consciente de edições do artista ser provado.
Wave 7: workflows transacionais e conscientes da ação
A Wave 7 estende tools existentes em vez de criar aliases. focus_network_editor, manage_component, make_portable_tox, manage_packages e add_custom_parameters agora compartilham primitives estruturados e limitados no bridge, e a nova tool insert_operator_at_selection adiciona a mutação de editor que faltava. As routes continuam autenticadas e funcionam com TDMCP_BRIDGE_ALLOW_EXEC=0; o caminho legado de load em manage_component não mudou e ainda usa sua implementação protegida pelo gate de exec.
Estado das evidências
| Área | Estado | O que a evidência prova |
|---|---|---|
| Follow do Network Editor consciente da ação | PASS — route no TD 2025.32820 | A route autenticada reutilizou panes visíveis/compatíveis, substituiu current/selection exatamente, executou seis frames com verificação de geração, cancelou gerações antigas rápidas e suprimiu Perform Mode. Processo headless real, outros builds e layouts incomuns com panes múltiplos/flutuantes seguem UNVERIFIED. |
| Inserção na seleção ativa | PASS — route autenticada, TD 2025.32820 | Com auth e exec desabilitado, cadeia simples, fan-out, multi-input, placement determinístico, replay/conflito, rollback induzido e undo/redo da route passaram sem conflito de thread. Proxies live de Connector exigiram identidade estrutural por owner/path/índice, não identidade Python. |
Exportação .tox transacional | PASS — route autenticada, TD 2025.32820 | as_is/portable, Overwrite / Keep, recuperação após perda de resposta, retry deduplicado, cancelamento, hash e limpeza passaram com exec desabilitado. Artefatos de filesystem continuam fora do undo do grafo TD. |
| Reconciliação do namespace de pacotes | PASS — TD autenticado + storage local | Keep, Bypass/Delete nativos, YOLO explícito auditado, rejeição de plano stale, quarentena/commit ou restore e undo/redo no TD passaram end to end. O fix live alinha fingerprints no OPType; undo restaura só o TD, não registry/filesystem já commitados. |
| Ciclo de parâmetros customizados | PASS — route autenticada, TD 2025.32820 | Add/edit/delete/sort/rename/delete-page, undo/redo exato, replay/conflito, rollback induzido e segurança do item de undo passaram. Os fixes live cobrem ParMode em módulo importado, identidade estrutural de ParGroup, rollback por estilo e ordem determinística de clamp/value. EXPORT segue HELD. |
| Undo/redo nativo automatizado de um item | REJEITADO | Undo/redo nativo funciona, mas o stack live expõe apenas labels repetíveis sem identidade estável. ABA com o mesmo label pode atingir uma ação interveniente do artista; uma route/tool genérica está permanentemente rejeitada. |
| Operação estruturada em uma request | PASS OFFLINE / ROUTE LIVE NÃO VERIFICADA | A Wave 15 adiciona preview com token obrigatório, commit em uma callback e observação de receipt autorizada por capability fora do wrapper genérico. O adapter já passou undo/redo do journal e rollback live, mas a nova route pública não pôde ser exercitada porque o segundo TD descartável não abriu listener. Nenhuma tool MCP foi registrada. |
| Undo de uma tool inteira entre requests REST | FAIL / DESIGN REJEITADO | O TD encerra um bloco de undo pendente quando cada callback do Web Server DAT retorna. Uma request posterior não consegue entrar nele com segurança; um undo removeu apenas a primeira mutação do probe. O bridge mantém um bloco nomeado por request REST mutante legado e nunca carrega um bloco entre requests. |
| Highlight por cor | HELD | Framing/current/selection foram entregues. A restauração transitória de cor sob ações sobrepostas e edições do artista não tem contrato compare-and-swap aceito; a Wave 7 não altera cores de nodes. |
PASS vale apenas para a evidência indicada na linha. Ele não promove TouchDesigner realmente headless, TouchPlayer, outros builds, comportamento de filesystem externo nem um caminho end-to-end autenticado que não foi executado.
Fronteira de operações da Wave 15
POST /api/operations/preview, /commit e /receipt são primitives guardados do bridge na árvore de código, não tools MCP. Eles exigem bearer token configurado antes do parsing do body e continuam utilizáveis com TDMCP_BRIDGE_ALLOW_EXEC=0. Preview é read-only. Commit possui uma transação síncrona com callback journal, e a recuperação do receipt exige ID opaco da operação, capability independente de 256 bits, o mesmo principal autenticado e a mesma instância do bridge. Capabilities ficam em bodies POST e nunca em labels de undo ou query strings. A idempotency key apenas deduplica um commit idêntico e é deliberadamente ausente dos receipts terminais.
A árvore de código ainda não expõe undo/redo genérico, revert por receipt, selection-to-component nem orquestração agent de plan/preview/commit. Revert exige journal de compensação consciente da direção e consentimento nativo Apply/Keep; collapse da seleção exige prova live de rollback exato de topologia e referências. O processo descartável da Wave 15 não chegou a um listener do bridge, portanto esses caminhos permanecem UNVERIFIED em vez de usar o projeto não salvo do artista como evidência.
Follow do Network Editor consciente da ação
A chamada legada { paths, animate } continua válida. Novos campos opcionais tornam o receipt e a política de UI explícitos:
action:create,edit,inspect,view,layoutoudelete;framing:auto,selection,ownerounone;enabled: opt-out explícito que retorna uma supressão tipada.
Os alvos precisam pertencer à mesma network parent. O bridge prefere o Network Editor ativo ou já dono do contexto, nunca cria um pane, substitui selection antiga, define um current explícito e faz readback final de owner, selection e viewport. animate:true usa seis passos ease-out limitados no frame seguinte; cada passo revalida a geração do pane e somente o sexto publica o readback final. Uma geração mais nova cancela passos antigos. Follow desabilitado, Perform Mode e sessões sem UI não movem o editor. O comportamento headless real segue UNVERIFIED, e o highlight por cor permanece HELD.
Inserção na seleção ativa
insert_operator_at_selection exige owner, único operador selecionado e current exatos do Network Editor ativo retornados por get_editor_context, além de uma chave opaca de idempotência. Qualquer drift falha antes da criação. O bridge só aceita tipo same-family criável no build live, define coordenadas explícitas, determinísticas e sem sobreposição imediatamente, desliga o viewer do novo node e substitui uma aresta downstream estável, preservando irmãos de fan-out e outros inputs downstream.
Criação, parâmetros, placement, conectores e readback final acontecem numa única mutação REST autenticada com um label de undo por request. Em falha, somente o novo node é desconectado/destruído e o snapshot exato de arestas é verificado; retry idêntico reapresenta receipt redigido e chave reutilizada com outro input falha fechada. placeOPs interativo, inferência de wire selecionado, inserção múltipla e raw Python não são expostos. O harness final exclusivamente no main thread passou pela route autenticada no 2025.32820 com exec desabilitado, incluindo rollback exato, replay/conflito e undo/redo da route.
Exportação TOX transacional
manage_component action:"save" agora usa a transação compartilhada as_is, e make_portable_tox usa portable. Ambas validam um alvo .tox absoluto, mantêm no máximo uma exportação ativa, gravam um arquivo temporário único no mesmo diretório, verificam tamanho/hash/build, promovem atomicamente e retêm um receipt de status limitado para polling e retry idempotente.
Overwrite agora usa overwrite_policy:"refuse" por default. Use "ask" para pedir um ticket Overwrite / Keep vinculado ao alvo exato; UI ausente nunca é consentimento. O modo portable tira snapshot de links/conteúdo de Text/Table DAT e do estado externaltox de COMPs, restaura tudo em finally e falha fechado fora do build provado live, a menos que o operador habilite explicitamente outro build testado separadamente. O .tox pode concluir enquanto sidecars de README/manifest falham; isso retorna partial_failure, nunca sucesso completo do pacote.
Com exec desabilitado no bridge, a exportação portable estruturada ainda roda. O helper existente de introspecção do README é best-effort e pode ser pulado com warning porque esse sidecar continua no caminho legado protegido pelo gate de exec.
Uma escrita no filesystem não é undo do grafo TouchDesigner. Não existe alegação de que ui.undo remova ou restaure um artefato exportado. Timeout/disconnect do cliente depois do dispatch também pode ser ambíguo; consulte o operation ID opaco antes de repetir.
Reconciliação do namespace de pacotes
manage_packages action:"reconcile" começa em dry-run. O plano varre um namespace limitado do projeto e só age sobre um marker único cujo package ID, fingerprint da source, ref e scope correspondem ao registro local de instalação. Candidatos estrangeiros, ilegíveis, incompatíveis, sem marker ou duplicados não são acionáveis.
Apply exige o plan_id ainda válido e revalida ownership. Keep não altera, Bypass preserva o COMP live, e Delete exige consentimento nativo, salvo política YOLO explícita. Arquivos locais staged são colocados em quarentena antes da mudança no registro; uma falha restaura a quarentena quando possível, e uma limpeza incompleta retorna partial_failure com remediação. Um uninstall legado que ainda tem alvo live no TD agora retorna esse plano seguro em vez de apagar primeiro o estado local.
Esse workflow nunca executa scripts de terceiros, instala dependências Python, baixa modelos nem configura aplicações externas.
Ciclo de parâmetros customizados
Chamadas existentes { comp_path, page, params } continuam significando add transacional. operations adiciona ações limitadas add, edit_parameter, delete_parameter, sort_page, rename_page e delete_page na mesma tool. Os estilos suportados são Float, Int, Toggle, Str, Menu, Pulse, Header, OP, TOP, File, Folder, XYZW e RGBA; inputs legados RGB/XYZ continuam aceitos. Modos EXPRESSION e BIND são suportados. O modo EXPORT está HELD e falha antes da mutação porque não foi provado um contrato reversível de export source.
A migração endurece de propósito o add parcial antigo: uma definição existente idêntica vira unchanged, uma definição conflitante falha sem replacement, e uma falha posterior restaura o snapshot completo das páginas customizadas ou retorna partial_failure. Built-ins nunca são editáveis. Sort precisa nomear cada ParGroup exatamente uma vez e passa ao TD apenas objetos par.parGroup, preservando componentes XYZW/RGBA. Resultados vêm por operação e campo; valores, expressões e bind expressions não entram nos receipts de idempotência.
Alerta de plugin externo específico deste ambiente
O alerta do macOS sobre não conseguir abrir serviços de criptografia do OS foi diagnosticado nesta máquina como FAIL de confiança da instalação local, não como falha do bridge tdmcp: o bundle atual do TouchDesigner tem requisito de código de recursos selados inválido, enquanto o FreenectTOP instalado tem assinatura ad-hoc e é rejeitado pelo Gatekeeper. O binário estar mapeado não prova que o operador registra ou cozinha; a ativação funcional segue UNVERIFIED.
Não apague itens do keychain, remova quarantine nem re-assine o app principal como atalho. O próximo experimento seguro é uma instalação oficial limpa do TouchDesigner verificada antes do primeiro launch, primeiro sem plugins externos e depois com um plugin assinado/notarizado pelo fornecedor em projeto isolado.
Exemplos de resultado da Wave 8
PASS — transação verificada
{
"status": "succeeded",
"operation_id": "opaque-export-id",
"verification": { "level": "load_independent" },
"cleanup": { "pending": false }
}FAIL — ownership não pôde ser provado
{
"status": "failed",
"code": "package_not_recorded",
"storage": { "quarantined": false, "recordRemoved": false }
}UNVERIFIED — limite da evidência
{
"status": "UNVERIFIED",
"checks": [
"TouchDesigner realmente headless",
"outros builds do TouchDesigner",
"registro e cook de plugin externo"
]
}Wave 9: componentes portáteis confiáveis e layout consciente de annotations
A Wave 9 estende tools existentes; não cria duplicatas de annotation, layout ou pacotes. Todas as operações novas no TouchDesigner usam routes estruturadas e autenticadas e funcionam com TDMCP_BRIDGE_ALLOW_EXEC=0.
manage_annotation action:"edit" edita título, corpo, cor RGBA e bounds exatos x, y, w, h de um annotateCOMP existente. O bridge resolve todos os aliases graváveis antes da mutação, fotografa o estado completo suportado, aplica e relê cada campo pedido e restaura o snapshot após uma falha parcial. Texto e comentário ficam redigidos nos logs e receipts. O edit não aceita os Text DATs de fallback que o create legado pode produzir.
arrange_network preserva o comportamento legado, salvo quando annotation_aware:true. O caminho opt-in lê um snapshot limitado de geometria, rejeita membership ambíguo entre annotations sobrepostas, planeja grupos sem Python raw e aplica posições com fingerprint do snapshot. Contexto stale falha antes de mutar. DATs docked seguem o delta do host; resize_annotations:true ajusta boxes não vazios ao conteúdo mais annotation_padding (default 80). Uma segunda execução idêntica reporta zero nodes movidos.
Para artefatos portáteis, validate_library_asset aceita validation_mode:"deep_roundtrip" somente com um bridge autenticado, explicitamente em quarantine e fora da porta 9980. Ele carrega o .tox num holder scratch único, espera frames com limite, compara o contrato declarado, captura erros/referências externas limitados e sempre tenta cleanup. Runtime ou prova ausente retorna UNVERIFIED, nunca PASS.
make_portable_tox agora grava por default um sidecar versionado de provenance. Ele liga o hash final do TOX ao hash canônico do manifest, identidade do COMP de origem, builds do TD/tdmcp e somente commit/estado dirty do Git. Nunca grava tokens, variáveis de ambiente, diffs, conteúdo do projeto ou raiz do repositório. Use provenance_policy:"require_clean" (e opcionalmente expected_git_commit) para um preflight estrito; Git indisponível, dirty ou com commit divergente falha antes do export. Alvos existentes ainda exigem consentimento nativo explícito, e TOX mais provenance são promovidos como um par recuperável.
O help_snapshot opcional inventaria tipos de operadores e APIs Python do TD explicitamente nomeadas com limites, lê somente o corpus OfflineHelp instalado do build exato, escreve índice/README determinísticos em docs/td-help e roda novamente o round-trip em quarantine após anexar. Caps, páginas ausentes ou build divergente viram UNVERIFIED honestamente. attach_docs_as_assets pode atualizar o snapshot depois e também atualiza atomicamente o hash do manifest na provenance existente.
Exemplos de resultado da Wave 9
PASS — contrato exact-build e cleanup verificados
{
"validation_mode": "deep_roundtrip",
"roundtrip": {
"verdict": "PASS",
"runtime": { "td_build": "2025.32820" },
"cleanup": { "verified": true }
}
}FAIL — provenance estrita recusa antes do export
{
"status": "FAIL",
"code": "git_worktree_dirty",
"export_started": false
}UNVERIFIED — inventário limitado não prova todas as entradas
{
"status": "UNVERIFIED",
"reason": "operator_type_cap",
"available": 1,
"truncated": 7
}Exemplos honestos de resultado
PASS — contrato offline e estado confirmados
{
"status": "PASS",
"decision": "Keep",
"action_applied": "keep",
"applied": false,
"final_path": "/project1/noise1"
}FAIL — operação estruturada inválida
{
"status": "FAIL",
"error": {
"code": "invalid_parameter_type",
"message": "pulse: parameter Gain has style Float, expected Pulse"
}
}UNVERIFIED — fora do runtime testado
{
"status": "UNVERIFIED",
"reason": "runtime não exercitado",
"checks": ["TouchDesigner realmente headless", "builds além de 2025.32820"]
}UNVERIFIED não é PASS. A matriz gráfica 2025.32820 passou; faça validação live separada antes de depender das mesmas semânticas em headless, outro build ou filesystem externo crítico para show.
Follow-ups adiados
OAuth/PKCE chegou numa wave posterior opt-in de autorização HTTP; veja OAuth, PKCE & consentimento no TouchDesigner. Estas waves não adicionam catálogos/instaladores remotos de skills, snapshot/restore do workspace, selection-to-component, highlight global animado, refactor amplo do bridge nem migração de todos os comandos destrutivos para o broker. Esses itens seguem separados. Skills curadas empacotadas e docs locais build-aware chegaram na wave seguinte; veja Agent build-aware & readiness do runtime.