Methodology — the work, shown
This page is the site checking itself. At every ingest, the pipeline re-parses the Postman collection and re-runs the audit checks below against the file. Nothing on the reference pages is typed in by hand, so the site cannot silently drift from its source — and if Kindsight ships a fixed collection, these results (and the findings that depend on them) update themselves.
Audit checks — current results
violated
G1 — Auth machinery promised by the description vs present in the file
The collection description instructs readers to use an 'Authentication folder' and collection-level authorization. This check verifies whether either exists in the file.
Raw check output (JSON)
{
"description_mentions_auth_folder": true,
"description_mentions_collection_auth": true,
"has_collection_auth_block": false,
"has_event_scripts": false,
"has_authentication_folder": false,
"defined_variables": [
"baseUrl"
],
"has_client_id_variable": false,
"has_client_secret_variable": false,
"top_level_keys": [
"info",
"item",
"variable"
]
}
violated
G2a — Capacity ranges: low ≤ high
16 of 28 capacity range pairs are inverted (low > high) in the saved examples.
Raw check output (JSON)
{
"pairs": [
{
"endpoint": "Get Profile by DMS ID",
"low": 8967,
"high": 219,
"inverted": true
},
{
"endpoint": "Get Profile by DMS ID",
"low": 4356,
"high": 9889,
"inverted": false
},
{
"endpoint": "Get Profile by DMS ID",
"low": 1938,
"high": 3857,
"inverted": false
},
{
"endpoint": "Get Profile by DMS ID",
"low": 7798,
"high": 269,
"inverted": true
},
{
"endpoint": "List Profiles",
"low": 7692,
"high": 6444,
"inverted": true
},
{
"endpoint": "List Profiles",
"low": 9715,
"high": 5796,
"inverted": true
},
{
"endpoint": "List Profiles",
"low": 7118,
"high": 2930,
"inverted": true
},
{
"endpoint": "List Profiles",
"low": 9568,
"high": 2404,
"inverted": true
},
{
"endpoint": "List Profiles",
"low": 1212,
"high": 3734,
"inverted": false
},
{
"endpoint": "List Profiles",
"low": 7211,
"high": 4210,
"inverted": true
},
{
"endpoint": "List Profiles",
"low": 2155,
"high": 7801,
"inverted": false
},
{
"endpoint": "List Profiles",
"low": 4088,
"high": 8945,
"inverted": false
},
{
"endpoint": "Create a Profile",
"low": 8967,
"high": 219,
"inverted": true
},
{
"endpoint": "Create a Profile",
"low": 4356,
"high": 9889,
"inverted": false
},
{
"endpoint": "Create a Profile",
"low": 1938,
"high": 3857,
"inverted": false
},
{
"endpoint": "Create a Profile",
"low": 7798,
"high": 269,
"inverted": true
},
{
"endpoint": "Get Score Request by ID (Deprecated)",
"low": 9611,
"high": 6367,
"inverted": true
},
{
"endpoint": "Request a Score (Deprecated)",
"low": 9611,
"high": 6367,
"inverted": true
},
{
"endpoint": "Step 5 (Alternate): Retrieve Project Scores (Deprecated)",
"low": 4340,
"high": 5028,
"inverted": false
},
{
"endpoint": "Step 5 (Alternate): Retrieve Project Scores (Deprecated)",
"low": 9416,
"high": 9903,
"inverted": false
},
{
"endpoint": "Step 5: Retrieve Scored Profiles",
"low": 7692,
"high": 6444,
"inverted": true
},
{
"endpoint": "Step 5: Retrieve Scored Profiles",
"low": 9715,
"high": 5796,
"inverted": true
},
{
"endpoint": "Step 5: Retrieve Scored Profiles",
"low": 7118,
"high": 2930,
"inverted": true
},
{
"endpoint": "Step 5: Retrieve Scored Profiles",
"low": 9568,
"high": 2404,
"inverted": true
},
{
"endpoint": "Step 5: Retrieve Scored Profiles",
"low": 1212,
"high": 3734,
"inverted": false
},
{
"endpoint": "Step 5: Retrieve Scored Profiles",
"low": 7211,
"high": 4210,
"inverted": true
},
{
"endpoint": "Step 5: Retrieve Scored Profiles",
"low": 2155,
"high": 7801,
"inverted": false
},
{
"endpoint": "Step 5: Retrieve Scored Profiles",
"low": 4088,
"high": 8945,
"inverted": false
}
],
"inverted_count": 16,
"total": 28
}
violated
G2b — Ages within human range (≤120)
12 of 12 age values in the saved examples are humanly impossible.
Raw check output (JSON)
{
"ages": [
{
"endpoint": "Get Profile by DMS ID",
"age": 4012,
"possible": false
},
{
"endpoint": "Get Profile by DMS ID",
"age": 4501,
"possible": false
},
{
"endpoint": "List Profiles",
"age": 2930,
"possible": false
},
{
"endpoint": "List Profiles",
"age": 7722,
"possible": false
},
{
"endpoint": "List Profiles",
"age": 8540,
"possible": false
},
{
"endpoint": "List Profiles",
"age": 9631,
"possible": false
},
{
"endpoint": "Create a Profile",
"age": 4012,
"possible": false
},
{
"endpoint": "Create a Profile",
"age": 4501,
"possible": false
},
{
"endpoint": "Step 5: Retrieve Scored Profiles",
"age": 2930,
"possible": false
},
{
"endpoint": "Step 5: Retrieve Scored Profiles",
"age": 7722,
"possible": false
},
{
"endpoint": "Step 5: Retrieve Scored Profiles",
"age": 8540,
"possible": false
},
{
"endpoint": "Step 5: Retrieve Scored Profiles",
"age": 9631,
"possible": false
}
],
"impossible_count": 12
}
violated
G2c — Row counts: validRows ≤ totalRows
2 of 4 totalRows/validRows pairs are incoherent.
Raw check output (JSON)
{
"rows": [
{
"endpoint": "Step 4: Get Project Status",
"totalRows": 9130,
"validRows": 4374,
"coherent": true
},
{
"endpoint": "List Projects",
"totalRows": 6141,
"validRows": 7799,
"coherent": false
},
{
"endpoint": "List Projects",
"totalRows": 2198,
"validRows": 6782,
"coherent": false
},
{
"endpoint": "Step 1: Create Screening Project",
"totalRows": 100,
"validRows": 100,
"coherent": true
}
],
"incoherent_count": 2
}
violated
G3 — CSV upload: documented vs specified
'text/csv' is mentioned 2 times in prose, but no request declares a CSV content type and no CSV example or column schema exists in the file.
Raw check output (JSON)
{
"prose_mentions": 2,
"csv_request_present": false
}
violated
G5 — Pagination on array-returning endpoints
4 of 5 array-returning GET endpoints have no pagination parameters.
Raw check output (JSON)
{
"endpoints": [
{
"endpoint": "List Profiles",
"query_params": [
"page",
"itemsPerPage"
],
"paginated": true
},
{
"endpoint": "Step 5 (Alternate): Retrieve Project Scores (Deprecated)",
"query_params": [],
"paginated": false
},
{
"endpoint": "Step 5: Retrieve Scored Profiles",
"query_params": [],
"paginated": false
},
{
"endpoint": "Step 6: Retrieve Project Errors",
"query_params": [],
"paginated": false
},
{
"endpoint": "List Projects",
"query_params": [],
"paginated": false
}
]
}
violated
G6 — Error envelope consistency
2 distinct error body shapes appear across 4xx examples. A client needs to parse defensively.
Raw check output (JSON)
{
"detail+status+title+type": [
"Get Profile by DMS ID (404)",
"Get Score Request by ID (Deprecated) (404)",
"Step 5 (Alternate): Retrieve Project Scores (Deprecated) (404)",
"Step 3: Initiate Project Processing (404)",
"Step 5: Retrieve Scored Profiles (404)",
"Step 4: Get Project Status (404)",
"Step 1: Create Screening Project (400)"
],
"code+message": [
"Create a Profile (400)",
"Request a Score (Deprecated) (400)",
"Step 2: Add Individuals to be screened to Project (404)",
"Step 3: Initiate Project Processing (403)",
"Step 6: Retrieve Project Errors (404)"
]
}
holds
INF1 — Inference: score fields observed within 0–4
All 228 observed score values fall in [0, 4]. This is an inference from sample data, not a documented bound — treat accordingly.
Raw check output (JSON)
{
"count": 228,
"min": 0,
"max": 4
}
observation
OBS1 — Project status values observed (not an exhaustive enumeration)
Status values seen in example bodies vs mentioned only in prose. The collection never enumerates the complete set.
Raw check output (JSON)
{
"in_example_bodies": [
"created",
"in-validation",
"pending-approval"
],
"in_prose_only": [
"processed"
]
}
The pipeline, literally
The two modules below are the entire derivation path from source file to site content. They are rendered from the running code, not copied into this page.
api/management/commands/ingest_collection.py
"""Derive the site's entire API content from the Postman collection.
This command is the provenance boundary: everything under /endpoints/ and
/schema/ comes out of this parse, nothing is hand-entered. It also re-runs the
audit checks (api/audit.py) so every analytical claim is re-verified against
the current file, and records the file's SHA-256 for reader verification.
"""
import hashlib
import json
import re
from django.conf import settings
from django.core.management.base import BaseCommand, CommandError
from django.db import transaction
from api import audit, seeds
from api.models import (
AuditCheck,
Endpoint,
Parameter,
RequestBody,
ResponseExample,
SchemaField,
Source,
)
FAMILY_ORDER = {"profile": 0, "project": 1, "credits": 2, "score-request": 3}
class Command(BaseCommand):
help = "Parse the Postman collection into the database (idempotent)."
def handle(self, *args, **opts):
path = settings.SOURCE_COLLECTION_PATH
if not path.exists():
raise CommandError(f"Source collection not found: {path}")
raw = path.read_bytes()
sha = hashlib.sha256(raw).hexdigest()
col = json.loads(raw)
with transaction.atomic():
self._wipe()
seeds.seed_sources(sha)
seeds.seed_reference_keys()
endpoints = self._ingest_endpoints(col)
self._ingest_schema(endpoints)
self._run_audits(col)
seeds.seed_findings()
seeds.seed_lessons()
self.stdout.write(self.style.SUCCESS(
f"Ingested {Endpoint.objects.count()} endpoints, "
f"{ResponseExample.objects.count()} response examples, "
f"{SchemaField.objects.count()} schema fields, "
f"{AuditCheck.objects.count()} audit checks. "
f"Source sha256={sha[:16]}…"
))
# ------------------------------------------------------------------
def _wipe(self):
for model in (Endpoint, AuditCheck, SchemaField):
model.objects.all().delete()
def _ingest_endpoints(self, col):
created = []
order = [0]
def walk(items, folders):
for it in items:
if "item" in it:
walk(it["item"], folders + [it["name"]])
continue
req = it.get("request", {})
url = req.get("url", {})
raw_url = url.get("raw") if isinstance(url, dict) else url
rel = (raw_url or "").replace("{{baseUrl}}", "")
desc = req.get("description") or ""
name = it["name"]
# Detected, never assumed:
deprecated = "Deprecated" in name or "DEPRECATED" in desc
m_step = re.match(r"\*\*Step (\d+)", desc)
m_use = re.search(r"Please use the `([^`]+)` endpoint instead", desc)
path_only = rel.split("?")[0]
seg = path_only.split("/")[3] if len(path_only.split("/")) > 3 else ""
ep = Endpoint.objects.create(
slug=re.sub(r"[^a-z0-9]+", "-", name.lower()).strip("-"),
name=name,
method=req.get("method", ""),
path=rel,
folder_path=" / ".join(folders),
description=desc,
family=seg,
is_deprecated=deprecated,
use_instead=m_use.group(1) if m_use else "",
lifecycle_step=int(m_step.group(1)) if m_step else None,
order=order[0],
)
order[0] += 1
if isinstance(url, dict):
for v in url.get("variable") or []:
Parameter.objects.create(
endpoint=ep, kind="path", key=v.get("key", ""),
example=str(v.get("value") or ""),
description=v.get("description") or "",
)
for q in url.get("query") or []:
Parameter.objects.create(
endpoint=ep, kind="query", key=q.get("key", ""),
example=str(q.get("value") or ""),
description=q.get("description") or "",
)
for h in req.get("header") or []:
Parameter.objects.create(
endpoint=ep, kind="header", key=h.get("key", ""),
example=str(h.get("value") or ""),
)
body = req.get("body") or {}
if body.get("raw"):
RequestBody.objects.create(
endpoint=ep, raw=body["raw"],
content_type="application/json",
)
for i, resp in enumerate(it.get("response") or []):
ctype = ""
for h in resp.get("header") or []:
if h.get("key") == "Content-Type":
ctype = h.get("value") or ""
ResponseExample.objects.create(
endpoint=ep, name=resp.get("name", ""),
status_code=resp.get("code"),
status_text=resp.get("status", ""),
body=resp.get("body") or "", content_type=ctype, order=i,
)
created.append(ep)
walk(col.get("item", []), [])
# Stable ordering: family, then lifecycle step, then original order.
for ep in created:
ep.order = (
FAMILY_ORDER.get(ep.family, 9) * 100
+ (ep.lifecycle_step or 50)
+ (0 if not ep.is_deprecated else 30)
)
ep.save(update_fields=["order"])
return created
def _ingest_schema(self, endpoints):
"""Flatten each endpoint's first 2xx JSON example into SchemaFields."""
for ep in endpoints:
ex = ep.examples.filter(status_code__lt=300).first()
if not ex or not ex.body.strip().startswith(("{", "[")):
continue
try:
data = json.loads(ex.body)
except json.JSONDecodeError:
continue
if isinstance(data, list):
data = data[0] if data else {}
for path, leaf, depth in _flatten(data):
field, _ = SchemaField.objects.get_or_create(
path=path, defaults={"leaf_type": leaf, "depth": depth}
)
field.endpoints.add(ep)
def _run_audits(self, col):
for result in audit.run_all(col):
AuditCheck.objects.create(**result)
def _flatten(obj, prefix="", depth=0):
out = []
if isinstance(obj, dict):
for k, v in obj.items():
p = f"{prefix}.{k}" if prefix else k
if isinstance(v, dict):
out.append((p, "", depth))
out += _flatten(v, p, depth + 1)
elif isinstance(v, list):
out.append((p, "array", depth))
if v:
out += _flatten(v[0], p + "[]", depth + 1)
else:
out.append((p, type(v).__name__, depth))
return out
api/audit.py
"""Ingest-time verification of every factual claim the site makes.
Each function inspects the raw collection dict and returns a result the site
displays on /methodology/. Nothing here is hardcoded as "true": if Kindsight
ships a fixed collection, these checks flip and the site's claims flip with
them. This is the mechanism behind the site's "show your work" promise.
"""
import re
def check_auth_gap(col):
"""G1: the collection description promises auth machinery the file lacks."""
desc = col.get("info", {}).get("description") or ""
folder_names = _all_folder_names(col.get("item", []))
variables = [v.get("key") for v in col.get("variable", [])]
details = {
"description_mentions_auth_folder": "Authentication folder" in desc,
"description_mentions_collection_auth": "Collection-level authorization" in desc,
"has_collection_auth_block": "auth" in col,
"has_event_scripts": "event" in col,
"has_authentication_folder": any("auth" in f.lower() for f in folder_names),
"defined_variables": variables,
"has_client_id_variable": "clientId" in variables,
"has_client_secret_variable": "clientSecret" in variables,
"top_level_keys": list(col.keys()),
}
gap = (
details["description_mentions_auth_folder"]
and not details["has_authentication_folder"]
and not details["has_collection_auth_block"]
)
return {
"code": "G1",
"title": "Auth machinery promised by the description vs present in the file",
"passed": not gap, # passed=False means the gap exists
"summary": (
"The collection description instructs readers to use an "
"'Authentication folder' and collection-level authorization. "
"This check verifies whether either exists in the file."
),
"details": details,
}
def check_capacity_ranges(col):
"""G2a: capacityRangeLow must not exceed capacityRangeHigh."""
pairs, inverted = [], 0
for name, body in _iter_example_bodies(col):
for lo, hi in re.findall(
r'"capacityRangeLow":\s*(\d+),\s*"capacityRangeHigh":\s*(\d+)', body
):
bad = int(lo) > int(hi)
inverted += bad
pairs.append({"endpoint": name, "low": int(lo), "high": int(hi), "inverted": bad})
return {
"code": "G2a",
"title": "Capacity ranges: low ≤ high",
"passed": inverted == 0,
"summary": f"{inverted} of {len(pairs)} capacity range pairs are inverted "
"(low > high) in the saved examples.",
"details": {"pairs": pairs, "inverted_count": inverted, "total": len(pairs)},
}
def check_ages(col):
"""G2b: ages in sample data must be humanly possible."""
ages = []
for name, body in _iter_example_bodies(col):
for v in re.findall(r'"age":\s*(\d+)', body):
ages.append({"endpoint": name, "age": int(v), "possible": int(v) <= 120})
impossible = sum(1 for a in ages if not a["possible"])
return {
"code": "G2b",
"title": "Ages within human range (≤120)",
"passed": impossible == 0,
"summary": f"{impossible} of {len(ages)} age values in the saved examples "
"are humanly impossible.",
"details": {"ages": ages, "impossible_count": impossible},
}
def check_row_counts(col):
"""G2c: validRows must not exceed totalRows."""
rows = []
for name, body in _iter_example_bodies(col):
for t, v in re.findall(r'"totalRows":\s*(\d+),\s*"validRows":\s*(\d+)', body):
rows.append(
{"endpoint": name, "totalRows": int(t), "validRows": int(v),
"coherent": int(v) <= int(t)}
)
bad = sum(1 for r in rows if not r["coherent"])
return {
"code": "G2c",
"title": "Row counts: validRows ≤ totalRows",
"passed": bad == 0,
"summary": f"{bad} of {len(rows)} totalRows/validRows pairs are incoherent.",
"details": {"rows": rows, "incoherent_count": bad},
}
def check_score_bounds(col):
"""Inference check: every *Score field observed falls in 0–4.
NOTE: this is the one INFERENCE the site makes (docs/ANALYSIS.md §G2). It
is not stated by any source; it is an observed bound across all examples.
"""
fields = (
"capacityScore|affinityScore|propensityScore|rfmScore|recencyScore|"
"frequencyScore|monetaryScore|primaryAffinityScore|secondaryAffinityScore"
)
values = []
for _, body in _iter_example_bodies(col):
values += [int(v) for v in re.findall(rf'"(?:{fields})":\s*(-?\d+)', body)]
in_band = all(0 <= v <= 4 for v in values) if values else None
return {
"code": "INF1",
"title": "Inference: score fields observed within 0–4",
"passed": in_band,
"summary": f"All {len(values)} observed score values fall in "
f"[{min(values)}, {max(values)}]. This is an inference from sample "
"data, not a documented bound — treat accordingly.",
"details": {"count": len(values), "min": min(values), "max": max(values)},
}
def check_statuses(col):
"""Which project status values are evidenced, and how."""
in_bodies = set()
for _, body in _iter_example_bodies(col):
in_bodies.update(re.findall(r'"status":\s*"([a-z-]+)"', body))
prose = set()
for item in _iter_requests(col):
desc = (item.get("request") or {}).get("description") or ""
if "`processed`" in desc:
prose.add("processed")
return {
"code": "OBS1",
"title": "Project status values observed (not an exhaustive enumeration)",
"passed": None, # informational
"summary": "Status values seen in example bodies vs mentioned only in "
"prose. The collection never enumerates the complete set.",
"details": {
"in_example_bodies": sorted(in_bodies),
"in_prose_only": sorted(prose - in_bodies),
},
}
def check_pagination(col):
"""G5: which array-returning GETs carry pagination parameters."""
rows = []
for item in _iter_requests(col):
req = item.get("request") or {}
if req.get("method") != "GET":
continue
first = (item.get("response") or [{}])[0].get("body") or ""
if not first.strip().startswith("["):
continue
url = req.get("url") or {}
q = [x.get("key") for x in (url.get("query") or [])] if isinstance(url, dict) else []
rows.append({"endpoint": item["name"], "query_params": q, "paginated": bool(q)})
unpag = sum(1 for r in rows if not r["paginated"])
return {
"code": "G5",
"title": "Pagination on array-returning endpoints",
"passed": unpag == 0,
"summary": f"{unpag} of {len(rows)} array-returning GET endpoints have no "
"pagination parameters.",
"details": {"endpoints": rows},
}
def check_error_envelopes(col):
"""G6: how many distinct error body shapes appear in 4xx examples."""
shapes = {}
for item in _iter_requests(col):
for resp in item.get("response") or []:
code = resp.get("code") or 0
if 400 <= code < 500 and (resp.get("body") or "").strip().startswith("{"):
keys = tuple(sorted(re.findall(r'"(\w+)":', resp["body"])))
shapes.setdefault(keys, []).append(f"{item['name']} ({code})")
return {
"code": "G6",
"title": "Error envelope consistency",
"passed": len(shapes) <= 1,
"summary": f"{len(shapes)} distinct error body shapes appear across 4xx "
"examples. A client needs to parse defensively.",
"details": {"+".join(k): v for k, v in shapes.items()},
}
def check_csv_schema(col):
"""G3: text/csv is documented but no CSV schema or example exists."""
raw = str(col)
mentions = raw.count("text/csv")
has_csv_header = False
for item in _iter_requests(col):
for h in (item.get("request") or {}).get("header") or []:
if "csv" in str(h.get("value", "")):
has_csv_header = True
return {
"code": "G3",
"title": "CSV upload: documented vs specified",
"passed": has_csv_header,
"summary": f"'text/csv' is mentioned {mentions} times in prose, but no "
"request declares a CSV content type and no CSV example or column "
"schema exists in the file.",
"details": {"prose_mentions": mentions, "csv_request_present": has_csv_header},
}
ALL_CHECKS = [
check_auth_gap,
check_capacity_ranges,
check_ages,
check_row_counts,
check_score_bounds,
check_statuses,
check_pagination,
check_error_envelopes,
check_csv_schema,
]
def run_all(col):
return [fn(col) for fn in ALL_CHECKS]
# -- helpers ----------------------------------------------------------------
def _iter_requests(col):
def walk(items):
for it in items:
if "item" in it:
yield from walk(it["item"])
else:
yield it
yield from walk(col.get("item", []))
def _iter_example_bodies(col):
for item in _iter_requests(col):
for resp in item.get("response") or []:
yield item["name"], resp.get("body") or ""
def _all_folder_names(items):
names = []
for it in items:
if "item" in it:
names.append(it["name"])
names += _all_folder_names(it["item"])
return names
What this site refuses to do
- No invented facts. Where sources are silent (complete
status enumeration, rate limits, CSV columns, affinity vocabulary), the site
says "unknown" instead of guessing. The one inference it makes (scores
bounded 0–4, check
INF1) is labelled as an inference wherever it appears. - No credentials. Try-it panels run simulated or against Postman mock servers only. The proxy refuses all other hosts and strips Authorization headers.
- No internal content. Internal documents are cited by opaque reference key only, enforced at the database layer (details).