test_landing_k12.py
python
sha256:0e9549ec7b463911bc08b7d586dc320b1ac9b1f5c943ee7e3865dcc6cb0f6f83
chore(governance): sync handover+roadmap to 84db8c8 (drift:…
Human
2 days ago
| 1 | """Unit tests for landing manifest and Landing + access clarity contract (§LAC.12).""" |
| 2 | |
| 3 | from __future__ import annotations |
| 4 | |
| 5 | from pathlib import Path |
| 6 | |
| 7 | import pytest |
| 8 | import yaml |
| 9 | |
| 10 | from tools.app.engine import handle_health |
| 11 | from tools.landing.schema import load_manifest |
| 12 | from tools.landing.validate import ( |
| 13 | FROZEN_PRIMARY_DOWNLOAD_HREF, |
| 14 | LAC_SECTION_IDS, |
| 15 | validate_landing, |
| 16 | ) |
| 17 | |
| 18 | KIT_ROOT = Path(__file__).resolve().parents[2] |
| 19 | MANIFEST = KIT_ROOT / "docs" / "landing" / "manifest.yaml" |
| 20 | INDEX = KIT_ROOT / "docs" / "landing" / "index.html" |
| 21 | |
| 22 | |
| 23 | def test_manifest_loads_version_one() -> None: |
| 24 | manifest = load_manifest(MANIFEST) |
| 25 | assert manifest.version == 1 |
| 26 | assert manifest.license == "MIT" |
| 27 | |
| 28 | |
| 29 | def test_manifest_section_ids_match_lac_contract() -> None: |
| 30 | """Public IA contract — visitor clarity pass (amends LAC §LAC.3.1).""" |
| 31 | manifest = load_manifest(MANIFEST) |
| 32 | assert manifest.section_ids == LAC_SECTION_IDS |
| 33 | assert len(manifest.section_ids) == 9 |
| 34 | assert "how-it-works" in manifest.section_ids |
| 35 | assert "kit-basics" in manifest.section_ids |
| 36 | assert "musehub" in manifest.section_ids |
| 37 | assert "living-docs" not in manifest.section_ids |
| 38 | assert "funnel" not in manifest.section_ids |
| 39 | |
| 40 | |
| 41 | def test_primary_download_href_equals_frozen_dmg() -> None: |
| 42 | manifest = load_manifest(MANIFEST) |
| 43 | html = INDEX.read_text(encoding="utf-8") |
| 44 | assert manifest.primary_download_href == FROZEN_PRIMARY_DOWNLOAD_HREF |
| 45 | assert FROZEN_PRIMARY_DOWNLOAD_HREF in html |
| 46 | assert 'id="cta-download-mac"' in html |
| 47 | assert "Download Mac console (Apple Silicon)" in html |
| 48 | assert "via the Download link above" in html |
| 49 | assert "via the button above" not in html |
| 50 | |
| 51 | |
| 52 | def test_forbidden_strings_absent_on_landing() -> None: |
| 53 | html = INDEX.read_text(encoding="utf-8") |
| 54 | for phrase in ("Sign up", "Create account", "executes tasks"): |
| 55 | assert phrase not in html |
| 56 | assert "mint session_credential" not in html.lower() |
| 57 | assert "mint csrf" not in html.lower() |
| 58 | assert "mints session_credential" not in html.lower() |
| 59 | |
| 60 | |
| 61 | def test_no_done_todo_wip_status_table_on_main_landing() -> None: |
| 62 | html = INDEX.read_text(encoding="utf-8") |
| 63 | assert 'id="roadmap-public"' not in html |
| 64 | assert "K9b DONE" not in html |
| 65 | assert ">DONE<" not in html |
| 66 | assert ">TODO<" not in html |
| 67 | assert ">WIP<" not in html |
| 68 | |
| 69 | |
| 70 | def test_four_diagram_paths_referenced() -> None: |
| 71 | html = INDEX.read_text(encoding="utf-8") |
| 72 | for name in ("lanes.svg", "regimes.svg", "layers.svg", "kit-consumer.svg"): |
| 73 | assert f"assets/diagrams/{name}" in html |
| 74 | assert (KIT_ROOT / "docs" / "landing" / "assets" / "diagrams" / name).is_file() |
| 75 | |
| 76 | |
| 77 | def test_health_result_schema_documents_repo_root() -> None: |
| 78 | """Narrow Q0 additive: health success result includes absolute repo_root (§LAC.6.3).""" |
| 79 | envelope = handle_health(port=8765, bind="127.0.0.1", repo_root=KIT_ROOT) |
| 80 | assert envelope.ok is True |
| 81 | assert envelope.result is not None |
| 82 | assert set(envelope.result) >= {"status", "port", "bind", "repo_root"} |
| 83 | assert envelope.result["repo_root"] == str(KIT_ROOT.resolve()) |
| 84 | assert envelope.result["status"] == "ok" |
| 85 | assert envelope.result["port"] == 8765 |
| 86 | assert envelope.result["bind"] == "127.0.0.1" |
| 87 | |
| 88 | |
| 89 | def test_manifest_persona_ids_a_through_e() -> None: |
| 90 | manifest = load_manifest(MANIFEST) |
| 91 | assert manifest.persona_ids == ("A", "B", "C", "D", "E") |
| 92 | |
| 93 | |
| 94 | def test_manifest_status_badges_frozen_enum() -> None: |
| 95 | manifest = load_manifest(MANIFEST) |
| 96 | assert manifest.status_badges == frozenset({"dogfood", "reference", "aspirational"}) |
| 97 | |
| 98 | |
| 99 | def test_manifest_rejects_bad_version(tmp_path: Path) -> None: |
| 100 | bad = tmp_path / "manifest.yaml" |
| 101 | bad.write_text(yaml.dump({"version": 99, "license": "MIT"}), encoding="utf-8") |
| 102 | with pytest.raises(ValueError, match="unsupported manifest version"): |
| 103 | load_manifest(bad) |
| 104 | |
| 105 | |
| 106 | def test_license_file_references_mit() -> None: |
| 107 | text = (KIT_ROOT / "LICENSE").read_text(encoding="utf-8") |
| 108 | assert "MIT License" in text |
| 109 | assert "Copyright 2026 Overseer Kit contributors" in text |
| 110 | assert "Apache License" not in text |
| 111 | |
| 112 | |
| 113 | def test_pyproject_license_matches_manifest() -> None: |
| 114 | pyproject = (KIT_ROOT / "pyproject.toml").read_text(encoding="utf-8") |
| 115 | manifest = load_manifest(MANIFEST) |
| 116 | assert 'license = { text = "MIT" }' in pyproject |
| 117 | assert manifest.license == "MIT" |
| 118 | |
| 119 | |
| 120 | def test_validate_missing_manifest_fails(tmp_path: Path) -> None: |
| 121 | result = validate_landing(tmp_path) |
| 122 | assert not result.ok |
| 123 | assert any(e.startswith("manifest_parse:") for e in result.errors) |
| 124 | |
| 125 | |
| 126 | def test_readme_and_runbook_carry_open_local_console_playbook() -> None: |
| 127 | readme = (KIT_ROOT / "README.md").read_text(encoding="utf-8") |
| 128 | runbook = (KIT_ROOT / "docs" / "TRACK-Q-DESKTOP-OPERATOR-RUNBOOK.md").read_text( |
| 129 | encoding="utf-8" |
| 130 | ) |
| 131 | assert "Open the local console" in readme |
| 132 | assert "Open the local console" in runbook |
| 133 | assert "OVERSEER_REPO_ROOT" in readme |
| 134 | assert FROZEN_PRIMARY_DOWNLOAD_HREF in readme |
| 135 | |
| 136 | |
| 137 | def test_main_landing_has_no_personal_product_doors() -> None: |
| 138 | html = INDEX.read_text(encoding="utf-8") |
| 139 | for phrase in ("Knowtation", "Scooling", "VideoFactory", "musehub.ai"): |
| 140 | assert phrase not in html |
| 141 | assert 'id="theme-toggle"' in html |
| 142 | assert 'id="how-it-works"' in html |
| 143 | assert "logo-mark" in html |
| 144 | assert "brand-name" in html |
| 145 | assert "Overseer Kit" in html |
| 146 | assert "Honesty for your agents" in html |
| 147 | assert "logo-mark-hero" not in html |
| 148 | assert "hero-brand" not in html |
| 149 | assert "Lock the plan" in html |
| 150 | assert "Keep docs truthful" in html |
| 151 | assert "Spend models wisely" in html |
| 152 | assert "Close clean" in html |
| 153 | assert "paste-ready prompt" not in html.lower() |
| 154 | assert "model-routing.yaml" not in html |
| 155 | assert "governance-sync" not in html |
| 156 | assert "cta-honesty" not in html.split('id="hero"')[1].split('id="problem"')[0] |
| 157 | assert "hero-terminal" in html |
| 158 | assert "ok check-ok" in html |
| 159 | assert 'src="assets/diagrams/honesty-loop.svg"' in html |
| 160 | assert "btn-primary" not in html.split('id="hero"')[1].split('id="problem"')[0] |
| 161 | assert 'href="docs.html">Docs</a>' in html |
| 162 | assert (KIT_ROOT / "docs" / "landing" / "docs.html").is_file() |
| 163 | assert "https://github.com/aaronrene/overseer-kit#readme" not in html |
| 164 | assert 'href="assets/favicon.ico"' in html |
| 165 | assert (KIT_ROOT / "docs" / "landing" / "assets" / "favicon.ico").is_file() |
| 166 | assert (KIT_ROOT / "docs" / "landing" / "assets" / "ok-mark-1024.png").is_file() |
| 167 | assert 'href="http://127.0.0.1:8765/"' in html |
| 168 | assert "id=\"local-console-loopback\"" in html or 'id="local-console-loopback"' in html |
| 169 | assert "ok hosted-dashboard" not in html |
| 170 | assert "../../README.md" not in html |
| 171 | assert "../CONSUMER-ADAPTER-PATTERN.md" not in html |
| 172 | |
| 173 | |
| 174 | def test_musehub_band_after_console_access() -> None: |
| 175 | html = INDEX.read_text(encoding="utf-8") |
| 176 | assert 'id="musehub"' in html |
| 177 | assert "Optional deepen with MuseHub" in html |
| 178 | assert "assets/musehub-logo.svg" in html |
| 179 | assert "musehub.ai" not in html |
| 180 | assert "K7-DOGFOOD-OPERATOR-RUNBOOK" not in html |
| 181 | assert "ok init --regime muse+git-mirror" in html |
| 182 | logo = (KIT_ROOT / "docs" / "landing" / "assets" / "musehub-logo.svg").read_text( |
| 183 | encoding="utf-8" |
| 184 | ) |
| 185 | assert "#6EA0F3" in logo |
| 186 | hero = html.index('id="hero"') |
| 187 | kit_basics = html.index('id="kit-basics"') |
| 188 | problem = html.index('id="problem"') |
| 189 | console = html.index('id="console-access"') |
| 190 | muse = html.index('id="musehub"') |
| 191 | next_steps = html.index('id="next-steps"') |
| 192 | assert hero < kit_basics < problem < console < muse < next_steps |
| 193 | kit_block = html.split('id="kit-basics"')[1].split('id="problem"')[0] |
| 194 | assert 'id="mechanical-check"' in kit_block |
| 195 | assert "Mechanical check" in kit_block |
| 196 | assert "your bar, on-disk evidence" in kit_block |
| 197 | assert "against that bar" in kit_block |
| 198 | assert "Customize the checks" in kit_block |
| 199 | assert "assets/diagrams/mechanical-check.svg" in kit_block |
| 200 | assert kit_block.index("mechanical-check") < kit_block.index("Roadmap · Handover") |
| 201 | assert "mech-check-details" in kit_block |
| 202 | assert "Technical detail" in kit_block |
| 203 | assert "ok verify-step --through current" in kit_block |
| 204 | assert "checkpoints.enabled: true" in kit_block |
| 205 | assert "ok review --freeze" in kit_block |
| 206 | assert "Check OK" in kit_block |
| 207 | assert "Any work" in kit_block |
| 208 | assert "Same honesty loop" in kit_block |
| 209 | assert "Anywhere you work" in kit_block |
| 210 | assert "Lanes" in kit_block |
| 211 | |
| 212 | |
| 213 | def test_theme_defaults_dark_not_os_preference() -> None: |
| 214 | js = (KIT_ROOT / "docs" / "landing" / "assets" / "theme.js").read_text(encoding="utf-8") |
| 215 | assert "matchMedia" not in js |
| 216 | assert 'return "dark"' in js |
| 217 | |
| 218 | |
| 219 | def test_landing_and_console_footers_say_mit() -> None: |
| 220 | landing = INDEX.read_text(encoding="utf-8") |
| 221 | scenarios = ( |
| 222 | KIT_ROOT / "docs" / "landing" / "scenarios" / "index.html" |
| 223 | ).read_text(encoding="utf-8") |
| 224 | console = (KIT_ROOT / "tools" / "app" / "static" / "index.html").read_text( |
| 225 | encoding="utf-8" |
| 226 | ) |
| 227 | assert ">MIT</a>" in landing or ">MIT open source</a>" in landing |
| 228 | assert ">MIT</a>" in scenarios or "MIT" in scenarios |
| 229 | assert "Open source — MIT" in console |
| 230 | footer = landing.split('class="site-footer"')[1] |
| 231 | assert "Hosting" not in footer |
| 232 | assert "footer-tagline" in landing |
| 233 | assert "🆗 Overseer Kit — portable governance for AI-assisted development." in footer |
| 234 | assert "🆗 Overseer Kit — portable governance for AI-assisted development." in scenarios |
| 235 | assert "Apache-2.0" not in landing |
| 236 | assert "Apache-2.0" not in scenarios |
| 237 | assert "Apache-2.0" not in console |
| 238 | |
| 239 | |
| 240 | def test_landing_funnel_steps_live_inside_next_steps() -> None: |
| 241 | html = INDEX.read_text(encoding="utf-8") |
| 242 | assert 'id="funnel"' in html |
| 243 | assert 'id="funnel-github"' in html |
| 244 | assert 'id="funnel-kit"' in html |
| 245 | assert 'id="funnel-musehub"' in html |
| 246 | next_start = html.index('id="next-steps"') |
| 247 | scenarios = html.index('id="scenarios"') |
| 248 | funnel = html.index('id="funnel"') |
| 249 | assert next_start < funnel < scenarios |
| 250 | |
| 251 | |
| 252 | def test_validate_rejects_apache_license_when_manifest_is_mit(tmp_path: Path) -> None: |
| 253 | """Fail-closed: SPDX flip must keep LICENSE and manifest aligned (§MIT.4).""" |
| 254 | landing = tmp_path / "docs" / "landing" |
| 255 | landing.mkdir(parents=True) |
| 256 | manifest_src = (KIT_ROOT / "docs" / "landing" / "manifest.yaml").read_text( |
| 257 | encoding="utf-8" |
| 258 | ) |
| 259 | (landing / "manifest.yaml").write_text(manifest_src, encoding="utf-8") |
| 260 | (landing / "index.html").write_text( |
| 261 | (KIT_ROOT / "docs" / "landing" / "index.html").read_text(encoding="utf-8"), |
| 262 | encoding="utf-8", |
| 263 | ) |
| 264 | scenarios = landing / "scenarios" |
| 265 | scenarios.mkdir() |
| 266 | (scenarios / "index.html").write_text( |
| 267 | (KIT_ROOT / "docs" / "landing" / "scenarios" / "index.html").read_text( |
| 268 | encoding="utf-8" |
| 269 | ), |
| 270 | encoding="utf-8", |
| 271 | ) |
| 272 | (landing / "assets").mkdir() |
| 273 | (landing / "assets" / "style.css").write_text("body{}", encoding="utf-8") |
| 274 | (tmp_path / "LICENSE").write_text( |
| 275 | "Apache License Version 2.0\nApache-2.0\n", encoding="utf-8" |
| 276 | ) |
| 277 | (tmp_path / "SECURITY.md").write_text( |
| 278 | "Reporting a vulnerability\n", encoding="utf-8" |
| 279 | ) |
| 280 | result = validate_landing(tmp_path) |
| 281 | assert not result.ok |
| 282 | assert any(e.startswith("license:") for e in result.errors) |
File History
1 commit
sha256:6abcf1fa82a7a621ccbc945f19acdba5bc0db54569599404a1452fb4a096a199
fix(ISR): default require_independent_second_reviewer to require
Human
minor
⚠
2 days ago