Running the composite test before the generated one is the kind of detail that only shows up after it has bitten someone, and it is the right call. There is a second ordering problem underneath it that the substring approach cannot reach. A C2PA manifest can embed ingredient manifests: the provenance of the assets that went into the file, not just of the file itself. A real photograph that had an AI-generated element composited into it carries its own assertion, which should read as composite, and also carries the ingredient's assertion, which is the bare trainedAlgorithmicMedia. Your scan sees the whole buffer as one string, so the bare token is present, the composite test and the generated test both have something to match, and the row that decides the verdict is whichever check you wrote first rather than whichever assertion describes this asset. Scoping the match to the active manifest's own assertion rather than to any byte in the file is the difference between reading the label and reading the packaging it arrived in. The other thing I would push into the result object is the distinction you already make in the UI. A file with no label and a file your own optimizer re-encoded above 10 MB are different epistemic states, and right now both arrive at the classifier as "no metadata signal" and get the same band table. Telling the user in the interface is not the same as encoding it in the verdict, and anything consuming this as an API sees only the band.
