FAILURE MAP
← Case archive

FA-74136 / Feature flag rollout bucketing / Open access

Multi-context canonical key: Context kinds follow insertion order · case 01

The same user+org context built in a different order buckets differently.

Verified by executionVariant 1 · 8 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

Kinds are joined in dictionary insertion order.

VERIFIED REPAIR

Join kinds in sorted order.

Unsuccessful approach: Sorting kinds by their key values changes order when the values change.

Case contract

contexts maps kind -> key. Empty input or any empty key -> None. A context containing only the kind "user" is keyed by the bare user key. Otherwise join, over kinds in sorted order, kind + ":" + escaped key with ":", where escaping replaces "%" by "%25" and then ":" by "%3A".

Why this case matters

Canonical context keys feed bucketing and caches; two spellings of one context split its traffic.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(contexts):
    def esc(s):
        return s.replace('%', '%25').replace(':', '%3A')
    if not contexts or any(k == '' for k in contexts.values()):
        return None
    if list(contexts) == ['user']:
        return contexts['user']
    return ':'.join(kind + ':' + esc(contexts[kind]) for kind in contexts)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('percent is escaped before colon', [{'org': 'a:b', 'user': '50%'}], 'org:a%3Ab:user:50%25'),
  ('already escaped text is escaped again', [{'org': 'x%3Ay', 'user': 'bob'}], 'org:x%253Ay:user:bob'),
  ('kinds are sorted regardless of insertion', [{'user': 'bob', 'org': 'acme'}], 'org:acme:user:bob'),
  ('single non-user kind is prefixed', [{'org': 'acme'}], 'org:acme'),
  ('single user kind stays bare with colon', [{'user': 'a:b'}], 'a:b'),
  ('three kinds', [{'device': 'd1', 'app': 'z', 'user': 'bob'}], 'app:z:device:d1:user:bob'),
  ('context sample 1', [{'device': '50%', 'user': 'z', 'app': 'a:b'}], 'app:a%3Ab:device:50%25:user:z'),
  ('context sample 2', [{'device': 'acme', 'user': 'z', 'org': 'z'}], 'device:acme:org:z:user:z')],
 [('already escaped text is escaped again', [{'org': 'x%3Ay', 'user': 'bob'}], 'org:x%253Ay:user:bob'),
  ('kinds are sorted regardless of insertion', [{'user': 'bob', 'org': 'acme'}], 'org:acme:user:bob'),
  ('single non-user kind is prefixed', [{'org': 'acme'}], 'org:acme'),
  ('single user kind stays bare with colon', [{'user': 'a:b'}], 'a:b'),
  ('empty key is invalid', [{'org': 'acme', 'user': ''}], None),
  ('three kinds', [{'device': 'd1', 'app': 'z', 'user': 'bob'}], 'app:z:device:d1:user:bob'),
  ('context sample 7', [{'org': 'a:b', 'device': 'a:b', 'user': 'z'}], 'device:a%3Ab:org:a%3Ab:user:z'),
  ('context sample 11', [{'org': 'x%3Ay', 'app': 'a:b', 'device': 'z'}], 'app:a%3Ab:device:z:org:x%253Ay')],
 [('kinds are sorted regardless of insertion', [{'user': 'bob', 'org': 'acme'}], 'org:acme:user:bob'),
  ('single non-user kind is prefixed', [{'org': 'acme'}], 'org:acme'),
  ('single user kind stays bare with colon', [{'user': 'a:b'}], 'a:b'),
  ('empty key is invalid', [{'org': 'acme', 'user': ''}], None),
  ('empty mapping is invalid', [{}], None),
  ('context sample 11', [{'org': 'x%3Ay', 'app': 'a:b', 'device': 'z'}], 'app:a%3Ab:device:z:org:x%253Ay'),
  ('context sample 31', [{'org': '50%', 'device': 'k:1%'}], 'device:k%3A1%25:org:50%25'),
  ('context sample 32', [{'org': 'z', 'user': 'z', 'app': 'x%3Ay'}], 'app:x%253Ay:org:z:user:z')],
 [('percent is escaped before colon', [{'org': 'a:b', 'user': '50%'}], 'org:a%3Ab:user:50%25'),
  ('single non-user kind is prefixed', [{'org': 'acme'}], 'org:acme'),
  ('single user kind stays bare with colon', [{'user': 'a:b'}], 'a:b'),
  ('empty key is invalid', [{'org': 'acme', 'user': ''}], None),
  ('empty mapping is invalid', [{}], None),
  ('three kinds', [{'device': 'd1', 'app': 'z', 'user': 'bob'}], 'app:z:device:d1:user:bob'),
  ('context sample 16', [{'org': 'x%3Ay', 'app': 'z'}], 'app:z:org:x%253Ay'),
  ('context sample 60', [{'user': 'z', 'device': 'k:1%', 'app': 'acme'}], 'app:acme:device:k%3A1%25:user:z')],
 [('percent is escaped before colon', [{'org': 'a:b', 'user': '50%'}], 'org:a%3Ab:user:50%25'),
  ('single user kind stays bare with colon', [{'user': 'a:b'}], 'a:b'),
  ('empty key is invalid', [{'org': 'acme', 'user': ''}], None),
  ('empty mapping is invalid', [{}], None),
  ('three kinds', [{'device': 'd1', 'app': 'z', 'user': 'bob'}], 'app:z:device:d1:user:bob'),
  ('context sample 7', [{'org': 'a:b', 'device': 'a:b', 'user': 'z'}], 'device:a%3Ab:org:a%3Ab:user:z'),
  ('context sample 21', [{'org': 'x%3Ay', 'app': 'z'}], 'app:z:org:x%253Ay'),
  ('context sample 22', [{'org': 'x%3Ay'}], 'org:x%253Ay')]]
for label, args, expected in fixtures[N - 1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
percent is escaped before colonorg:a%3Ab:user:50%25org:a%3Ab:user:50%25Passed
already escaped text is escaped againorg:x%253Ay:user:boborg:x%253Ay:user:bobPassed
kinds are sorted regardless of insertionuser:bob:org:acmeorg:acme:user:bobFailed
single non-user kind is prefixedorg:acmeorg:acmePassed
single user kind stays bare with colona:ba:bPassed
three kindsdevice:d1:app:z:user:bobapp:z:device:d1:user:bobFailed
context sample 1device:50%25:user:z:app:a%3Abapp:a%3Ab:device:50%25:user:zFailed
context sample 2device:acme:user:z:org:zdevice:acme:org:z:user:zFailed

SHA-256 / 8275bdf65faf74e244d21500957b83ab7ec831986c0a213b8dd9287df57ea75d

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(contexts):
    def esc(s):
        return s.replace('%', '%25').replace(':', '%3A')
    if not contexts or any(k == '' for k in contexts.values()):
        return None
    if list(contexts) == ['user']:
        return contexts['user']
    return ':'.join(kind + ':' + esc(contexts[kind]) for kind in sorted(contexts, key=contexts.get))
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('percent is escaped before colon', [{'org': 'a:b', 'user': '50%'}], 'org:a%3Ab:user:50%25'),
  ('already escaped text is escaped again', [{'org': 'x%3Ay', 'user': 'bob'}], 'org:x%253Ay:user:bob'),
  ('kinds are sorted regardless of insertion', [{'user': 'bob', 'org': 'acme'}], 'org:acme:user:bob'),
  ('single non-user kind is prefixed', [{'org': 'acme'}], 'org:acme'),
  ('single user kind stays bare with colon', [{'user': 'a:b'}], 'a:b'),
  ('three kinds', [{'device': 'd1', 'app': 'z', 'user': 'bob'}], 'app:z:device:d1:user:bob'),
  ('context sample 1', [{'device': '50%', 'user': 'z', 'app': 'a:b'}], 'app:a%3Ab:device:50%25:user:z'),
  ('context sample 2', [{'device': 'acme', 'user': 'z', 'org': 'z'}], 'device:acme:org:z:user:z')],
 [('already escaped text is escaped again', [{'org': 'x%3Ay', 'user': 'bob'}], 'org:x%253Ay:user:bob'),
  ('kinds are sorted regardless of insertion', [{'user': 'bob', 'org': 'acme'}], 'org:acme:user:bob'),
  ('single non-user kind is prefixed', [{'org': 'acme'}], 'org:acme'),
  ('single user kind stays bare with colon', [{'user': 'a:b'}], 'a:b'),
  ('empty key is invalid', [{'org': 'acme', 'user': ''}], None),
  ('three kinds', [{'device': 'd1', 'app': 'z', 'user': 'bob'}], 'app:z:device:d1:user:bob'),
  ('context sample 7', [{'org': 'a:b', 'device': 'a:b', 'user': 'z'}], 'device:a%3Ab:org:a%3Ab:user:z'),
  ('context sample 11', [{'org': 'x%3Ay', 'app': 'a:b', 'device': 'z'}], 'app:a%3Ab:device:z:org:x%253Ay')],
 [('kinds are sorted regardless of insertion', [{'user': 'bob', 'org': 'acme'}], 'org:acme:user:bob'),
  ('single non-user kind is prefixed', [{'org': 'acme'}], 'org:acme'),
  ('single user kind stays bare with colon', [{'user': 'a:b'}], 'a:b'),
  ('empty key is invalid', [{'org': 'acme', 'user': ''}], None),
  ('empty mapping is invalid', [{}], None),
  ('context sample 11', [{'org': 'x%3Ay', 'app': 'a:b', 'device': 'z'}], 'app:a%3Ab:device:z:org:x%253Ay'),
  ('context sample 31', [{'org': '50%', 'device': 'k:1%'}], 'device:k%3A1%25:org:50%25'),
  ('context sample 32', [{'org': 'z', 'user': 'z', 'app': 'x%3Ay'}], 'app:x%253Ay:org:z:user:z')],
 [('percent is escaped before colon', [{'org': 'a:b', 'user': '50%'}], 'org:a%3Ab:user:50%25'),
  ('single non-user kind is prefixed', [{'org': 'acme'}], 'org:acme'),
  ('single user kind stays bare with colon', [{'user': 'a:b'}], 'a:b'),
  ('empty key is invalid', [{'org': 'acme', 'user': ''}], None),
  ('empty mapping is invalid', [{}], None),
  ('three kinds', [{'device': 'd1', 'app': 'z', 'user': 'bob'}], 'app:z:device:d1:user:bob'),
  ('context sample 16', [{'org': 'x%3Ay', 'app': 'z'}], 'app:z:org:x%253Ay'),
  ('context sample 60', [{'user': 'z', 'device': 'k:1%', 'app': 'acme'}], 'app:acme:device:k%3A1%25:user:z')],
 [('percent is escaped before colon', [{'org': 'a:b', 'user': '50%'}], 'org:a%3Ab:user:50%25'),
  ('single user kind stays bare with colon', [{'user': 'a:b'}], 'a:b'),
  ('empty key is invalid', [{'org': 'acme', 'user': ''}], None),
  ('empty mapping is invalid', [{}], None),
  ('three kinds', [{'device': 'd1', 'app': 'z', 'user': 'bob'}], 'app:z:device:d1:user:bob'),
  ('context sample 7', [{'org': 'a:b', 'device': 'a:b', 'user': 'z'}], 'device:a%3Ab:org:a%3Ab:user:z'),
  ('context sample 21', [{'org': 'x%3Ay', 'app': 'z'}], 'app:z:org:x%253Ay'),
  ('context sample 22', [{'org': 'x%3Ay'}], 'org:x%253Ay')]]
for label, args, expected in fixtures[N - 1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
percent is escaped before colonuser:50%25:org:a%3Aborg:a%3Ab:user:50%25Failed
already escaped text is escaped againuser:bob:org:x%253Ayorg:x%253Ay:user:bobFailed
kinds are sorted regardless of insertionorg:acme:user:boborg:acme:user:bobPassed
single non-user kind is prefixedorg:acmeorg:acmePassed
single user kind stays bare with colona:ba:bPassed
three kindsuser:bob:device:d1:app:zapp:z:device:d1:user:bobFailed
context sample 1device:50%25:app:a%3Ab:user:zapp:a%3Ab:device:50%25:user:zFailed
context sample 2device:acme:user:z:org:zdevice:acme:org:z:user:zFailed

SHA-256 / a8b0057d7dc4b7e5911f23d3971b3dc185ed50c4a3ad4bd00bc6e865fb01a238

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(contexts):
    def esc(s):
        return s.replace('%', '%25').replace(':', '%3A')
    if not contexts or any(k == '' for k in contexts.values()):
        return None
    if list(contexts) == ['user']:
        return contexts['user']
    return ':'.join(kind + ':' + esc(contexts[kind]) for kind in sorted(contexts))
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('percent is escaped before colon', [{'org': 'a:b', 'user': '50%'}], 'org:a%3Ab:user:50%25'),
  ('already escaped text is escaped again', [{'org': 'x%3Ay', 'user': 'bob'}], 'org:x%253Ay:user:bob'),
  ('kinds are sorted regardless of insertion', [{'user': 'bob', 'org': 'acme'}], 'org:acme:user:bob'),
  ('single non-user kind is prefixed', [{'org': 'acme'}], 'org:acme'),
  ('single user kind stays bare with colon', [{'user': 'a:b'}], 'a:b'),
  ('three kinds', [{'device': 'd1', 'app': 'z', 'user': 'bob'}], 'app:z:device:d1:user:bob'),
  ('context sample 1', [{'device': '50%', 'user': 'z', 'app': 'a:b'}], 'app:a%3Ab:device:50%25:user:z'),
  ('context sample 2', [{'device': 'acme', 'user': 'z', 'org': 'z'}], 'device:acme:org:z:user:z')],
 [('already escaped text is escaped again', [{'org': 'x%3Ay', 'user': 'bob'}], 'org:x%253Ay:user:bob'),
  ('kinds are sorted regardless of insertion', [{'user': 'bob', 'org': 'acme'}], 'org:acme:user:bob'),
  ('single non-user kind is prefixed', [{'org': 'acme'}], 'org:acme'),
  ('single user kind stays bare with colon', [{'user': 'a:b'}], 'a:b'),
  ('empty key is invalid', [{'org': 'acme', 'user': ''}], None),
  ('three kinds', [{'device': 'd1', 'app': 'z', 'user': 'bob'}], 'app:z:device:d1:user:bob'),
  ('context sample 7', [{'org': 'a:b', 'device': 'a:b', 'user': 'z'}], 'device:a%3Ab:org:a%3Ab:user:z'),
  ('context sample 11', [{'org': 'x%3Ay', 'app': 'a:b', 'device': 'z'}], 'app:a%3Ab:device:z:org:x%253Ay')],
 [('kinds are sorted regardless of insertion', [{'user': 'bob', 'org': 'acme'}], 'org:acme:user:bob'),
  ('single non-user kind is prefixed', [{'org': 'acme'}], 'org:acme'),
  ('single user kind stays bare with colon', [{'user': 'a:b'}], 'a:b'),
  ('empty key is invalid', [{'org': 'acme', 'user': ''}], None),
  ('empty mapping is invalid', [{}], None),
  ('context sample 11', [{'org': 'x%3Ay', 'app': 'a:b', 'device': 'z'}], 'app:a%3Ab:device:z:org:x%253Ay'),
  ('context sample 31', [{'org': '50%', 'device': 'k:1%'}], 'device:k%3A1%25:org:50%25'),
  ('context sample 32', [{'org': 'z', 'user': 'z', 'app': 'x%3Ay'}], 'app:x%253Ay:org:z:user:z')],
 [('percent is escaped before colon', [{'org': 'a:b', 'user': '50%'}], 'org:a%3Ab:user:50%25'),
  ('single non-user kind is prefixed', [{'org': 'acme'}], 'org:acme'),
  ('single user kind stays bare with colon', [{'user': 'a:b'}], 'a:b'),
  ('empty key is invalid', [{'org': 'acme', 'user': ''}], None),
  ('empty mapping is invalid', [{}], None),
  ('three kinds', [{'device': 'd1', 'app': 'z', 'user': 'bob'}], 'app:z:device:d1:user:bob'),
  ('context sample 16', [{'org': 'x%3Ay', 'app': 'z'}], 'app:z:org:x%253Ay'),
  ('context sample 60', [{'user': 'z', 'device': 'k:1%', 'app': 'acme'}], 'app:acme:device:k%3A1%25:user:z')],
 [('percent is escaped before colon', [{'org': 'a:b', 'user': '50%'}], 'org:a%3Ab:user:50%25'),
  ('single user kind stays bare with colon', [{'user': 'a:b'}], 'a:b'),
  ('empty key is invalid', [{'org': 'acme', 'user': ''}], None),
  ('empty mapping is invalid', [{}], None),
  ('three kinds', [{'device': 'd1', 'app': 'z', 'user': 'bob'}], 'app:z:device:d1:user:bob'),
  ('context sample 7', [{'org': 'a:b', 'device': 'a:b', 'user': 'z'}], 'device:a%3Ab:org:a%3Ab:user:z'),
  ('context sample 21', [{'org': 'x%3Ay', 'app': 'z'}], 'app:z:org:x%253Ay'),
  ('context sample 22', [{'org': 'x%3Ay'}], 'org:x%253Ay')]]
for label, args, expected in fixtures[N - 1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
percent is escaped before colonorg:a%3Ab:user:50%25org:a%3Ab:user:50%25Passed
already escaped text is escaped againorg:x%253Ay:user:boborg:x%253Ay:user:bobPassed
kinds are sorted regardless of insertionorg:acme:user:boborg:acme:user:bobPassed
single non-user kind is prefixedorg:acmeorg:acmePassed
single user kind stays bare with colona:ba:bPassed
three kindsapp:z:device:d1:user:bobapp:z:device:d1:user:bobPassed
context sample 1app:a%3Ab:device:50%25:user:zapp:a%3Ab:device:50%25:user:zPassed
context sample 2device:acme:org:z:user:zdevice:acme:org:z:user:zPassed

SHA-256 / 9e0054dd7f0f0cc43c5c3cb71fe9bc59b80b1237716a9309057c1af40f1abfe9

Verification & scope

A deterministic toy flag-evaluation model with a stipulated contract; it does not reproduce any vendor SDK byte for byte. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.

Observations recorded using Python 3.12.14 at 2026-09-29T14:48:53.902012+00:00.

Case digest / d6e5fff303c27721edc09570ec12180d78f3b0169a69b94bf2f5544a812c8151