Resumo

  • O draft-ietf-jmap-object-history-00 acrescenta versões anteriores e destruídas ao Foo/get, mas permite condensar atualizações rápidas, remover versões em qualquer ordem e descartar histórico silenciosamente sob pressão de armazenamento.
  • Um retrato recuperado ajuda a restaurar dados. Ele não identifica ator, pedido, decisão de autorização nem efeito posterior; até hasMoreHistory: false é incapaz de certificar que o histórico está completo.

Um catálogo de contatos pode trazer de volta o telefone removido ontem. Uma caixa postal pode mostrar a mensagem como estava imediatamente antes da exclusão. É uma função útil: torna reversível um erro e evita que cada cliente invente seu próprio arquivo paralelo.

Os mesmos campos, porém, podem transmitir uma certeza que o protocolo não oferece. Um ID constante, um número de versão e um horário de substituição viram facilmente uma linha do tempo elegante. Nenhum deles diz quem agiu, qual cliente enviou a mutação, qual regra autorizou a operação ou se a consequência posterior aconteceu.

Essa é a fronteira decisiva do JMAP Object History, enviado em nome do grupo de trabalho em 15 de setembro. A proposta torna consultável um estado antigo. Ela não transforma um depósito de recuperação em livro de auditoria.

O protocolo devolve estados retidos, não eventos

O núcleo do JMAP define uma família de métodos para cada tipo de objeto: Foo/get, Foo/changes, Foo/set, Foo/query e Foo/queryChanges. A sincronização do estado atual já faz parte da arquitetura. Foo/changes informa quais IDs mudaram entre estados, mas não entrega os valores anteriores.

A capability urn:ietf:params:jmap:object-history amplia Foo/get. Com includeReplaced: true, representações substituídas aparecem ao lado do objeto vigente. Com includeDestroyed: true, é possível pedir objetos que deixaram de existir. Se os dois forem usados, o servidor pode devolver todas as versões ainda retidas de um objeto destruído.

Cada versão conserva o mesmo ID. objectHistory.version estabelece a ordem dentro da resposta. objectHistory.replaced registra quando aquela representação foi substituída por atualização ou destruição; null marca o objeto vivo.

São coordenadas de estado, não a proveniência de um acontecimento. O horário de substituição não informa quando a versão nasceu. O número não nomeia uma transação. Nenhum campo traz ator, sessão, dispositivo, corpo do pedido, política aplicada, aprovação, motivo, notificação ou efeito externo.

Dois retratos vizinhos permitem calcular a diferença de valores. Não demonstram que uma única ação atômica causou essa diferença.

O meio ausente talvez nunca tenha sido registrado

O texto permite explicitamente que o servidor reúna várias atualizações rápidas em uma só versão. Se um número de telefone for alterado três vezes em pouco tempo, talvez reste apenas o valor anterior e o posterior ao intervalo. Não é obrigatório criar uma linha histórica para cada ação.

Também é permitido podar versões antigas em qualquer ordem. Lacunas na sequência são válidas, e o cliente não pode presumir que o histórico seja contínuo ou completo. Uma ausência admite duas explicações: uma versão separada nunca foi criada, ou foi criada e eliminada depois.

Até o número é fraco entre consultas. O servidor deve procurar consistência, mas o cliente não pode depender dela. A finalidade principal é ordenar versões do mesmo objeto em uma resposta. Tratá-lo como ID durável de evento de auditoria exigiria uma propriedade que a proposta deliberadamente não promete.

Isso dá honestidade econômica ao desenho. Também torna inválida a pergunta “mostre tudo o que aconteceu” quando não existe um sistema de eventos separado.

hasMoreHistory é orientação de busca, não certificado de completude

historyLimit limita o total de entradas e pede as versões mais recentes. Se o limite for alcançado para qualquer ID solicitado, hasMoreHistory: true informa que há material retido mais antigo naquele momento. Numa resposta com vários objetos, não revela qual deles tem continuação; cada um precisa ser consultado separadamente.

O valor verdadeiro é transitório. A proposta avisa que as entradas antigas podem ser eliminadas antes da próxima chamada. A marca descreve disponibilidade instantânea, não reserva os dados.

O valor falso é ainda menos conclusivo. Normalmente significa que todo o histórico retido para aqueles IDs foi devolvido. Mesmo assim, o servidor pode responder falso quando há mais histórico se for caro demais determiná-lo. E falso não quer dizer que toda mudança foi capturada, que nada foi podado ou que toda representação ainda existente foi encontrada.

Um painel que converta falso em “auditoria completa” inverte o contrato. O rótulo defensável é mais limitado: nenhum histórico retido adicional foi informado nesta resposta.

Duração nula não quer dizer retenção eterna

Uma conta que anuncia a capability expõe maxHistoryDuration. Um número é a idade máxima, em segundos após a substituição, depois da qual uma versão pode ter sido descartada. Null indica que o servidor não impõe limite baseado em tempo.

Null não significa permanente. A seção de segurança reconhece pressão de armazenamento e autoriza o descarte silencioso ao atingir os limites. Tempo é um controle de retenção; espaço total é outro. Um tipo pode até oferecer a interface e não manter versão anterior alguma. Ainda assim, devolve o objeto atual com objectHistory e pode chamar todos os objetos correntes de versão 1.

Portanto, a capability prova a existência de uma interface, não de um acervo probatório mínimo. Aquisição e conformidade precisam fixar retenção mínima, aviso de exclusão, exportação, integridade e preservação legal em contratos próprios.

Recuperação e responsabilização precisam de recibos diferentes

Para recuperação, a superfície é bem desenhada. Um cliente pode perguntar a Email/changes quais IDs foram destruídos, passar esses IDs a Email/get, solicitar objetos excluídos e apresentar os últimos valores anteriores à remoção. O usuário recupera conteúdo sem o protocolo fingir que ele continua ativo.

Para responsabilização, faltam colunas. Um recibo robusto precisa ligar ator autenticado e sessão, cliente e dispositivo de origem, corpo exato da mutação, token de estado condicional, versão e decisão da política de autorização, transação aceita pelo servidor, hashes anterior e posterior, ID durável do evento, entrega de notificação e resultado observado.

O histórico pode oferecer uma representação anterior ou posterior. Não preenche o restante. Inferir o autor a partir do dono do objeto é inseguro. Inferir autoridade a partir da mudança visível ignora a política aplicada. Inferir efeito externo a partir de um valor armazenado confunde aceitação no plano de controle com execução e observação.

Quando houver dever de prestar contas, a arquitetura deve unir retratos de recuperação a um registro append-only. Não deve fingir que um único depósito cumpre dois contratos incompatíveis.

Acesso histórico não é apenas o acesso de hoje

O passado introduz um problema de autorização. Quem não pode ler o objeto atual não pode ler seu histórico. Se as permissões mudaram ao longo do tempo, o servidor deve entregar apenas as versões que o solicitante teria tido direito de ler naquela época.

A regra impede que um leitor recém-autorizado veja valores anteriores ao seu direito de acesso. Também exige que o servidor retenha contexto histórico suficiente para decidir. Uma lista de controle atual pode não conseguir reconstruir a resposta correta.

O JMAP Sharing já separa principais, permissão pretendida e acesso efetivo. Object History acrescenta tempo: o direito de inspecionar uma versão antiga depende de um direito antigo, não apenas do mapa shareWith atual. A versão devolvida evidencia que o servidor decidiu revelá-la, mas não documenta por completo essa decisão sem um registro independente.

Às vezes, o histórico correto é incompleto de propósito

Uma cópia antiga pode revelar justamente a informação que alguém quis remover. Um telefone apagado de um contato pode permanecer na história. Por isso o texto recomenda uma capacidade administrativa de purgar o histórico de objetos específicos por privacidade ou conformidade.

Não é uma falha a esconder. Recuperação, responsabilização, apagamento e custo de armazenamento apontam para direções diferentes. Para cada classe de dados, é preciso declarar qual objetivo prevalece, quem pode autorizar a purga, se um recibo resistente a adulteração permanece e quais fatos independentes sobrevivem depois que o conteúdo é removido.

Prometer “histórico imutável” sobre uma interface feita para permitir exclusão seria perigoso. Desligar a recuperação por ela não ser um livro forense seria igualmente ruim. A solução é separar os depósitos e publicar seus limites.

Adoção pelo grupo de trabalho não é implantação

O documento de setembro é quase idêntico ao rascunho individual de março. O corpo do protocolo não ganhou nova evidência. A mudança relevante é que a proposta agora leva o nome do grupo JMAP.

O Datatracker o classifica como WG Document em I-D Exists. Não há area director responsável, shepherd ou telechat informados. O resumo deixa vazio o intended status, enquanto o cabeçalho do rascunho diz Standards Track. Continua sendo Internet-Draft, não RFC, e as fontes congeladas não comprovam implementação ativa nem política de retenção em serviço identificado.

Essa fronteira de maturidade reforça a lição operacional. Um registro coordena o vocabulário entre implementações. Só evidência de execução mostra quais versões foram capturadas, condensadas ou podadas, quem tinha autorização e se a restauração funcionou.

Fontes