8fabc87f6e
Three findings from @kartik-mem0 on this PR. The first two mean the fingerprint gate this PR added never worked, and the first would have broken the plugin. keyFingerprint was not in ALLOWED_KEYS, and assertAllowedKeys throws on an unknown key. So the first successful lookup wrote a config that every later load of the plugin rejected outright. Added there and to the manifest schema, with a round-trip test that parses a config carrying the field. readPluginAuth builds its result field by field and did not include keyFingerprint, so the comparison always ran against undefined, the resolved email was never used again, and telemetry fell back to the API key hash for every event. That is worse than the defect this PR set out to fix, which at least used the email. Returned now, with a test against the real reader. Both were invisible to the telemetry tests because those mock the config module, and the mock returned a field the real reader drops. That is the actual lesson here, so the new tests live in config-file.test.ts and config.test.ts against the real implementations. Confirmed both fail without the fixes. flush() also had no in-flight guard. Two overlapping flushes each detach the queue and each prepend their own batch back on failure, so the later batch landed in front of the earlier one and the truncation then dropped the OLDER events first, inverting the priority the failure path exists to establish. Serialized with a guard; a second caller returns and the queue waits for the next flush. Regression test asserts one delivery in flight and the backlog order preserved. core 37, openclaw 435, opencode 35, deepseek 47. Wire e2e 9 of 9, exit cost unchanged at 6s failing and 12ms healthy. Claude-Session: https://claude.ai/code/session_01C7tEmH86HAr7GoAAKCEHZb