testsAndMisc/docs/superpowers/contracts/endurain-db-dedupe-2026-08-23.json
Krzysztof kuhy Rudnicki 5ba2cbd476
Some checks are pending
Pre-commit checks / pre-commit (push) Waiting to run
Python tests / test (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
Dedupe endurain imports against postgres when the API cannot answer
Endurain API keys are upload-only by design: the scope allow-list is
frozenset({"activities:upload"}), enforced in both validate_api_key_scopes
and the create schema, and the activities read route is mounted with
validate_access_token rather than validate_access_token_or_api_key. A key
therefore fails at authentication before any scope check, so the HTTP
dedupe check added in 325d5a8b could never succeed and every pass fell
back to the ledger alone. Verified against v0.19.0; upstream documents no
plan to widen the allow-list.

Read the start times out of postgres instead. The container publishes no
host port, so this goes through docker exec -- no new dependency and no
port opened just to read four rows. The HTTP path is still tried first so
the supported route resumes working on its own if the allow-list ever
grows.

None and [] are kept strictly apart: a dead container, timeout or non-zero
exit means "could not ask" and returns to the ledger, while an empty result
set is a real answer. Conflating them would re-upload everything on any
docker hiccup, which is the bug the dedupe check exists to prevent.

Proven with an empty ledger: the known-duplicate TCX was skipped and the
activity count held at 4, and the same file WAS imported with
ENDURAIN_NO_DB=1, so the check is what blocks it. The duplicate that
negative control created was removed afterwards.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GbYEnfGnf1988cdFdGebot
2026-08-23 15:23:08 +02:00

20 lines
1.6 KiB
JSON

{
"title": "endurain importer dedupe via postgres",
"objective": "Give the importer a working answer to 'does Endurain already hold this run?', now that the HTTP route cannot provide one: API keys are upload-only and the activities read endpoint is JWT-only, so the existing check always returned None and every pass relied on the local ledger alone.",
"acceptance_criteria": [
"A run Endurain already holds is skipped even when the local ledger is empty, and the activity count does not grow.",
"The same run IS imported when the fallback is disabled, proving the check is what blocks it.",
"A dead or renamed container yields None (ledger fallback), while a user with no activities yields an empty list; the two are never conflated.",
"The journal distinguishes which backend answered, so a DB-sourced pass is not mistaken for a ledger-only one.",
"Verified in the real systemd unit, not only from an interactive shell.",
"100% branch coverage on the new and changed modules, with no lint suppressions added.",
"No test touches the real postgres container."
],
"out_of_scope": [
"Removing or replacing the HTTP lookup - it stays first in the chain so the supported path resumes working by itself if Endurain widens the API-key scope allow-list.",
"Exposing a postgres host port or adding a database driver dependency.",
"Patching Endurain's own source or forging scopes in users_api_keys to work around the upload-only allow-list."
],
"verifier": "pre-commit + python_pkg/endurain_import/tests + a real systemctl --user run with journal inspection"
}