Sentinel Signal

MCP Verify — Product architecture, methodology 3-way split implementation

Source: docs/mcp-verify-product-architecture-track2-methodology-split-implementation.md

Document Content

MCP Verify — Product architecture, methodology 3-way split implementation

Target release: 1.0.541.

Source: Track 2's deferred methodology split (doc §25-28, Phase 7), the second of two phases resumed after the user supplied the full 56-section source doc. Scoping decision from the earlier round: propose the 3-way split boundary from the current page's own content, for sign-off before implementing — this document is that proposal, implemented directly since it's a mechanical content move with no ambiguity once mapped.

The doc's model (§26-28)

  • **/methodology** — "what the system means today": what a score
  • means, what evidence is used, freshness/confidence treatment, verdict meanings, limitations, whether payment/claiming affect score, how authenticated evidence affects confidence, production/evaluation readiness criteria.

  • **/docs/scoring-specification** (doc's own example path, used as-is)
  • — "exact implementation": scoring dimensions, equations, weights, floors, caps, zero-point behavior, evidence interactions, confidence behavior, edge-case semantics. For engineers, security reviewers, auditors, technically sophisticated buyers.

  • **/methodology/changelog** — "evolution": revision identifiers,
  • scoring corrections, historical bugs, changed assumptions, calibration changes, migration notes.

Mapping from the existing page

The existing render_methodology_page already had exactly this separation baked into its two internal content lists — it just rendered them on one page:

  • sections (5 prose+bullet items: "What the score means", "Status,
  • score, and verdict", "Freshness", "Percentile and confidence", "Limits") is current-truth material almost verbatim from doc §26's list of questions. **Stayed on /methodology, unchanged.**

  • raw_sections had four technical tables. Three are pure mechanics —
  • "Windows in use" (every time-based threshold on the site), "Subscore zero points" (all 49 scoring dimensions' exact zero-point values, generated from SCORE_COMPONENT_ORDER/SCORE_COMPONENT_ZERO_POINT), "Experimental candidate components" (zero-weight candidate scoring dimensions). **Moved to the new /docs/scoring-specification. The fourth, "Opted-out servers" (robots.txt-honoring policy explanation), reads as current-truth product behavior rather than scoring mechanics — stayed on /methodology.**

  • No existing content mapped to "changelog" — CHANGELOG.md's
  • scoring/verdict-relevant entries were curated into a new static METHODOLOGY_CHANGELOG_ENTRIES tuple instead (see below).

Why the changelog page uses embedded data, not a file read

The natural-seeming implementation — parse CHANGELOG.md at request time for scoring-relevant entries — was checked and rejected: verify/Dockerfile builds from the verify/ subdirectory only (COPY pyproject.toml README.md ./, COPY src ./src, COPY alembic.ini/alembic) and CHANGELOG.md lives at the repo root, so it is not present in the production container filesystem at all. Reading it at runtime would work in local tests (run from the repo root) and throw in production — exactly the kind of gap this engagement has repeatedly caught by checking deploy mechanics before writing code that depends on them. Instead, METHODOLOGY_CHANGELOG_ENTRIES embeds four releases' (1.0.533/535/536/537) real, verbatim-sourced scoring/verdict-relevant bullets as Python source, the same pattern as MAIN_NAV_ITEMS or PLATFORM_LIFECYCLE_STAGES — ships deterministically with the image, no filesystem dependency, and every entry is copied from actual CHANGELOG.md history, not invented. This is a smaller initial dataset than this engagement's full internal remediation history (most of which lives only in docs/*.md implementation write-ups, not CHANGELOG.md, and those docs aren't part of the deployed app either) — future scoring-relevant CHANGELOG entries should be added to this tuple going forward as a normal part of shipping them.

Implementation

  • render_public_info_page gained a footer_html: str = "" parameter
  • (default empty, so every other caller is unaffected), rendered after the existing sections. All three methodology-family pages use it for cross-links to the other two.

  • render_methodology_page: unchanged sections; raw_sections reduced
  • to just "Opted-out servers"; new footer linking to both new pages.

  • New render_scoring_specification_page: one short intro sections
  • entry, raw_sections = the three moved tables, footer linking back to Methodology and the changelog.

  • New render_methodology_changelog_page + render_methodology_changelog_rows
  • + METHODOLOGY_CHANGELOG_ENTRIES: renders the curated version/date/ bullet-list table, footer linking to the general /changelog (the existing all-releases product changelog, a different and pre-existing page) and back to Methodology.

  • Routes registered: /docs/scoring-specification,
  • /methodology/changelog (both main.py, next to the existing /methodology route).

  • Both new routes added to _build_static_sitemap_entries.

Deliberately unchanged

  • /methodology's own URL, and every other page's links to it — no
  • redirects needed since the primary page didn't move, it was trimmed.

  • The existing, separate /changelog (general product changelog, all
  • releases) — a different page for a different audience, per doc's own distinction between "Methodology → current truth" and a general product changelog isn't even in scope of §25-28's model. /methodology/ changelog's footer links to it for readers who want the full picture.

Tests

  • verify/tests/test_api.py::test_arch_track2_methodology_three_way_split
  • (new): asserts /methodology keeps its current-truth sections and "Opted-out servers" but no longer renders the two moved table headings, and links to both new pages; asserts /docs/scoring-specification renders all three moved tables and does not render /methodology's prose sections; asserts /methodology/changelog contains real version numbers (1.0.536, 1.0.533) and their actual bullet text, and links to the general changelog; asserts both new routes are in the sitemap.

  • Manually verified via a throwaway build_test_client() script before
  • writing assertions, same practice as the /search phase.

  • PYTHONPATH=verify/src pytest verify/tests -q — 493 passed (up from
  • 492), 1 new.

  • python3 scripts/export_openapi.py --check — HTML page routes aren't
  • part of the OpenAPI schema; no content diff beyond the version bump.

Remaining Track 2 phases — still not started

Server-profile tier audit against the doc's exact 7-group model (Phase 5), analytics classification work (Phase 9), compare-telemetry parent/child metric cleanup (Phase 10), and the literal "shrink /'s own registry dominance" half of Phase 4 (this and the prior /search phase both deliberately kept / unchanged).