Stratify
More

Graphify Findings Cleanup

docs/plans/graphify-findings-cleanup.md

Source updated 03. Aug. 2026

Plan: graphify-findings-cleanup

  • PRD: n/a (findings from /graphify knowledge-graph audit, not a PRD-tracked feature) · Issue: n/a
  • Risk class: Low
  • Status: Approved <2026-07-15> — independent review (fresh context) found A3 was

wrong-direction and A1's seed.sql line was a mechanical overclaim; both corrected below, plus 5 same-class 🟡 findings the original audit missed, fixed in the same PR.

Approach

/graphify update surfaced 13 AMBIGUOUS edges + doc-drift patterns. Findings were re-verified against origin/main directly (not the stale local checkout the graph was built from — see Open Questions) before inclusion here; one candidate finding (OpenAPI MandateId enum still listing inverse-cramer/dax-mdax-smi-directors) turned out to be a false positive already fixed in PR #46 and is excluded.

Two tiers:

  • Tier A (this plan, executed directly): unambiguous doc/schema drift — the

correct answer is derivable from current code, no editorial judgment needed.

  • Tier B (listed, not executed): genuine judgment calls — compliance content,

business/content decisions, file-deletion calls — held for explicit direction.

Affected files & modules

A1 — Mandate count stale throughout README.md README.md has a whole section header ### The five mandates plus 8 more "five"/"5 mandate(s)" references. Current catalog (packages/shared/src/mandates.ts) has seven, unchanged in count since the mid-session swap (which replaced 2 of 7, not reduced the count). Rewrite the section + all count references to seven, listing all seven mandate names.

A2 — `docs/compliance/strategy-playbooks/README.md` — full rewrite, not word-swap

  • Mandate table still lists Inverse Cramer and Insider DACH (removed in #46);

missing Liquid Private Equity and Deutsche Credit (added in #46).

  • Ingest-script line references pnpm ingest:inverse-cramer / pnpm ingest:dax-mdax-smi

— both removed from package.json in #46 (dead commands).

  • Cron line says "(Vercel)" and lists the same two dead routes — crons moved to

Hetzner /etc/cron.d/stratify per docs/runbooks/hetzner-cutover.md / hetzner-power-schedule.md, and the routes themselves no longer exist.

A3 — REVERTED, moved to Tier B. Original plan: tighten Signal.mandateNumber maximum: 54 to match the 4-value MandateId enum. Wrong — independent review caught that mandates.ts numbers all 7 mandates 1-7, and the live partner route (apps/web/app/api/v1/mandates/[mandateId]/signals/route.ts) validates via isMandateId() against all 7, not just the OpenAPI's 4-value enum. Tightening to 4 would have made a real, partner-reachable value (5, Europe Defense) newly non-compliant with the spec — backwards from the actual drift, which is that the OpenAPI MandateId enum (and Signal.mandateNumber's bound) may need _widening_ to 7, not narrowing to 4. Whether the partner API is meant to expose all 7 mandates or stay deliberately scoped to 4 is a product/API-contract decision, not mine to guess — reverted both openapi/stratify-api.yaml and the parallel hand-written zod bound in packages/shared/src/webhook-events.ts back to their original maximum: 5 (itself also wrong either way, but not a regression I'm introducing). Moved to Tier B below.

A4 — `docs/jenkins.md` + `docs/runbooks/pre-launch-quality.md` — false "GH Actions disabled" claim Both state GitHub Actions is "intentionally disabled." .github/workflows/dos-ci.yml (build/lint/tests/verify/secret-scan on every PR) and .github/workflows/deploy.yml (auto-deploy on merge, added PR #51 — never once succeeded, see the deploy runbook) gate main right now — this claim was already false before #51 and is more false after it. Correct both docs to state GitHub Actions runs CI + deploy; note Jenkins' exact current relationship to that (parallel gate vs. vestigial) is unverified — don't assert Jenkins is _disabled_ without evidence, just fix the demonstrably false part.

Tier A2 — additional same-class fixes made after independent review

The A1/A2 audit wasn't as thorough as claimed; independent review caught 5 more instances of the exact same mandate-swap-not-propagated bug, all mechanically fixed in the same PR (no judgment calls):

  • README.md:193 — "Seven mandates seeded from mandates.ts" was itself a

mechanical overclaim (I swapped "Five"→"Seven" without opening the file): supabase/seed.sql only seeds 3 of 7 mandates directly. Corrected to state that precisely, crediting migrations 0016/0019/0022/0023 for the rest.

  • README.md:165 — "Four Vercel cron drainers (every 2 min)" was also stale

(same Vercel→Hetzner drift as A2, just a location the original sweep missed) — the real Hetzner crontab runs these once daily at 06:00 UTC. Fixed, plus a collateral indentation regression the first pass's reformatting introduced.

  • docs/README.md — the public team-handbook mandate table had the identical

stale Inverse Cramer/Insider DACH rows as A2's file. Fixed with the same "_not yet written_" convention for the two undocumented playbooks.

  • docs/product-design.md — rows 2 and 4 of the flagship mandate-narrative

table still described Inverse Cramer/Insider DACH even though the doc's own header prose already said "sieben Strategie-Mandate." Replaced with the exact mandates.ts thesis/universe text for Liquid Private Equity/Deutsche Credit.

  • apps/web/e2e/landing.spec.ts — a test literally named `'renders the seven

mandates' asserted getByText('Inverse Cramer'), which no longer renders anywhere. Swapped to 'Liquid Private Equity'`.

  • docs/api/quickstart.md — every example in the file used a mandate id

(koalitionsmix-eu) from an even older, pre-Inverse-Cramer product generation that would 404 against the real API today. Swapped every occurrence to pelosi-tracker-plus with matching name/thesis/universe fields; also fixed 3 "five mandates" count references.

  • docs/compliance/strategy-playbooks/README.md:10 — Deutsche Credit's

benchmark was missing the trailing "Index" present in backtest.ts's MANDATE_BENCHMARK. One-word fix.

Tier B — not executed, needs your call

  • `Signal.mandateNumber` bound (openapi/stratify-api.yaml,

packages/shared/src/webhook-events.ts) — currently maximum: 5, matching neither the OpenAPI's own 4-value MandateId enum nor the real 7-mandate catalog isMandateId() validates against. Needs a decision: is the partner API meant to expose all 7 mandates (widen enum + bound to 7), or deliberately scoped to 4 (bound to 4, and the scoping should be documented as intentional rather than left implicit)? Not currently causing a live bug — the zod schema isn't enforced anywhere in the actual webhook-delivery code path — but the spec is wrong either way.

  • scripts/ingest/koalitionsmix-eu.ts, scripts/ingest/transatlantischer-wahlkreis.ts

— dead ingest scripts for mandates removed even before the Inverse Cramer/Insider DACH generation, unreferenced by any package.json script. Same "delete or keep as historical record" call as the other orphaned artifacts below.

  • docs/compliance/signalgeber-classification.md: "FMA" used for what look like two

different regulators (Liechtenstein vs. probably Austria) across different compliance docs — legal-content question, not mine to resolve.

  • docs/closed-beta/partner-runbook.md vs docs/api/phase-c-endpoints.md: runbook

treats a Phase-C webhook as testable in sandbox; the endpoints doc says it 404s pre-license. docs/compliance/closed-beta-sign-off-checklist.md also cites two different mechanisms for the "propagated trade <60s" criterion. Needs whoever owns closed-beta ops to say which is current.

  • docs/Stratify Design System/export/src/*.jsx (6 files) + the bundled

export/stratify-clickdummy.html are byte-identical duplicates of prototype/*. Delete as redundant, or keep as an intentional "handoff export" artifact?

  • Pitch-deck sprawl: docs/stratify_pitch_deck_v1.md (2 copies incl. one under

Design System/uploads/), docs/pitch-deck/stratify-preseed-v2.html, -v3.html, -v3.pdf, and an unversioned .pdf matching v3 content. No canonical pointer. Consolidate/archive, or intentional historical record?

  • apps/web/content/insights/{digitaler-souveraenitaets-stack-thesis,koalitionsmix-eu-q2-2026}.md

reference "mandates" not in the 7-entry catalog — likely just editorial blog pieces mislabeled as mandates by the extraction, not a real catalog gap, but worth a 10-second confirm.

Test strategy

  • A1, A2, A4, and the Tier A2 additional fixes: doc-only, no test surface except

apps/web/e2e/landing.spec.ts (assertion text updated to match what actually renders — not run as part of the standard gate, Playwright is a separate test:e2e command).

  • A3: reverted, not shipped — see Tier B.
  • Full gate: pnpm run lint && pnpm run typecheck && pnpm test — green (shared

44, web 69, mobile 19).

Migration / flag implications

  • Flag: n/a
  • Schema: n/a — the one schema-adjacent change (A3, the mandateNumber bound)

was reverted after review rather than shipped in either direction.

Open questions

  • The graph this plan is based on was built against a stale local checkout

(/Users/tobiastemmen/thoughtful-toby/stratify on feature/test-t4-ci, 11 commits behind origin/main) — every Tier A finding above was individually re-verified against origin/main directly, so this plan is sound, but the underlying graphify-out/graph.json in that directory should not be trusted for further "is X still true on main" questions without the same re-check.