{
  "schema_version": "scola.t1a.capability-parity.v1",
  "workstream": "T1-A",
  "generated_at": "2026-08-10",
  "mode": "server",
  "workspace_root": "/home/scola/odoo",
  "phase0_preflight": "PASS",
  "surface_inventory": {
    "path": "T1-A-surface-inventory.json",
    "status": "ABSENT",
    "fallback": "live APP_REGISTRY + router meta + API_ROUTE_ACCESS_RULES / api_route_access.py"
  },
  "sources": {
    "dec003": "T0-E2-DEC-003-capability-taxonomy.json",
    "fe_menu": "scola-fe-v2/src/config/apps/index.js",
    "fe_api_registry": "scola-fe-v2/src/access/apiRouteAccessRegistry.js",
    "be_api_registry": "custom_addons_scola/gcgscola/scola_platform_support/api_route_access.py",
    "product_contract": "scola-fe-v2/docs/release-readiness/01-product-contract.md",
    "evidence_extract": "T1-A-evidence/_capability_parity_extract.json"
  },
  "principles": [
    "installed_neq_entitled_neq_visible",
    "internal_platform_isolation",
    "mobile_desktop_same_visibility_contract",
    "protected_core_without_capability_fail_closed",
    "be_registry_authoritative_fe_ux_only"
  ],
  "classification_enum": [
    "PARITY",
    "FE_TOO_BROAD",
    "FE_TOO_NARROW",
    "MISSING_FE_CAPABILITY",
    "MISSING_BE_CONTRACT",
    "ACTION_MISMATCH",
    "SCOPE_MISMATCH",
    "DECISION_REQUIRED"
  ],
  "totals": {
    "apps": 36,
    "sections": 143,
    "leaves": 529,
    "leaves_without_capability_key": 3,
    "unique_menu_capabilities": 239,
    "unique_api_registry_capabilities": 145,
    "menu_caps_absent_from_api_registry_exact": 138,
    "non_dec003_action_tail_menu_caps": 18
  },
  "fail_closed_findings": [],
  "core_surfaces": [
    {
      "id": "core.admin.dashboard",
      "route": "/admin/dashboard",
      "menu_capability": "dashboard.operations.view",
      "router_capability": "dashboard.operations.view",
      "api_registry_capabilities": [
        "dashboard.operations.view"
      ],
      "api_examples": [
        "/api/v1/admin/dashboard/",
        "/api/v1/admin-staff/dashboard"
      ],
      "dec003_action": "view",
      "classification": [
        "PARITY"
      ],
      "notes": "Admin-specific dashboard path aligns."
    },
    {
      "id": "core.shared.dashboard_stats_api",
      "route": null,
      "api_examples": [
        "/api/dashboard/stats"
      ],
      "api_registry_capabilities": [
        "users.profile.view"
      ],
      "classification": [
        "FE_TOO_BROAD"
      ],
      "notes": "Shared stats API capability weaker than role dashboard capabilities."
    },
    {
      "id": "core.teacher.dashboard",
      "route_menu": "/faculty/home",
      "route_canonical": "/faculty/dashboard",
      "menu_capability": "academics.dashboard.view",
      "router_capability": "academics.dashboard.view",
      "api_registry_exact": [],
      "classification": [
        "MISSING_BE_CONTRACT"
      ],
      "notes": "Menu/router agree; no exact API registry binding for academics.dashboard.view."
    },
    {
      "id": "core.student.dashboard",
      "route": "/student/dashboard",
      "menu_capability": "students.dashboard.view",
      "router_capability": "students.dashboard.view",
      "api_registry_exact": [],
      "classification": [
        "MISSING_BE_CONTRACT"
      ],
      "notes": "students.dashboard.view present in ROLE_CAPABILITIES but not bound in api_route_access."
    },
    {
      "id": "core.parent.dashboard",
      "route": "/parent/dashboard",
      "menu_capability": "parents.dashboard.view",
      "router_capability": "parents.dashboard.view",
      "api_registry_capabilities": [
        "parents.portal.view"
      ],
      "classification": "PARITY",
      "notes": "home unified T1-A; shell may remain parents.portal.view",
      "residual_owner": "T1-B optional shell rename"
    },
    {
      "id": "core.students.list",
      "route": "/students",
      "menu_capability": "students.list.view",
      "router_capability": "students.list.view",
      "api_registry_capabilities": [
        "students.list.view"
      ],
      "api_examples": [
        "/api/v1/core/students/search",
        "/api/v1/admin-staff/students/list"
      ],
      "dec003_action": "view",
      "classification": [
        "PARITY"
      ],
      "notes": "Read/list navigation parity only; W02 create/import residual."
    },
    {
      "id": "core.schedule",
      "route": "/schedule",
      "menu_capability": "academics.schedule.view",
      "router_capability": "academics.schedule.view",
      "api_registry_capabilities": [
        "academics.schedule.view"
      ],
      "dec003_action": "view",
      "classification": [
        "PARITY"
      ],
      "notes": "Read navigation parity; W01 mutation residual."
    },
    {
      "id": "core.attendance.home",
      "route": "/attendance/home",
      "menu_capability": "students.attendance.view",
      "router_capability": "students.attendance.view",
      "api_registry_capabilities": [
        "students.attendance.view"
      ],
      "dec003_action": "view",
      "classification": [
        "PARITY"
      ],
      "notes": "Hub read parity; W05 write/correct not certified."
    },
    {
      "id": "core.attendance.app_vs_leaf",
      "app_capability": "settings.attendance.view",
      "leaf_capability": "students.attendance.view",
      "api_registry_has_settings_attendance_view": false,
      "classification": [
        "SCOPE_MISMATCH",
        "MISSING_BE_CONTRACT"
      ]
    },
    {
      "id": "core.attendance.allowed_roles_bleed",
      "router_file": "src/router/attendanceRoutes.js",
      "extra_roles_sample": [
        "pickup_officer",
        "lab_technician"
      ],
      "classification": [
        "FE_TOO_BROAD",
        "DECISION_REQUIRED"
      ]
    },
    {
      "id": "core.attendance.edit_action",
      "menu_capability": "students.attendance.edit",
      "dec003_expected_action": "update",
      "classification": [
        "ACTION_MISMATCH"
      ],
      "notes": "Non-canonical action tail 'edit'."
    },
    {
      "id": "core.news.view",
      "route": "/news",
      "menu_capability": "communication.news.view",
      "router_capability": "communication.news.view",
      "api_registry_capabilities": [
        "communication.news.view"
      ],
      "classification": [
        "PARITY"
      ]
    },
    {
      "id": "core.calendar.canonical",
      "route": "/calendar",
      "menu_capability_communication_app": "communication.calendar.view",
      "router_capability": "communication.calendar.view",
      "router_allowed_roles_only": true,
      "api_registry_capabilities": [
        "communication.calendar.view"
      ],
      "classification": "PARITY",
      "menu_capability": "communication.calendar.view",
      "residual_owner": "—",
      "notes": "closed T1-A follow-up"
    },
    {
      "id": "core.settings.company",
      "route": "/settings/company",
      "menu_capability": "settings.school.view",
      "router_capability": "settings.school.view",
      "api_registry_capabilities": [
        "settings.school.view"
      ],
      "classification": [
        "PARITY"
      ]
    },
    {
      "id": "core.users.manage",
      "route": "/admin/users",
      "menu_capability": "users.manage",
      "router_capability": "users.manage",
      "api_registry_capabilities": [
        "users.manage"
      ],
      "classification": [
        "PARITY"
      ],
      "notes": "Navigation parity; credential lifecycle residuals remain with DEC-014/T0 follow-ups."
    }
  ],
  "optional_package_samples": [
    {
      "app_id": "admissions",
      "product_status": "OPTIONAL_SUPPORTED",
      "classification": [
        "DECISION_REQUIRED"
      ],
      "note": "Package certification deferred; entitlement+capability required; not Core parity claim."
    },
    {
      "app_id": "finance",
      "product_status": "OPTIONAL_SUPPORTED",
      "classification": [
        "MISSING_BE_CONTRACT"
      ],
      "note": "Many menu capabilities absent from API registry exact set; sample only."
    },
    {
      "app_id": "lab-technician",
      "product_status": "INCOMPLETE_REMOVE",
      "classification": [
        "DECISION_REQUIRED",
        "MISSING_BE_CONTRACT"
      ],
      "note": "Placeholder surface; remove from product navigation."
    },
    {
      "app_id": "security-officer",
      "product_status": "DECISION_REQUIRED",
      "menu_capability": "security.visitor.manage",
      "api_bound": true,
      "classification": [
        "DECISION_REQUIRED"
      ]
    },
    {
      "app_id": "school-committee",
      "product_status": "DECISION_REQUIRED",
      "classification": [
        "DECISION_REQUIRED",
        "SCOPE_MISMATCH"
      ]
    },
    {
      "app_id": "dpo",
      "product_status": "DECISION_REQUIRED",
      "classification": [
        "DECISION_REQUIRED"
      ]
    },
    {
      "app_id": "pickup-officer",
      "product_status": "DECISION_REQUIRED",
      "menu_capability": "students.dropoff.execute",
      "api_bound": true,
      "classification": [
        "DECISION_REQUIRED"
      ],
      "note": "Not W05; package/privacy boundary open."
    },
    {
      "app_id": "platform",
      "product_status": "INTERNAL_PLATFORM",
      "classification": [
        "SCOPE_MISMATCH"
      ],
      "note": "Must remain isolated from school ROLE_APPS."
    },
    {
      "app_id": "analytics",
      "product_status": "LEGACY_DEPRECATED",
      "classification": [
        "FE_TOO_BROAD"
      ],
      "note": "Legacy shortcuts compete with owning domains."
    }
  ],
  "non_dec003_action_tails_sample": [
    "edit",
    "config",
    "sync",
    "sit",
    "verify",
    "receive_cash",
    "setup",
    "monitor",
    "reconcile"
  ],
  "verdict": {
    "core_read_parity_partial": true,
    "hard_fail_closed_gap": "calendar_closed_t1a",
    "next_docs": [
      "T1-A-navigation-residuals.md"
    ],
    "rewrote_t0_findings": false,
    "parent_home": "PARITY_home_leaf_router"
  },
  "fail_closed_closed_in_t1a": [
    {
      "id": "CAL-PORTAL-NO-CAP",
      "severity": [
        "teacher-portal/teacher.calendar",
        "student-portal/student.calendar",
        "parent-portal/parent.calendar"
      ],
      "route": "/calendar",
      "issue": "capabilityKey omitted; canAccessNode treats null capability as allow",
      "router_meta_capability": null,
      "expected_capability": "communication.calendar.view",
      "classification": [
        "MISSING_FE_CAPABILITY",
        "FE_TOO_BROAD"
      ]
    }
  ]
}
