← All rules
IOI-012 · IoI Rule · Temporal
Office XML Metadata Timestamp Inconsistent with MFT
✓ Validated Temporal Office core.xml $MFT
Contributed by @ioi-framework · 2025-01-01 · v1.5 · View scenario →
Invariant predicate φ
The Office XML embedded creation minute must be consistent with the MFT $SI creation minute for the same file path.
Download ioi-012.rq ↗
Tested on: Virtuoso 7.2 (OpenLink OSE)

Dependency specification

  1. Office XML metadata graphioi-ext:OfficeXMLFacet with ioi-ext:dctermsCreated; linked to observable:FileFacet providing fileName and normalized filePath
  2. $MFT graphioi-ext:MftFacet with created0x10 ($SI) and created0x30 ($FN); linked to observable:FileFacet providing normalized filePath

Matching is on case-insensitive comparison of normalized absolute observable:filePath values across two named graphs.

A document’s embedded Office XML creation minute must match the filesystem $SI creation minute for the same file path.

Contradiction condition

The embedded Office XML creation minute differs from the MFT $SI creation minute, indicating the document metadata and filesystem timestamp disagree. This catches either direction of timestamp manipulation while ignoring sub-minute skew, such as 14:26:00Z versus 14:26:37Z.

SPARQL signature

PREFIX core:       <https://ontology.unifiedcyberontology.org/uco/core/>
PREFIX observable: <https://ontology.unifiedcyberontology.org/uco/observable/>
PREFIX ioi-ext:    <https://ioi-framework.github.io/ns/ioi-ext/>
PREFIX xsd:        <http://www.w3.org/2001/XMLSchema#>

SELECT ?officeEntry ?fileName ?filePath ?xmlCreated
       (MIN(?mftSiCreated) AS ?mftSiCreated)
       (MIN(?mftFnCreated) AS ?mftFnCreated)
WHERE {
  GRAPH <https://ioi-framework.github.io/cases/AF-012/graphs/office> {
    ?officeEntry a observable:File ;
                 core:hasFacet ?xmlFacet, ?officeFileFacet .

    ?xmlFacet a ioi-ext:OfficeXMLFacet ;
              ioi-ext:dctermsCreated ?xmlCreated .

    ?officeFileFacet a observable:FileFacet ;
                     observable:fileName ?fileName ;
                     observable:filePath ?filePath .
  }

  GRAPH <https://ioi-framework.github.io/cases/AF-012/graphs/mft> {
    ?mftEntry a observable:File ;
              core:hasFacet ?mftFacet, ?mftFileFacet .

    ?mftFacet a ioi-ext:MftFacet ;
              ioi-ext:created0x10 ?mftSiCreated ;
              ioi-ext:created0x30 ?mftFnCreated .

    ?mftFileFacet a observable:FileFacet ;
                  observable:filePath ?mftFilePath .

    FILTER(LCASE(STR(?mftFilePath)) = LCASE(STR(?filePath)))
  }

  BIND(SUBSTR(REPLACE(STR(?xmlCreated), "T", " "), 1, 16) AS ?xmlCreatedMinute)
  BIND(SUBSTR(REPLACE(STR(?mftSiCreated), "T", " "), 1, 16) AS ?mftSiCreatedMinute)
  FILTER(?xmlCreatedMinute != ?mftSiCreatedMinute)
}
GROUP BY ?officeEntry ?fileName ?filePath ?xmlCreated
ORDER BY ?filePath

Graph IRI substitution

The checked-in rule uses the canonical placeholders:

  • https://ioi-framework.github.io/cases/AF-012/graphs/office
  • https://ioi-framework.github.io/cases/AF-012/graphs/mft

The executor rewrites AF-012 to the active case ID at runtime.

Implementation note

The Office XML graph is very small compared with the MFT graph. The normalized filePath join eliminates the earlier filename-only Cartesian-product problem, and the GROUP BY + MIN() pattern keeps the result stable when residual duplicate MFT matches exist. Timestamp comparison is intentionally minute-precision to avoid false positives from normal sub-minute write skew while still detecting bidirectional mismatches.