38 lines
1.9 KiB
Python
38 lines
1.9 KiB
Python
"""Phase-local removal of storage navigation, never facts or database cells."""
|
|
import copy
|
|
|
|
NOTICE = "Model view omits storage hashes, byte sizes, archive/member navigation and JSON pointers from provenance containers. Source/evidence IDs, origins, authors, times, facts, rows, scope and uncertainty retain their meaning. Omitted navigation is not absence evidence; the complete immutable context is archived."
|
|
|
|
|
|
def project(value):
|
|
result = copy.deepcopy(value)
|
|
def provenance(node):
|
|
if isinstance(node, list): return [provenance(x) for x in node]
|
|
if not isinstance(node, dict): return node
|
|
return {k: provenance(v) if k in ('origin', 'provenance') else v
|
|
for k, v in node.items()
|
|
if k not in ('json_pointer', 'archive_ref', 'member_name', 'sha256', 'size')
|
|
and not (v is None and k in ('author', 'observed_at'))}
|
|
def visit(node):
|
|
if isinstance(node, list):
|
|
for x in node: visit(x)
|
|
elif isinstance(node, dict):
|
|
# Values in literal DB/source data must not be interpreted as metadata.
|
|
for k, v in list(node.items()):
|
|
if k in ('row', 'rows', 'value', 'values', 'text', 'lines'): continue
|
|
if k in ('provenance', 'origin'):
|
|
node[k] = provenance(v)
|
|
else: visit(v)
|
|
visit(result)
|
|
if isinstance(result, dict):
|
|
evidence = result.get('evidence', {})
|
|
for entry in result.get('evidence_catalog', []):
|
|
if isinstance(entry, dict) and entry.get('id') in evidence:
|
|
# The complete capture/query/provenance is already visible.
|
|
eid = entry['id']
|
|
collector = entry.get('collector')
|
|
entry.clear()
|
|
entry.update(id=eid, collector=collector, details_in='evidence')
|
|
if result != value: result['navigation_projection'] = NOTICE
|
|
return result
|