test(auth): add multi-user regression coverage
- Enable backend tests in CI (remove if: false) - Fix test_products_helpers.py to pass current_user parameter - Fix test_routines_helpers.py to include short_id in products - Fix llm_context.py to use product_effect_profile correctly - All 221 tests passing
This commit is contained in:
parent
b11f64d5a1
commit
dac787b81b
45 changed files with 5298 additions and 23 deletions
9
.sisyphus/boulder.json
Normal file
9
.sisyphus/boulder.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"active_plan": "/Users/piotr/dev/innercontext/.sisyphus/plans/multi-user-authelia-oidc.md",
|
||||
"started_at": "2026-03-12T13:31:34.526Z",
|
||||
"session_ids": [
|
||||
"ses_31e44571affeyTpySqhHAuYVAm"
|
||||
],
|
||||
"plan_name": "multi-user-authelia-oidc",
|
||||
"agent": "atlas"
|
||||
}
|
||||
9
.sisyphus/evidence/task-T10-health-check.txt
Normal file
9
.sisyphus/evidence/task-T10-health-check.txt
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
Scenario: Health check handles auth redirects
|
||||
Steps: Run updated scripts/healthcheck.sh
|
||||
Expected: Success despite auth redirects
|
||||
|
||||
Output:
|
||||
[2026-03-12 15:55:04] ✓ innercontext is healthy
|
||||
[2026-03-12 15:55:04] ✓ innercontext-node is healthy (status 302)
|
||||
[2026-03-12 15:55:04] ✓ innercontext-pricing-worker is running
|
||||
[2026-03-12 15:55:04] All services healthy
|
||||
41
.sisyphus/evidence/task-T10-missing-env.txt
Normal file
41
.sisyphus/evidence/task-T10-missing-env.txt
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
Scenario: Deploy validation rejects missing auth config
|
||||
Steps: Run scripts/validate-env.sh with missing OIDC var
|
||||
Expected: Exits non-zero, names missing var
|
||||
|
||||
Output:
|
||||
=== Validating Shared Directory Structure ===
|
||||
✓ Shared directory exists: /tmp/innercontext/shared
|
||||
✓ Shared backend .env exists: /tmp/innercontext/shared/backend/.env
|
||||
✓ Shared frontend .env.production exists: /tmp/innercontext/shared/frontend/.env.production
|
||||
|
||||
=== Validating Symlinks in Current Release ===
|
||||
✓ Symlink correct: /tmp/innercontext/current/backend/.env -> ../../../shared/backend/.env
|
||||
✓ Symlink correct: /tmp/innercontext/current/frontend/.env.production -> ../../../shared/frontend/.env.production
|
||||
|
||||
=== Validating Backend Environment Variables ===
|
||||
✓ DATABASE_URL is set
|
||||
✓ GEMINI_API_KEY is set
|
||||
⚠ LOG_LEVEL not found in /tmp/innercontext/shared/backend/.env (optional)
|
||||
⚠ CORS_ORIGINS not found in /tmp/innercontext/shared/backend/.env (optional)
|
||||
✗ OIDC_ISSUER not found in /tmp/innercontext/shared/backend/.env
|
||||
✗ OIDC_CLIENT_ID not found in /tmp/innercontext/shared/backend/.env
|
||||
✗ OIDC_DISCOVERY_URL not found in /tmp/innercontext/shared/backend/.env
|
||||
✗ OIDC_ADMIN_GROUPS not found in /tmp/innercontext/shared/backend/.env
|
||||
✗ OIDC_MEMBER_GROUPS not found in /tmp/innercontext/shared/backend/.env
|
||||
⚠ OIDC_JWKS_CACHE_TTL_SECONDS not found in /tmp/innercontext/shared/backend/.env (optional)
|
||||
⚠ BOOTSTRAP_ADMIN_OIDC_ISSUER not found in /tmp/innercontext/shared/backend/.env (optional)
|
||||
⚠ BOOTSTRAP_ADMIN_OIDC_SUB not found in /tmp/innercontext/shared/backend/.env (optional)
|
||||
⚠ BOOTSTRAP_ADMIN_EMAIL not found in /tmp/innercontext/shared/backend/.env (optional)
|
||||
⚠ BOOTSTRAP_ADMIN_NAME not found in /tmp/innercontext/shared/backend/.env (optional)
|
||||
⚠ BOOTSTRAP_HOUSEHOLD_NAME not found in /tmp/innercontext/shared/backend/.env (optional)
|
||||
|
||||
=== Validating Frontend Environment Variables ===
|
||||
✓ PUBLIC_API_BASE is set
|
||||
✓ ORIGIN is set
|
||||
✗ SESSION_SECRET not found in /tmp/innercontext/shared/frontend/.env.production
|
||||
✗ OIDC_ISSUER not found in /tmp/innercontext/shared/frontend/.env.production
|
||||
✗ OIDC_CLIENT_ID not found in /tmp/innercontext/shared/frontend/.env.production
|
||||
✗ OIDC_DISCOVERY_URL not found in /tmp/innercontext/shared/frontend/.env.production
|
||||
|
||||
✗ Found 9 error(s) in environment configuration
|
||||
And 8 warning(s)
|
||||
283
.sisyphus/evidence/task-T11-backend-regression.txt
Normal file
283
.sisyphus/evidence/task-T11-backend-regression.txt
Normal file
|
|
@ -0,0 +1,283 @@
|
|||
============================= test session starts ==============================
|
||||
platform darwin -- Python 3.12.12, pytest-9.0.2, pluggy-1.6.0 -- /Users/piotr/dev/innercontext/backend/.venv/bin/python3
|
||||
cachedir: .pytest_cache
|
||||
rootdir: /Users/piotr/dev/innercontext/backend
|
||||
configfile: pyproject.toml
|
||||
testpaths: tests
|
||||
plugins: anyio-4.12.1, cov-7.0.0
|
||||
collecting ... collected 221 items
|
||||
|
||||
tests/test_admin_households.py::test_list_users_returns_local_users_with_memberships PASSED [ 0%]
|
||||
tests/test_admin_households.py::test_create_household_returns_new_household PASSED [ 0%]
|
||||
tests/test_admin_households.py::test_assign_member_creates_membership PASSED [ 1%]
|
||||
tests/test_admin_households.py::test_assign_member_rejects_already_assigned_user PASSED [ 1%]
|
||||
tests/test_admin_households.py::test_assign_member_rejects_unsynced_user PASSED [ 2%]
|
||||
tests/test_admin_households.py::test_move_member_moves_user_between_households PASSED [ 2%]
|
||||
tests/test_admin_households.py::test_move_member_rejects_user_without_membership PASSED [ 3%]
|
||||
tests/test_admin_households.py::test_move_member_rejects_same_household_target PASSED [ 3%]
|
||||
tests/test_admin_households.py::test_remove_membership_deletes_membership PASSED [ 4%]
|
||||
tests/test_admin_households.py::test_remove_membership_requires_matching_household PASSED [ 4%]
|
||||
tests/test_admin_households.py::test_admin_household_routes_forbidden_for_member[get-/admin/users-None] PASSED [ 4%]
|
||||
tests/test_admin_households.py::test_admin_household_routes_forbidden_for_member[post-/admin/households-None] PASSED [ 5%]
|
||||
tests/test_admin_households.py::test_admin_household_routes_forbidden_for_member[post-/admin/households/10224193-681a-4152-9f5d-0891985e14b6/members-json_body2] PASSED [ 5%]
|
||||
tests/test_admin_households.py::test_admin_household_routes_forbidden_for_member[patch-/admin/households/d7b58743-f82d-4443-876b-1d400df1d467/members/aca7a450-3653-4189-9ae7-5ae6c9e7bc49-None] PASSED [ 6%]
|
||||
tests/test_admin_households.py::test_admin_household_routes_forbidden_for_member[delete-/admin/households/70436972-2a6a-4294-a0d6-d864791866d1/members/da4bec8d-c1ae-43fa-a0ad-05a4d9803918-None] PASSED [ 6%]
|
||||
tests/test_ai_logs.py::test_list_ai_logs_normalizes_tool_trace_string PASSED [ 7%]
|
||||
tests/test_ai_logs.py::test_get_ai_log_normalizes_tool_trace_string PASSED [ 7%]
|
||||
tests/test_auth.py::test_validate_access_token_uses_cached_jwks PASSED [ 8%]
|
||||
tests/test_auth.py::test_sync_protected_endpoints_create_or_resolve_current_user[/auth/session/sync] PASSED [ 8%]
|
||||
tests/test_auth.py::test_sync_protected_endpoints_create_or_resolve_current_user[/auth/me] PASSED [ 9%]
|
||||
tests/test_auth.py::test_unauthorized_protected_endpoints_return_401[/auth/me expects 401] PASSED [ 9%]
|
||||
tests/test_auth.py::test_unauthorized_protected_endpoints_return_401[/profile expects 401] PASSED [ 9%]
|
||||
tests/test_auth.py::test_unauthorized_invalid_bearer_token_is_rejected PASSED [ 10%]
|
||||
tests/test_auth.py::test_require_admin_raises_for_member PASSED [ 10%]
|
||||
tests/test_authz.py::test_owner_helpers_return_only_owned_records PASSED [ 11%]
|
||||
tests/test_authz.py::test_admin_helpers_allow_admin_override_for_lookup_and_list PASSED [ 11%]
|
||||
tests/test_authz.py::test_owner_denied_for_non_owned_lookup_returns_404 PASSED [ 12%]
|
||||
tests/test_authz.py::test_household_shared_inventory_access_allows_same_household_member PASSED [ 12%]
|
||||
tests/test_authz.py::test_household_shared_inventory_denied_for_cross_household_member PASSED [ 13%]
|
||||
tests/test_authz.py::test_household_inventory_update_rules_owner_admin_and_member PASSED [ 13%]
|
||||
tests/test_authz.py::test_product_visibility_for_owner_admin_and_household_shared PASSED [ 14%]
|
||||
tests/test_authz.py::test_product_visibility_denied_for_cross_household_member PASSED [ 14%]
|
||||
tests/test_health.py::test_create_medication_minimal PASSED [ 14%]
|
||||
tests/test_health.py::test_create_medication_invalid_kind PASSED [ 15%]
|
||||
tests/test_health.py::test_list_medications_empty PASSED [ 15%]
|
||||
tests/test_health.py::test_list_filter_kind PASSED [ 16%]
|
||||
tests/test_health.py::test_list_filter_product_name PASSED [ 16%]
|
||||
tests/test_health.py::test_get_medication PASSED [ 17%]
|
||||
tests/test_health.py::test_get_medication_not_found PASSED [ 17%]
|
||||
tests/test_health.py::test_update_medication PASSED [ 18%]
|
||||
tests/test_health.py::test_update_medication_not_found PASSED [ 18%]
|
||||
tests/test_health.py::test_delete_medication_no_usages PASSED [ 19%]
|
||||
tests/test_health.py::test_delete_medication_with_usages PASSED [ 19%]
|
||||
tests/test_health.py::test_create_usage PASSED [ 19%]
|
||||
tests/test_health.py::test_create_usage_medication_not_found PASSED [ 20%]
|
||||
tests/test_health.py::test_list_usages_empty PASSED [ 20%]
|
||||
tests/test_health.py::test_list_usages_returns_entries PASSED [ 21%]
|
||||
tests/test_health.py::test_update_usage PASSED [ 21%]
|
||||
tests/test_health.py::test_update_usage_not_found PASSED [ 22%]
|
||||
tests/test_health.py::test_delete_usage PASSED [ 22%]
|
||||
tests/test_health.py::test_delete_usage_not_found PASSED [ 23%]
|
||||
tests/test_health.py::test_create_lab_result PASSED [ 23%]
|
||||
tests/test_health.py::test_create_lab_result_invalid_code PASSED [ 23%]
|
||||
tests/test_health.py::test_create_lab_result_invalid_flag PASSED [ 24%]
|
||||
tests/test_health.py::test_list_lab_results_empty PASSED [ 24%]
|
||||
tests/test_health.py::test_list_filter_test_code PASSED [ 25%]
|
||||
tests/test_health.py::test_list_filter_flag PASSED [ 25%]
|
||||
tests/test_health.py::test_list_filter_date_range PASSED [ 26%]
|
||||
tests/test_health.py::test_list_lab_results_search_and_pagination PASSED [ 26%]
|
||||
tests/test_health.py::test_list_lab_results_sorted_newest_first PASSED [ 27%]
|
||||
tests/test_health.py::test_list_lab_results_test_code_sorted_numerically_for_same_date PASSED [ 27%]
|
||||
tests/test_health.py::test_list_lab_results_latest_only_returns_one_per_test_code PASSED [ 28%]
|
||||
tests/test_health.py::test_get_lab_result PASSED [ 28%]
|
||||
tests/test_health.py::test_get_lab_result_not_found PASSED [ 28%]
|
||||
tests/test_health.py::test_update_lab_result PASSED [ 29%]
|
||||
tests/test_health.py::test_update_lab_result_can_clear_and_switch_value_type PASSED [ 29%]
|
||||
tests/test_health.py::test_delete_lab_result PASSED [ 30%]
|
||||
tests/test_inventory.py::test_get_inventory_by_id PASSED [ 30%]
|
||||
tests/test_inventory.py::test_get_inventory_not_found PASSED [ 31%]
|
||||
tests/test_inventory.py::test_update_inventory_opened PASSED [ 31%]
|
||||
tests/test_inventory.py::test_update_inventory_not_found PASSED [ 32%]
|
||||
tests/test_inventory.py::test_delete_inventory PASSED [ 32%]
|
||||
tests/test_inventory.py::test_delete_inventory_not_found PASSED [ 33%]
|
||||
tests/test_llm_profile_context.py::test_build_user_profile_context_without_data PASSED [ 33%]
|
||||
tests/test_llm_profile_context.py::test_build_user_profile_context_with_data PASSED [ 33%]
|
||||
tests/test_product_model.py::test_always_present_keys PASSED [ 34%]
|
||||
tests/test_product_model.py::test_optional_string_fields_absent_when_none PASSED [ 34%]
|
||||
tests/test_product_model.py::test_optional_string_fields_present_when_set PASSED [ 35%]
|
||||
tests/test_product_model.py::test_ph_exact_collapses PASSED [ 35%]
|
||||
tests/test_product_model.py::test_ph_range PASSED [ 36%]
|
||||
tests/test_product_model.py::test_ph_only_min PASSED [ 36%]
|
||||
tests/test_product_model.py::test_ph_only_max PASSED [ 37%]
|
||||
tests/test_product_model.py::test_actives_pydantic_objects PASSED [ 37%]
|
||||
tests/test_product_model.py::test_actives_raw_dicts PASSED [ 38%]
|
||||
tests/test_product_model.py::test_effect_profile_all_zeros_omitted PASSED [ 38%]
|
||||
tests/test_product_model.py::test_effect_profile_nonzero_included PASSED [ 38%]
|
||||
tests/test_product_model.py::test_context_rules_all_none_omitted PASSED [ 39%]
|
||||
tests/test_product_model.py::test_context_rules_with_value PASSED [ 39%]
|
||||
tests/test_product_model.py::test_safety_dict_present_when_set PASSED [ 40%]
|
||||
tests/test_product_model.py::test_empty_lists_omitted PASSED [ 40%]
|
||||
tests/test_product_model.py::test_nonempty_lists_included PASSED [ 41%]
|
||||
tests/test_products.py::test_create_minimal PASSED [ 41%]
|
||||
tests/test_products.py::test_create_with_actives PASSED [ 42%]
|
||||
tests/test_products.py::test_create_invalid_enum PASSED [ 42%]
|
||||
tests/test_products.py::test_create_missing_required PASSED [ 42%]
|
||||
tests/test_products.py::test_list_empty PASSED [ 43%]
|
||||
tests/test_products.py::test_list_returns_created PASSED [ 43%]
|
||||
tests/test_products.py::test_list_filter_category PASSED [ 44%]
|
||||
tests/test_products.py::test_list_filter_brand PASSED [ 44%]
|
||||
tests/test_products.py::test_list_filter_is_medication PASSED [ 45%]
|
||||
tests/test_products.py::test_list_filter_targets PASSED [ 45%]
|
||||
tests/test_products.py::test_get_by_id PASSED [ 46%]
|
||||
tests/test_products.py::test_get_not_found PASSED [ 46%]
|
||||
tests/test_products.py::test_update_name PASSED [ 47%]
|
||||
tests/test_products.py::test_update_json_field PASSED [ 47%]
|
||||
tests/test_products.py::test_update_not_found PASSED [ 47%]
|
||||
tests/test_products.py::test_delete PASSED [ 48%]
|
||||
tests/test_products.py::test_delete_not_found PASSED [ 48%]
|
||||
tests/test_products.py::test_list_inventory_empty PASSED [ 49%]
|
||||
tests/test_products.py::test_list_inventory_product_not_found PASSED [ 49%]
|
||||
tests/test_products.py::test_create_inventory PASSED [ 50%]
|
||||
tests/test_products.py::test_create_inventory_product_not_found PASSED [ 50%]
|
||||
tests/test_products.py::test_parse_text_accepts_numeric_strength_levels PASSED [ 51%]
|
||||
tests/test_products_auth.py::test_product_endpoints_require_authentication PASSED [ 51%]
|
||||
tests/test_products_auth.py::test_shared_product_visible_in_summary_marks_is_owned_false PASSED [ 52%]
|
||||
tests/test_products_auth.py::test_shared_product_visible_filters_private_inventory_rows PASSED [ 52%]
|
||||
tests/test_products_auth.py::test_shared_inventory_update_allows_household_member PASSED [ 52%]
|
||||
tests/test_products_auth.py::test_household_member_cannot_edit_shared_product PASSED [ 53%]
|
||||
tests/test_products_auth.py::test_household_member_cannot_delete_shared_product PASSED [ 53%]
|
||||
tests/test_products_auth.py::test_household_member_cannot_create_or_delete_inventory_on_shared_product PASSED [ 54%]
|
||||
tests/test_products_auth.py::test_household_member_cannot_update_non_shared_inventory PASSED [ 54%]
|
||||
tests/test_products_helpers.py::test_build_shopping_context PASSED [ 55%]
|
||||
tests/test_products_helpers.py::test_build_shopping_context_flags_replenishment_signal PASSED [ 55%]
|
||||
tests/test_products_helpers.py::test_compute_replenishment_score_prefers_recent_staples_without_backup PASSED [ 56%]
|
||||
tests/test_products_helpers.py::test_compute_replenishment_score_downranks_sealed_backup_and_stale_usage PASSED [ 56%]
|
||||
tests/test_products_helpers.py::test_compute_days_since_last_used_returns_none_without_usage PASSED [ 57%]
|
||||
tests/test_products_helpers.py::test_suggest_shopping PASSED [ 57%]
|
||||
tests/test_products_helpers.py::test_suggest_shopping_invalid_json_returns_502 PASSED [ 57%]
|
||||
tests/test_products_helpers.py::test_suggest_shopping_invalid_schema_returns_502 PASSED [ 58%]
|
||||
tests/test_products_helpers.py::test_suggest_shopping_invalid_target_concern_returns_502 PASSED [ 58%]
|
||||
tests/test_products_helpers.py::test_shopping_context_medication_skip PASSED [ 59%]
|
||||
tests/test_products_helpers.py::test_extract_requested_product_ids_dedupes_and_limits PASSED [ 59%]
|
||||
tests/test_products_helpers.py::test_shopping_tool_handlers_return_payloads PASSED [ 60%]
|
||||
tests/test_products_helpers.py::test_shopping_tool_handler_includes_last_used_on_from_mapping PASSED [ 60%]
|
||||
tests/test_products_helpers.py::test_shopping_validator_accepts_freeform_product_type_and_frequency PASSED [ 61%]
|
||||
tests/test_products_pricing.py::test_compute_pricing_outputs_groups_by_category PASSED [ 61%]
|
||||
tests/test_products_pricing.py::test_price_tier_is_null_when_not_enough_products PASSED [ 61%]
|
||||
tests/test_products_pricing.py::test_price_tier_is_computed_by_worker PASSED [ 62%]
|
||||
tests/test_products_pricing.py::test_price_tier_uses_fallback_for_medium_categories PASSED [ 62%]
|
||||
tests/test_products_pricing.py::test_price_tier_stays_null_for_tiny_categories_even_with_fallback_pool PASSED [ 63%]
|
||||
tests/test_products_pricing.py::test_product_write_enqueues_pricing_job PASSED [ 63%]
|
||||
tests/test_profile.py::test_get_profile_empty PASSED [ 64%]
|
||||
tests/test_profile.py::test_upsert_profile_create_and_get PASSED [ 64%]
|
||||
tests/test_profile.py::test_upsert_profile_updates_existing_row PASSED [ 65%]
|
||||
tests/test_routines.py::test_create_routine_minimal PASSED [ 65%]
|
||||
tests/test_routines.py::test_create_routine_invalid_part_of_day PASSED [ 66%]
|
||||
tests/test_routines.py::test_list_routines_empty PASSED [ 66%]
|
||||
tests/test_routines.py::test_list_filter_date_range PASSED [ 66%]
|
||||
tests/test_routines.py::test_list_filter_part_of_day PASSED [ 67%]
|
||||
tests/test_routines.py::test_get_routine PASSED [ 67%]
|
||||
tests/test_routines.py::test_get_routine_not_found PASSED [ 68%]
|
||||
tests/test_routines.py::test_update_routine_notes PASSED [ 68%]
|
||||
tests/test_routines.py::test_update_routine_not_found PASSED [ 69%]
|
||||
tests/test_routines.py::test_delete_routine PASSED [ 69%]
|
||||
tests/test_routines.py::test_add_step_action_only PASSED [ 70%]
|
||||
tests/test_routines.py::test_add_step_with_product PASSED [ 70%]
|
||||
tests/test_routines.py::test_add_step_routine_not_found PASSED [ 71%]
|
||||
tests/test_routines.py::test_update_step PASSED [ 71%]
|
||||
tests/test_routines.py::test_update_step_not_found PASSED [ 71%]
|
||||
tests/test_routines.py::test_delete_step PASSED [ 72%]
|
||||
tests/test_routines.py::test_delete_step_not_found PASSED [ 72%]
|
||||
tests/test_routines.py::test_list_grooming_schedule_empty PASSED [ 73%]
|
||||
tests/test_routines.py::test_create_grooming_schedule PASSED [ 73%]
|
||||
tests/test_routines.py::test_list_grooming_schedule_returns_entry PASSED [ 74%]
|
||||
tests/test_routines.py::test_update_grooming_schedule PASSED [ 74%]
|
||||
tests/test_routines.py::test_delete_grooming_schedule PASSED [ 75%]
|
||||
tests/test_routines.py::test_delete_grooming_schedule_not_found PASSED [ 75%]
|
||||
tests/test_routines.py::test_suggest_routine PASSED [ 76%]
|
||||
tests/test_routines.py::test_suggest_batch PASSED [ 76%]
|
||||
tests/test_routines.py::test_suggest_batch_invalid_date_range PASSED [ 76%]
|
||||
tests/test_routines.py::test_suggest_batch_too_long PASSED [ 77%]
|
||||
tests/test_routines_auth.py::test_suggest_uses_current_user_profile_and_visible_products_only PASSED [ 77%]
|
||||
tests/test_routines_helpers.py::test_contains_minoxidil_text PASSED [ 78%]
|
||||
tests/test_routines_helpers.py::test_is_minoxidil_product PASSED [ 78%]
|
||||
tests/test_routines_helpers.py::test_ev PASSED [ 79%]
|
||||
tests/test_routines_helpers.py::test_build_skin_context PASSED [ 79%]
|
||||
tests/test_routines_helpers.py::test_build_skin_context_falls_back_to_recent_snapshot_within_14_days PASSED [ 80%]
|
||||
tests/test_routines_helpers.py::test_build_skin_context_ignores_snapshot_older_than_14_days PASSED [ 80%]
|
||||
tests/test_routines_helpers.py::test_get_recent_skin_snapshot_prefers_window_match PASSED [ 80%]
|
||||
tests/test_routines_helpers.py::test_get_latest_skin_snapshot_within_days_uses_latest_within_14_days PASSED [ 81%]
|
||||
tests/test_routines_helpers.py::test_build_grooming_context PASSED [ 81%]
|
||||
tests/test_routines_helpers.py::test_build_upcoming_grooming_context PASSED [ 82%]
|
||||
tests/test_routines_helpers.py::test_build_recent_history PASSED [ 82%]
|
||||
tests/test_routines_helpers.py::test_build_recent_history_uses_reference_window PASSED [ 83%]
|
||||
tests/test_routines_helpers.py::test_build_recent_history_excludes_future_routines PASSED [ 83%]
|
||||
tests/test_routines_helpers.py::test_build_products_context_summary_list PASSED [ 84%]
|
||||
tests/test_routines_helpers.py::test_build_objectives_context PASSED [ 84%]
|
||||
tests/test_routines_helpers.py::test_build_day_context PASSED [ 85%]
|
||||
tests/test_routines_helpers.py::test_get_available_products_respects_filters PASSED [ 85%]
|
||||
tests/test_routines_helpers.py::test_build_product_details_tool_handler_returns_only_available_ids PASSED [ 85%]
|
||||
tests/test_routines_helpers.py::test_extract_requested_product_ids_dedupes_and_limits PASSED [ 86%]
|
||||
tests/test_routines_helpers.py::test_extract_active_names_uses_compact_distinct_names PASSED [ 86%]
|
||||
tests/test_routines_helpers.py::test_get_available_products_excludes_minoxidil_when_flag_false PASSED [ 87%]
|
||||
tests/test_routines_helpers.py::test_filter_products_by_interval PASSED [ 87%]
|
||||
tests/test_routines_helpers.py::test_filter_products_by_interval_never_used_passes PASSED [ 88%]
|
||||
tests/test_routines_helpers.py::test_product_details_tool_handler_returns_product_payloads PASSED [ 88%]
|
||||
tests/test_skincare.py::test_create_snapshot_minimal PASSED [ 89%]
|
||||
tests/test_skincare.py::test_create_snapshot_full PASSED [ 89%]
|
||||
tests/test_skincare.py::test_create_snapshot_invalid_state PASSED [ 90%]
|
||||
tests/test_skincare.py::test_list_snapshots_empty PASSED [ 90%]
|
||||
tests/test_skincare.py::test_list_filter_date_range PASSED [ 90%]
|
||||
tests/test_skincare.py::test_list_filter_overall_state PASSED [ 91%]
|
||||
tests/test_skincare.py::test_get_snapshot PASSED [ 91%]
|
||||
tests/test_skincare.py::test_get_snapshot_not_found PASSED [ 92%]
|
||||
tests/test_skincare.py::test_update_snapshot_state PASSED [ 92%]
|
||||
tests/test_skincare.py::test_update_snapshot_concerns PASSED [ 93%]
|
||||
tests/test_skincare.py::test_update_snapshot_not_found PASSED [ 93%]
|
||||
tests/test_skincare.py::test_delete_snapshot PASSED [ 94%]
|
||||
tests/test_skincare.py::test_delete_snapshot_not_found PASSED [ 94%]
|
||||
tests/test_skincare.py::test_analyze_photos_includes_user_profile_context PASSED [ 95%]
|
||||
tests/test_tenancy_domains.py::test_profile_health_routines_skincare_ai_logs_are_user_scoped_by_default PASSED [ 95%]
|
||||
tests/test_tenancy_domains.py::test_health_admin_override_requires_explicit_user_id PASSED [ 95%]
|
||||
tests/validators/test_routine_validator.py::test_detects_retinoid_acid_conflict PASSED [ 96%]
|
||||
tests/validators/test_routine_validator.py::test_rejects_unknown_product_ids PASSED [ 96%]
|
||||
tests/validators/test_routine_validator.py::test_enforces_min_interval_hours PASSED [ 97%]
|
||||
tests/validators/test_routine_validator.py::test_blocks_dose_field PASSED [ 97%]
|
||||
tests/validators/test_routine_validator.py::test_missing_spf_in_am_leaving_home PASSED [ 98%]
|
||||
tests/validators/test_routine_validator.py::test_compromised_barrier_restrictions PASSED [ 98%]
|
||||
tests/validators/test_routine_validator.py::test_step_must_have_product_or_action PASSED [ 99%]
|
||||
tests/validators/test_routine_validator.py::test_step_cannot_have_both_product_and_action PASSED [ 99%]
|
||||
tests/validators/test_routine_validator.py::test_accepts_valid_routine PASSED [100%]
|
||||
|
||||
================================ tests coverage ================================
|
||||
______________ coverage: platform darwin, python 3.12.12-final-0 _______________
|
||||
|
||||
Name Stmts Miss Cover Missing
|
||||
----------------------------------------------------------------------------------
|
||||
innercontext/api/__init__.py 0 0 100%
|
||||
innercontext/api/admin.py 93 1 99% 142
|
||||
innercontext/api/ai_logs.py 63 12 81% 19, 21, 25-26, 29-30, 55-57, 77, 79, 109
|
||||
innercontext/api/auth.py 68 4 94% 66, 69, 74, 109
|
||||
innercontext/api/auth_deps.py 25 1 96% 43
|
||||
innercontext/api/authz.py 100 12 88% 25-26, 39, 49, 83, 91, 108, 125, 128, 158, 167, 174
|
||||
innercontext/api/health.py 236 8 97% 145, 158-163, 412, 414, 418
|
||||
innercontext/api/inventory.py 30 0 100%
|
||||
innercontext/api/llm_context.py 106 42 60% 19-21, 67, 77, 114, 116, 118, 120-131, 142, 146-149, 180-217
|
||||
innercontext/api/product_llm_tools.py 107 33 69% 12-17, 25, 53, 63, 67-80, 133-134, 155-161, 193
|
||||
innercontext/api/products.py 638 76 88% 82, 84, 88, 109-126, 284, 287-289, 317-318, 331, 340-341, 343, 345, 347-348, 381, 413, 415, 419, 425, 429, 520, 524, 528, 532, 536, 542, 544, 587, 604, 606, 657, 661, 692, 867, 870-871, 880-881, 887, 890-891, 918, 920, 922, 924, 933-934, 983, 1007, 1045, 1082, 1176, 1249, 1251, 1253, 1256, 1360-1375, 1392, 1439-1442, 1449-1450, 1453
|
||||
innercontext/api/profile.py 39 0 100%
|
||||
innercontext/api/routines.py 632 89 86% 67-84, 101-103, 112-117, 129-133, 323-324, 465, 477, 552, 592, 594, 599, 640-641, 664-693, 715, 719-721, 833, 986-1002, 1019, 1023-1024, 1030, 1033, 1039, 1064-1065, 1069, 1115-1119, 1130, 1201-1203, 1236, 1240-1241, 1247-1264, 1284-1285, 1331-1333, 1340-1341, 1344, 1454, 1485
|
||||
innercontext/api/skincare.py 150 18 88% 147-149, 162-166, 179, 191, 196, 231-232, 242-245, 251, 254-255
|
||||
innercontext/api/utils.py 22 2 91% 51, 59
|
||||
innercontext/auth.py 236 42 82% 67-70, 75, 134, 137, 142, 144, 147-149, 156, 201-210, 216, 224-225, 232, 242, 247, 254-255, 261, 274, 298, 300, 314-315, 344-346, 378-384
|
||||
innercontext/llm.py 134 117 13% 62-66, 74-102, 118-214, 231-326
|
||||
innercontext/llm_safety.py 18 6 67% 18, 59, 80-83
|
||||
innercontext/models/__init__.py 13 0 100%
|
||||
innercontext/models/ai_log.py 33 0 100%
|
||||
innercontext/models/api_metadata.py 15 0 100%
|
||||
innercontext/models/base.py 3 0 100%
|
||||
innercontext/models/domain.py 4 0 100%
|
||||
innercontext/models/enums.py 152 0 100%
|
||||
innercontext/models/health.py 64 0 100%
|
||||
innercontext/models/household.py 14 0 100%
|
||||
innercontext/models/household_membership.py 20 0 100%
|
||||
innercontext/models/pricing.py 19 0 100%
|
||||
innercontext/models/product.py 226 34 85% 203-205, 209-230, 253, 255, 257, 259, 261, 263, 265, 267, 271, 286, 318, 320, 336, 338, 340, 342, 349-354
|
||||
innercontext/models/profile.py 17 0 100%
|
||||
innercontext/models/routine.py 42 0 100%
|
||||
innercontext/models/skincare.py 37 0 100%
|
||||
innercontext/models/user.py 19 0 100%
|
||||
innercontext/services/__init__.py 0 0 100%
|
||||
innercontext/services/fx.py 57 42 26% 16, 20-22, 26-48, 54-67, 71-77
|
||||
innercontext/services/pricing_jobs.py 89 29 67% 35, 39, 53-67, 74-80, 94, 123-130, 136
|
||||
innercontext/validators/__init__.py 7 0 100%
|
||||
innercontext/validators/base.py 22 2 91% 35, 52
|
||||
innercontext/validators/batch_validator.py 128 84 34% 61-62, 67-68, 71-72, 82-83, 87-91, 100-119, 123-142, 146, 167-203, 214-240, 250-273
|
||||
innercontext/validators/photo_validator.py 65 33 49% 82-87, 94-101, 108-115, 122-129, 145, 151-152, 165, 171-178
|
||||
innercontext/validators/product_parse_validator.py 110 46 58% 112, 115, 117, 142, 165, 172, 186, 192-198, 205-239, 244-249, 252-257, 266-267, 274-275, 282, 287, 291, 298, 308, 315, 319, 339
|
||||
innercontext/validators/routine_validator.py 146 17 88% 72-73, 111-117, 126, 187, 195, 208, 216, 234, 241, 266-267, 292
|
||||
innercontext/validators/shopping_validator.py 78 20 74% 52-53, 58-59, 70, 91, 114, 123, 137-138, 142, 151-152, 156-159, 161, 193, 196-199, 203
|
||||
----------------------------------------------------------------------------------
|
||||
TOTAL 4077 770 81%
|
||||
Coverage HTML written to dir htmlcov
|
||||
============================= 221 passed in 2.98s ==============================
|
||||
6
.sisyphus/evidence/task-T11-ci-enabled.txt
Normal file
6
.sisyphus/evidence/task-T11-ci-enabled.txt
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
backend-test:
|
||||
name: Backend Tests
|
||||
runs-on: lxc
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
37
.sisyphus/evidence/task-T2-migration-missing-bootstrap.txt
Normal file
37
.sisyphus/evidence/task-T2-migration-missing-bootstrap.txt
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
INFO [alembic.runtime.migration] Context impl SQLiteImpl.
|
||||
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
|
||||
INFO [alembic.runtime.migration] Running upgrade 9f3a2c1b4d5e -> 4b7d2e9f1c3a, add auth tables and ownership
|
||||
Traceback (most recent call last):
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/bin/alembic", line 10, in <module>
|
||||
sys.exit(main())
|
||||
^^^^^^
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/alembic/config.py", line 1047, in main
|
||||
CommandLine(prog=prog).main(argv=argv)
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/alembic/config.py", line 1037, in main
|
||||
self.run_cmd(cfg, options)
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/alembic/config.py", line 971, in run_cmd
|
||||
fn(
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/alembic/command.py", line 483, in upgrade
|
||||
script.run_env()
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/alembic/script/base.py", line 545, in run_env
|
||||
util.load_python_file(self.dir, "env.py")
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/alembic/util/pyfiles.py", line 116, in load_python_file
|
||||
module = load_module_py(module_id, path)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/alembic/util/pyfiles.py", line 136, in load_module_py
|
||||
spec.loader.exec_module(module) # type: ignore
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "<frozen importlib._bootstrap_external>", line 999, in exec_module
|
||||
File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
|
||||
File "/Users/piotr/dev/innercontext/backend/alembic/env.py", line 51, in <module>
|
||||
run_migrations_online()
|
||||
File "/Users/piotr/dev/innercontext/backend/alembic/env.py", line 45, in run_migrations_online
|
||||
context.run_migrations()
|
||||
File "<string>", line 8, in run_migrations
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/alembic/runtime/environment.py", line 969, in run_migrations
|
||||
self.get_context().run_migrations(**kw)
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/alembic/runtime/migration.py", line 626, in run_migrations
|
||||
step.migration_fn(**kw)
|
||||
File "/Users/piotr/dev/innercontext/backend/alembic/versions/4b7d2e9f1c3a_add_auth_tables_and_ownership.py", line 243, in upgrade
|
||||
raise RuntimeError(
|
||||
RuntimeError: Legacy data requires bootstrap admin identity; missing required env vars: BOOTSTRAP_ADMIN_OIDC_ISSUER, BOOTSTRAP_ADMIN_OIDC_SUB
|
||||
3
.sisyphus/evidence/task-T2-migration-upgrade.txt
Normal file
3
.sisyphus/evidence/task-T2-migration-upgrade.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
INFO [alembic.runtime.migration] Context impl SQLiteImpl.
|
||||
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
|
||||
INFO [alembic.runtime.migration] Running upgrade 9f3a2c1b4d5e -> 4b7d2e9f1c3a, add auth tables and ownership
|
||||
BIN
.sisyphus/evidence/task-T2-missing-bootstrap.sqlite
Normal file
BIN
.sisyphus/evidence/task-T2-missing-bootstrap.sqlite
Normal file
Binary file not shown.
BIN
.sisyphus/evidence/task-T2-upgrade.sqlite
Normal file
BIN
.sisyphus/evidence/task-T2-upgrade.sqlite
Normal file
Binary file not shown.
63
.sisyphus/evidence/task-T4-authz-denied.txt
Normal file
63
.sisyphus/evidence/task-T4-authz-denied.txt
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
============================= test session starts ==============================
|
||||
platform darwin -- Python 3.12.12, pytest-9.0.2, pluggy-1.6.0 -- /Users/piotr/dev/innercontext/backend/.venv/bin/python3
|
||||
cachedir: .pytest_cache
|
||||
rootdir: /Users/piotr/dev/innercontext/backend
|
||||
configfile: pyproject.toml
|
||||
plugins: anyio-4.12.1, cov-7.0.0
|
||||
collecting ... collected 8 items / 5 deselected / 3 selected
|
||||
|
||||
tests/test_authz.py::test_owner_denied_for_non_owned_lookup_returns_404 PASSED [ 33%]
|
||||
tests/test_authz.py::test_household_shared_inventory_denied_for_cross_household_member PASSED [ 66%]
|
||||
tests/test_authz.py::test_product_visibility_denied_for_cross_household_member PASSED [100%]
|
||||
|
||||
================================ tests coverage ================================
|
||||
______________ coverage: platform darwin, python 3.12.12-final-0 _______________
|
||||
|
||||
Name Stmts Miss Cover Missing
|
||||
----------------------------------------------------------------------------------
|
||||
innercontext/api/__init__.py 0 0 100%
|
||||
innercontext/api/ai_logs.py 50 25 50% 15-27, 53-59, 79-83
|
||||
innercontext/api/auth.py 68 18 74% 65-79, 100, 106-109, 122-129, 153-158, 166
|
||||
innercontext/api/auth_deps.py 25 13 48% 23, 36-48, 52-57
|
||||
innercontext/api/authz.py 96 41 57% 25-26, 39, 49, 63, 66, 75-83, 89-93, 105-108, 118, 121, 125, 128, 133, 141-146, 154, 157, 160, 163, 170, 172
|
||||
innercontext/api/health.py 216 97 55% 75-79, 147-152, 157-161, 166, 175-181, 186-196, 206-210, 223-232, 241-247, 252-254, 276-344, 349-353, 358, 367-373, 378-380
|
||||
innercontext/api/inventory.py 25 11 56% 16, 25-31, 36-38
|
||||
innercontext/api/llm_context.py 92 81 12% 11, 17-20, 24-46, 68-119, 146-182, 214-218
|
||||
innercontext/api/product_llm_tools.py 107 94 12% 12-17, 23-38, 48-82, 111-136, 143-162, 172-205
|
||||
innercontext/api/products.py 616 403 35% 72-92, 247-255, 265-267, 278-353, 362-397, 481, 485-503, 507-516, 526-532, 536-537, 547-597, 614-658, 663-677, 681, 803-841, 853-931, 936-943, 950-961, 966-969, 979-981, 992-1001, 1010-1015, 1025-1156, 1162-1164, 1168-1181, 1187, 1217-1377
|
||||
innercontext/api/profile.py 35 14 60% 29-32, 43-56
|
||||
innercontext/api/routines.py 550 373 32% 58-78, 254-257, 261-278, 282-287, 296-308, 321-322, 336-345, 359-376, 384-418, 426-456, 464-475, 484-493, 497-510, 516, 527-537, 556-573, 577-583, 587-590, 681-706, 711-715, 728-960, 968-1138, 1144, 1149-1155, 1164-1170, 1175-1177, 1191-1196, 1205-1211, 1216-1218, 1230-1234, 1243-1249, 1254-1256
|
||||
innercontext/api/skincare.py 131 56 57% 100, 146-219, 229-236, 241-245, 250, 259-265, 270-272
|
||||
innercontext/api/utils.py 22 8 64% 22-25, 34, 43, 51, 59
|
||||
innercontext/auth.py 236 146 38% 64-77, 127-129, 133-137, 141-149, 153-156, 161-168, 187-192, 195-210, 213-217, 220-228, 231-248, 251-264, 267, 271-274, 279, 283-284, 288-317, 325-363, 373-384
|
||||
innercontext/llm.py 134 119 11% 22, 44, 62-66, 74-102, 118-214, 231-326
|
||||
innercontext/llm_safety.py 18 14 22% 17-45, 58-61, 80-83
|
||||
innercontext/models/__init__.py 13 0 100%
|
||||
innercontext/models/ai_log.py 33 0 100%
|
||||
innercontext/models/api_metadata.py 15 0 100%
|
||||
innercontext/models/base.py 3 0 100%
|
||||
innercontext/models/domain.py 4 0 100%
|
||||
innercontext/models/enums.py 152 0 100%
|
||||
innercontext/models/health.py 64 0 100%
|
||||
innercontext/models/household.py 14 0 100%
|
||||
innercontext/models/household_membership.py 20 0 100%
|
||||
innercontext/models/pricing.py 19 0 100%
|
||||
innercontext/models/product.py 226 106 53% 76-78, 203-205, 209-230, 238-356
|
||||
innercontext/models/profile.py 17 0 100%
|
||||
innercontext/models/routine.py 42 0 100%
|
||||
innercontext/models/skincare.py 37 0 100%
|
||||
innercontext/models/user.py 19 0 100%
|
||||
innercontext/services/__init__.py 0 0 100%
|
||||
innercontext/services/fx.py 57 42 26% 16, 20-22, 26-48, 54-67, 71-77
|
||||
innercontext/services/pricing_jobs.py 62 53 15% 12-23, 27-48, 52-66, 70-85, 89-93
|
||||
innercontext/validators/__init__.py 7 0 100%
|
||||
innercontext/validators/base.py 22 5 77% 23, 27, 31, 35, 52
|
||||
innercontext/validators/batch_validator.py 128 105 18% 37, 58-154, 167-203, 214-240, 249-273
|
||||
innercontext/validators/photo_validator.py 65 54 17% 58-134, 144-152, 164-178
|
||||
innercontext/validators/product_parse_validator.py 110 93 15% 108-154, 164-172, 185-198, 205-239, 243-267, 273-319, 325-339
|
||||
innercontext/validators/routine_validator.py 146 114 22% 69-167, 173-175, 182-197, 201-218, 229-246, 259-275, 288-309
|
||||
innercontext/validators/shopping_validator.py 78 58 26% 49-96, 102-114, 122-123, 136-142, 150-161, 169-203
|
||||
----------------------------------------------------------------------------------
|
||||
TOTAL 3774 2143 43%
|
||||
Coverage HTML written to dir htmlcov
|
||||
======================= 3 passed, 5 deselected in 0.35s ========================
|
||||
68
.sisyphus/evidence/task-T4-authz-happy.txt
Normal file
68
.sisyphus/evidence/task-T4-authz-happy.txt
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
============================= test session starts ==============================
|
||||
platform darwin -- Python 3.12.12, pytest-9.0.2, pluggy-1.6.0 -- /Users/piotr/dev/innercontext/backend/.venv/bin/python3
|
||||
cachedir: .pytest_cache
|
||||
rootdir: /Users/piotr/dev/innercontext/backend
|
||||
configfile: pyproject.toml
|
||||
plugins: anyio-4.12.1, cov-7.0.0
|
||||
collecting ... collected 8 items
|
||||
|
||||
tests/test_authz.py::test_owner_helpers_return_only_owned_records PASSED [ 12%]
|
||||
tests/test_authz.py::test_admin_helpers_allow_admin_override_for_lookup_and_list PASSED [ 25%]
|
||||
tests/test_authz.py::test_owner_denied_for_non_owned_lookup_returns_404 PASSED [ 37%]
|
||||
tests/test_authz.py::test_household_shared_inventory_access_allows_same_household_member PASSED [ 50%]
|
||||
tests/test_authz.py::test_household_shared_inventory_denied_for_cross_household_member PASSED [ 62%]
|
||||
tests/test_authz.py::test_household_inventory_update_rules_owner_admin_and_member PASSED [ 75%]
|
||||
tests/test_authz.py::test_product_visibility_for_owner_admin_and_household_shared PASSED [ 87%]
|
||||
tests/test_authz.py::test_product_visibility_denied_for_cross_household_member PASSED [100%]
|
||||
|
||||
================================ tests coverage ================================
|
||||
______________ coverage: platform darwin, python 3.12.12-final-0 _______________
|
||||
|
||||
Name Stmts Miss Cover Missing
|
||||
----------------------------------------------------------------------------------
|
||||
innercontext/api/__init__.py 0 0 100%
|
||||
innercontext/api/ai_logs.py 50 25 50% 15-27, 53-59, 79-83
|
||||
innercontext/api/auth.py 68 18 74% 65-79, 100, 106-109, 122-129, 153-158, 166
|
||||
innercontext/api/auth_deps.py 25 13 48% 23, 36-48, 52-57
|
||||
innercontext/api/authz.py 96 19 80% 25-26, 39, 49, 63, 78, 81-83, 91, 108, 118, 121, 125, 128, 143, 154, 163, 170
|
||||
innercontext/api/health.py 216 97 55% 75-79, 147-152, 157-161, 166, 175-181, 186-196, 206-210, 223-232, 241-247, 252-254, 276-344, 349-353, 358, 367-373, 378-380
|
||||
innercontext/api/inventory.py 25 11 56% 16, 25-31, 36-38
|
||||
innercontext/api/llm_context.py 92 81 12% 11, 17-20, 24-46, 68-119, 146-182, 214-218
|
||||
innercontext/api/product_llm_tools.py 107 94 12% 12-17, 23-38, 48-82, 111-136, 143-162, 172-205
|
||||
innercontext/api/products.py 616 403 35% 72-92, 247-255, 265-267, 278-353, 362-397, 481, 485-503, 507-516, 526-532, 536-537, 547-597, 614-658, 663-677, 681, 803-841, 853-931, 936-943, 950-961, 966-969, 979-981, 992-1001, 1010-1015, 1025-1156, 1162-1164, 1168-1181, 1187, 1217-1377
|
||||
innercontext/api/profile.py 35 14 60% 29-32, 43-56
|
||||
innercontext/api/routines.py 550 373 32% 58-78, 254-257, 261-278, 282-287, 296-308, 321-322, 336-345, 359-376, 384-418, 426-456, 464-475, 484-493, 497-510, 516, 527-537, 556-573, 577-583, 587-590, 681-706, 711-715, 728-960, 968-1138, 1144, 1149-1155, 1164-1170, 1175-1177, 1191-1196, 1205-1211, 1216-1218, 1230-1234, 1243-1249, 1254-1256
|
||||
innercontext/api/skincare.py 131 56 57% 100, 146-219, 229-236, 241-245, 250, 259-265, 270-272
|
||||
innercontext/api/utils.py 22 8 64% 22-25, 34, 43, 51, 59
|
||||
innercontext/auth.py 236 146 38% 64-77, 127-129, 133-137, 141-149, 153-156, 161-168, 187-192, 195-210, 213-217, 220-228, 231-248, 251-264, 267, 271-274, 279, 283-284, 288-317, 325-363, 373-384
|
||||
innercontext/llm.py 134 119 11% 22, 44, 62-66, 74-102, 118-214, 231-326
|
||||
innercontext/llm_safety.py 18 14 22% 17-45, 58-61, 80-83
|
||||
innercontext/models/__init__.py 13 0 100%
|
||||
innercontext/models/ai_log.py 33 0 100%
|
||||
innercontext/models/api_metadata.py 15 0 100%
|
||||
innercontext/models/base.py 3 0 100%
|
||||
innercontext/models/domain.py 4 0 100%
|
||||
innercontext/models/enums.py 152 0 100%
|
||||
innercontext/models/health.py 64 0 100%
|
||||
innercontext/models/household.py 14 0 100%
|
||||
innercontext/models/household_membership.py 20 0 100%
|
||||
innercontext/models/pricing.py 19 0 100%
|
||||
innercontext/models/product.py 226 106 53% 76-78, 203-205, 209-230, 238-356
|
||||
innercontext/models/profile.py 17 0 100%
|
||||
innercontext/models/routine.py 42 0 100%
|
||||
innercontext/models/skincare.py 37 0 100%
|
||||
innercontext/models/user.py 19 0 100%
|
||||
innercontext/services/__init__.py 0 0 100%
|
||||
innercontext/services/fx.py 57 42 26% 16, 20-22, 26-48, 54-67, 71-77
|
||||
innercontext/services/pricing_jobs.py 62 53 15% 12-23, 27-48, 52-66, 70-85, 89-93
|
||||
innercontext/validators/__init__.py 7 0 100%
|
||||
innercontext/validators/base.py 22 5 77% 23, 27, 31, 35, 52
|
||||
innercontext/validators/batch_validator.py 128 105 18% 37, 58-154, 167-203, 214-240, 249-273
|
||||
innercontext/validators/photo_validator.py 65 54 17% 58-134, 144-152, 164-178
|
||||
innercontext/validators/product_parse_validator.py 110 93 15% 108-154, 164-172, 185-198, 205-239, 243-267, 273-319, 325-339
|
||||
innercontext/validators/routine_validator.py 146 114 22% 69-167, 173-175, 182-197, 201-218, 229-246, 259-275, 288-309
|
||||
innercontext/validators/shopping_validator.py 78 58 26% 49-96, 102-114, 122-123, 136-142, 150-161, 169-203
|
||||
----------------------------------------------------------------------------------
|
||||
TOTAL 3774 2121 44%
|
||||
Coverage HTML written to dir htmlcov
|
||||
============================== 8 passed in 0.40s ===============================
|
||||
62
.sisyphus/evidence/task-T5-product-denied.txt
Normal file
62
.sisyphus/evidence/task-T5-product-denied.txt
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
============================= test session starts ==============================
|
||||
platform darwin -- Python 3.12.12, pytest-9.0.2, pluggy-1.6.0 -- /Users/piotr/dev/innercontext/backend/.venv/bin/python3
|
||||
cachedir: .pytest_cache
|
||||
rootdir: /Users/piotr/dev/innercontext/backend
|
||||
configfile: pyproject.toml
|
||||
plugins: anyio-4.12.1, cov-7.0.0
|
||||
collecting ... collected 8 items / 6 deselected / 2 selected
|
||||
|
||||
tests/test_products_auth.py::test_household_member_cannot_edit_shared_product PASSED [ 50%]
|
||||
tests/test_products_auth.py::test_household_member_cannot_delete_shared_product PASSED [100%]
|
||||
|
||||
================================ tests coverage ================================
|
||||
______________ coverage: platform darwin, python 3.12.12-final-0 _______________
|
||||
|
||||
Name Stmts Miss Cover Missing
|
||||
----------------------------------------------------------------------------------
|
||||
innercontext/api/__init__.py 0 0 100%
|
||||
innercontext/api/ai_logs.py 63 34 46% 18-30, 53-57, 69-81, 106-113
|
||||
innercontext/api/auth.py 68 18 74% 65-79, 100, 106-109, 122-129, 153-158, 166
|
||||
innercontext/api/auth_deps.py 25 13 48% 23, 36-48, 52-57
|
||||
innercontext/api/authz.py 100 68 32% 25-26, 35-40, 48-51, 60-66, 78, 80, 83, 89-93, 105-108, 116-133, 141-150, 156-177
|
||||
innercontext/api/health.py 238 115 52% 77-81, 142-146, 156-163, 179-185, 195-204, 214, 231-243, 253-270, 285-298, 313-330, 341-353, 363-371, 395-464, 474-483, 493, 510-522, 532-540
|
||||
innercontext/api/inventory.py 30 13 57% 26, 36-44, 53-60
|
||||
innercontext/api/llm_context.py 102 87 15% 17-21, 30-31, 39-42, 52-74, 96-147, 174-210, 242-246
|
||||
innercontext/api/product_llm_tools.py 107 94 12% 12-17, 23-38, 48-82, 111-136, 143-162, 172-205
|
||||
innercontext/api/products.py 638 389 39% 82, 84, 88, 106-126, 281-289, 299-301, 312-387, 396-431, 515, 519-537, 541-550, 560-566, 570-571, 581-631, 649-703, 712-727, 731, 853-891, 918, 920, 922, 924, 933-934, 983, 1005-1015, 1027-1029, 1043-1048, 1060-1072, 1081-1086, 1097-1232, 1238-1240, 1244-1257, 1263, 1296-1457
|
||||
innercontext/api/profile.py 39 15 62% 36-39, 55-69
|
||||
innercontext/api/routines.py 586 402 31% 63-83, 98-102, 108-116, 126-132, 300-303, 307-324, 328-333, 343-356, 371-372, 388-398, 414-433, 442-478, 487-519, 528-555, 564-573, 577-590, 596, 609-629, 652-681, 685-691, 695-698, 789-814, 819-823, 836-1068, 1076-1246, 1252, 1257-1263, 1272-1278, 1283-1285, 1299-1304, 1313-1319, 1324-1326, 1338-1342, 1351-1357, 1362-1364
|
||||
innercontext/api/skincare.py 150 70 53% 103, 145-149, 158-166, 178-255, 267-277, 287-296, 306, 322-333, 343-350
|
||||
innercontext/api/utils.py 22 4 82% 24, 34, 51, 59
|
||||
innercontext/auth.py 236 146 38% 64-77, 127-129, 133-137, 141-149, 153-156, 161-168, 187-192, 195-210, 213-217, 220-228, 231-248, 251-264, 267, 271-274, 279, 283-284, 288-317, 325-363, 373-384
|
||||
innercontext/llm.py 134 119 11% 22, 44, 62-66, 74-102, 118-214, 231-326
|
||||
innercontext/llm_safety.py 18 14 22% 17-45, 58-61, 80-83
|
||||
innercontext/models/__init__.py 13 0 100%
|
||||
innercontext/models/ai_log.py 33 0 100%
|
||||
innercontext/models/api_metadata.py 15 0 100%
|
||||
innercontext/models/base.py 3 0 100%
|
||||
innercontext/models/domain.py 4 0 100%
|
||||
innercontext/models/enums.py 152 0 100%
|
||||
innercontext/models/health.py 64 0 100%
|
||||
innercontext/models/household.py 14 0 100%
|
||||
innercontext/models/household_membership.py 20 0 100%
|
||||
innercontext/models/pricing.py 19 0 100%
|
||||
innercontext/models/product.py 226 106 53% 76-78, 203-205, 209-230, 238-356
|
||||
innercontext/models/profile.py 17 0 100%
|
||||
innercontext/models/routine.py 42 0 100%
|
||||
innercontext/models/skincare.py 37 0 100%
|
||||
innercontext/models/user.py 19 0 100%
|
||||
innercontext/services/__init__.py 0 0 100%
|
||||
innercontext/services/fx.py 57 42 26% 16, 20-22, 26-48, 54-67, 71-77
|
||||
innercontext/services/pricing_jobs.py 62 52 16% 18-23, 27-48, 52-66, 70-85, 89-93
|
||||
innercontext/validators/__init__.py 7 0 100%
|
||||
innercontext/validators/base.py 22 5 77% 23, 27, 31, 35, 52
|
||||
innercontext/validators/batch_validator.py 128 105 18% 37, 58-154, 167-203, 214-240, 249-273
|
||||
innercontext/validators/photo_validator.py 65 54 17% 58-134, 144-152, 164-178
|
||||
innercontext/validators/product_parse_validator.py 110 93 15% 108-154, 164-172, 185-198, 205-239, 243-267, 273-319, 325-339
|
||||
innercontext/validators/routine_validator.py 146 114 22% 69-167, 173-175, 182-197, 201-218, 229-246, 259-275, 288-309
|
||||
innercontext/validators/shopping_validator.py 78 58 26% 49-96, 102-114, 122-123, 136-142, 150-161, 169-203
|
||||
----------------------------------------------------------------------------------
|
||||
TOTAL 3909 2230 43%
|
||||
Coverage HTML written to dir htmlcov
|
||||
======================= 2 passed, 6 deselected in 0.49s ========================
|
||||
63
.sisyphus/evidence/task-T5-product-sharing.txt
Normal file
63
.sisyphus/evidence/task-T5-product-sharing.txt
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
============================= test session starts ==============================
|
||||
platform darwin -- Python 3.12.12, pytest-9.0.2, pluggy-1.6.0 -- /Users/piotr/dev/innercontext/backend/.venv/bin/python3
|
||||
cachedir: .pytest_cache
|
||||
rootdir: /Users/piotr/dev/innercontext/backend
|
||||
configfile: pyproject.toml
|
||||
plugins: anyio-4.12.1, cov-7.0.0
|
||||
collecting ... collected 8 items / 5 deselected / 3 selected
|
||||
|
||||
tests/test_products_auth.py::test_shared_product_visible_in_summary_marks_is_owned_false PASSED [ 33%]
|
||||
tests/test_products_auth.py::test_shared_product_visible_filters_private_inventory_rows PASSED [ 66%]
|
||||
tests/test_products_auth.py::test_shared_inventory_update_allows_household_member PASSED [100%]
|
||||
|
||||
================================ tests coverage ================================
|
||||
______________ coverage: platform darwin, python 3.12.12-final-0 _______________
|
||||
|
||||
Name Stmts Miss Cover Missing
|
||||
----------------------------------------------------------------------------------
|
||||
innercontext/api/__init__.py 0 0 100%
|
||||
innercontext/api/ai_logs.py 63 34 46% 18-30, 53-57, 69-81, 106-113
|
||||
innercontext/api/auth.py 68 18 74% 65-79, 100, 106-109, 122-129, 153-158, 166
|
||||
innercontext/api/auth_deps.py 25 13 48% 23, 36-48, 52-57
|
||||
innercontext/api/authz.py 100 46 54% 25-26, 39, 49, 60-66, 78, 80, 83, 89-93, 105-108, 116-133, 143, 145, 147, 149, 158, 161, 164, 167, 174, 177
|
||||
innercontext/api/health.py 238 115 52% 77-81, 142-146, 156-163, 179-185, 195-204, 214, 231-243, 253-270, 285-298, 313-330, 341-353, 363-371, 395-464, 474-483, 493, 510-522, 532-540
|
||||
innercontext/api/inventory.py 30 5 83% 26, 37, 53-60
|
||||
innercontext/api/llm_context.py 102 87 15% 17-21, 30-31, 39-42, 52-74, 96-147, 174-210, 242-246
|
||||
innercontext/api/product_llm_tools.py 107 94 12% 12-17, 23-38, 48-82, 111-136, 143-162, 172-205
|
||||
innercontext/api/products.py 638 389 39% 82, 84, 88, 106-126, 281-289, 299-301, 312-387, 396-431, 515, 519-537, 541-550, 560-566, 570-571, 581-631, 649-703, 712-727, 731, 853-891, 918, 920, 922, 924, 933-934, 983, 1005-1015, 1027-1029, 1043-1048, 1060-1072, 1081-1086, 1097-1232, 1238-1240, 1244-1257, 1263, 1296-1457
|
||||
innercontext/api/profile.py 39 15 62% 36-39, 55-69
|
||||
innercontext/api/routines.py 586 402 31% 63-83, 98-102, 108-116, 126-132, 300-303, 307-324, 328-333, 343-356, 371-372, 388-398, 414-433, 442-478, 487-519, 528-555, 564-573, 577-590, 596, 609-629, 652-681, 685-691, 695-698, 789-814, 819-823, 836-1068, 1076-1246, 1252, 1257-1263, 1272-1278, 1283-1285, 1299-1304, 1313-1319, 1324-1326, 1338-1342, 1351-1357, 1362-1364
|
||||
innercontext/api/skincare.py 150 70 53% 103, 145-149, 158-166, 178-255, 267-277, 287-296, 306, 322-333, 343-350
|
||||
innercontext/api/utils.py 22 4 82% 24, 34, 51, 59
|
||||
innercontext/auth.py 236 146 38% 64-77, 127-129, 133-137, 141-149, 153-156, 161-168, 187-192, 195-210, 213-217, 220-228, 231-248, 251-264, 267, 271-274, 279, 283-284, 288-317, 325-363, 373-384
|
||||
innercontext/llm.py 134 119 11% 22, 44, 62-66, 74-102, 118-214, 231-326
|
||||
innercontext/llm_safety.py 18 14 22% 17-45, 58-61, 80-83
|
||||
innercontext/models/__init__.py 13 0 100%
|
||||
innercontext/models/ai_log.py 33 0 100%
|
||||
innercontext/models/api_metadata.py 15 0 100%
|
||||
innercontext/models/base.py 3 0 100%
|
||||
innercontext/models/domain.py 4 0 100%
|
||||
innercontext/models/enums.py 152 0 100%
|
||||
innercontext/models/health.py 64 0 100%
|
||||
innercontext/models/household.py 14 0 100%
|
||||
innercontext/models/household_membership.py 20 0 100%
|
||||
innercontext/models/pricing.py 19 0 100%
|
||||
innercontext/models/product.py 226 106 53% 76-78, 203-205, 209-230, 238-356
|
||||
innercontext/models/profile.py 17 0 100%
|
||||
innercontext/models/routine.py 42 0 100%
|
||||
innercontext/models/skincare.py 37 0 100%
|
||||
innercontext/models/user.py 19 0 100%
|
||||
innercontext/services/__init__.py 0 0 100%
|
||||
innercontext/services/fx.py 57 42 26% 16, 20-22, 26-48, 54-67, 71-77
|
||||
innercontext/services/pricing_jobs.py 62 52 16% 18-23, 27-48, 52-66, 70-85, 89-93
|
||||
innercontext/validators/__init__.py 7 0 100%
|
||||
innercontext/validators/base.py 22 5 77% 23, 27, 31, 35, 52
|
||||
innercontext/validators/batch_validator.py 128 105 18% 37, 58-154, 167-203, 214-240, 249-273
|
||||
innercontext/validators/photo_validator.py 65 54 17% 58-134, 144-152, 164-178
|
||||
innercontext/validators/product_parse_validator.py 110 93 15% 108-154, 164-172, 185-198, 205-239, 243-267, 273-319, 325-339
|
||||
innercontext/validators/routine_validator.py 146 114 22% 69-167, 173-175, 182-197, 201-218, 229-246, 259-275, 288-309
|
||||
innercontext/validators/shopping_validator.py 78 58 26% 49-96, 102-114, 122-123, 136-142, 150-161, 169-203
|
||||
----------------------------------------------------------------------------------
|
||||
TOTAL 3909 2200 44%
|
||||
Coverage HTML written to dir htmlcov
|
||||
======================= 3 passed, 5 deselected in 0.51s ========================
|
||||
62
.sisyphus/evidence/task-T6-domain-tenancy.txt
Normal file
62
.sisyphus/evidence/task-T6-domain-tenancy.txt
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
============================= test session starts ==============================
|
||||
platform darwin -- Python 3.12.12, pytest-9.0.2, pluggy-1.6.0 -- /Users/piotr/dev/innercontext/backend/.venv/bin/python3
|
||||
cachedir: .pytest_cache
|
||||
rootdir: /Users/piotr/dev/innercontext/backend
|
||||
configfile: pyproject.toml
|
||||
plugins: anyio-4.12.1, cov-7.0.0
|
||||
collecting ... collected 2 items
|
||||
|
||||
tests/test_tenancy_domains.py::test_profile_health_routines_skincare_ai_logs_are_user_scoped_by_default PASSED [ 50%]
|
||||
tests/test_tenancy_domains.py::test_health_admin_override_requires_explicit_user_id PASSED [100%]
|
||||
|
||||
================================ tests coverage ================================
|
||||
______________ coverage: platform darwin, python 3.12.12-final-0 _______________
|
||||
|
||||
Name Stmts Miss Cover Missing
|
||||
----------------------------------------------------------------------------------
|
||||
innercontext/api/__init__.py 0 0 100%
|
||||
innercontext/api/ai_logs.py 63 21 67% 18-30, 55-57, 77, 79, 109, 112-113
|
||||
innercontext/api/auth.py 68 18 74% 65-79, 100, 106-109, 122-129, 153-158, 166
|
||||
innercontext/api/auth_deps.py 25 13 48% 23, 36-48, 52-57
|
||||
innercontext/api/authz.py 100 70 30% 25-26, 31, 35-40, 48-51, 63, 66, 75-83, 89-93, 105-108, 116-133, 141-150, 156-177
|
||||
innercontext/api/health.py 236 68 71% 78, 145, 158-163, 182, 184, 231-243, 253-270, 285-298, 313-330, 341-353, 363-371, 400-401, 408, 410, 412, 414, 416, 418, 422-442, 492, 509-521, 531-539
|
||||
innercontext/api/inventory.py 30 13 57% 26, 36-44, 53-60
|
||||
innercontext/api/llm_context.py 106 58 45% 19-21, 31, 46, 59, 67, 77, 107-131, 138-149, 180-217
|
||||
innercontext/api/product_llm_tools.py 107 51 52% 12-17, 25, 31, 33, 37, 50-80, 133-134, 144, 155-161, 193
|
||||
innercontext/api/products.py 638 410 36% 81-89, 97, 106-126, 281-289, 299-301, 312-387, 396-431, 515, 519-537, 541-550, 560-566, 570-571, 581-631, 649-703, 714, 731, 853-891, 904-972, 981-992, 1002-1015, 1024-1029, 1043-1048, 1060-1072, 1081-1086, 1097-1232, 1238-1240, 1244-1257, 1263, 1296-1457
|
||||
innercontext/api/profile.py 39 3 92% 39, 62-63
|
||||
innercontext/api/routines.py 632 285 55% 67-84, 101-103, 112-117, 129-133, 309, 311, 313, 315, 319-324, 330, 334, 355, 398-399, 415-434, 451-479, 498-520, 552, 555, 559, 561, 563, 577-581, 587-600, 606, 620, 640-641, 664-693, 698, 709-710, 715, 719-721, 817, 819, 821, 827-833, 837-841, 927-929, 986-1002, 1019, 1023-1024, 1030, 1033, 1039, 1064-1065, 1069, 1115-1119, 1130, 1143-1348, 1358-1359, 1379-1386, 1397-1409, 1419-1427, 1443-1464, 1475-1491, 1501-1509, 1524-1529, 1540-1552, 1562-1570
|
||||
innercontext/api/skincare.py 150 53 65% 103, 147-149, 162-166, 178-255, 272, 274, 276, 322-333, 343-350
|
||||
innercontext/api/utils.py 22 7 68% 22-25, 43, 51, 59
|
||||
innercontext/auth.py 236 146 38% 64-77, 127-129, 133-137, 141-149, 153-156, 161-168, 187-192, 195-210, 213-217, 220-228, 231-248, 251-264, 267, 271-274, 279, 283-284, 288-317, 325-363, 373-384
|
||||
innercontext/llm.py 134 118 12% 22, 62-66, 74-102, 118-214, 231-326
|
||||
innercontext/llm_safety.py 18 14 22% 17-45, 58-61, 80-83
|
||||
innercontext/models/__init__.py 13 0 100%
|
||||
innercontext/models/ai_log.py 33 0 100%
|
||||
innercontext/models/api_metadata.py 15 0 100%
|
||||
innercontext/models/base.py 3 0 100%
|
||||
innercontext/models/domain.py 4 0 100%
|
||||
innercontext/models/enums.py 152 0 100%
|
||||
innercontext/models/health.py 64 0 100%
|
||||
innercontext/models/household.py 14 0 100%
|
||||
innercontext/models/household_membership.py 20 0 100%
|
||||
innercontext/models/pricing.py 19 0 100%
|
||||
innercontext/models/product.py 226 67 70% 78, 203-205, 209-230, 250, 253, 255, 257, 259, 261, 263, 265, 267, 269, 271, 273, 275-288, 291-298, 304, 306, 309-315, 318, 320, 331, 333, 336, 338, 340, 342, 349-354
|
||||
innercontext/models/profile.py 17 0 100%
|
||||
innercontext/models/routine.py 42 0 100%
|
||||
innercontext/models/skincare.py 37 0 100%
|
||||
innercontext/models/user.py 19 0 100%
|
||||
innercontext/services/__init__.py 0 0 100%
|
||||
innercontext/services/fx.py 57 42 26% 16, 20-22, 26-48, 54-67, 71-77
|
||||
innercontext/services/pricing_jobs.py 89 71 20% 28-49, 53-67, 71-80, 89-107, 111-130, 134-138
|
||||
innercontext/validators/__init__.py 7 0 100%
|
||||
innercontext/validators/base.py 22 3 86% 27, 35, 52
|
||||
innercontext/validators/batch_validator.py 128 105 18% 37, 58-154, 167-203, 214-240, 249-273
|
||||
innercontext/validators/photo_validator.py 65 54 17% 58-134, 144-152, 164-178
|
||||
innercontext/validators/product_parse_validator.py 110 93 15% 108-154, 164-172, 185-198, 205-239, 243-267, 273-319, 325-339
|
||||
innercontext/validators/routine_validator.py 146 90 38% 72-73, 92-95, 98-101, 107-147, 151, 158, 175, 182-197, 201-218, 229-246, 259-275, 288-309
|
||||
innercontext/validators/shopping_validator.py 78 58 26% 49-96, 102-114, 122-123, 136-142, 150-161, 169-203
|
||||
----------------------------------------------------------------------------------
|
||||
TOTAL 3984 1931 52%
|
||||
Coverage HTML written to dir htmlcov
|
||||
============================== 2 passed in 0.49s ===============================
|
||||
61
.sisyphus/evidence/task-T6-routine-scope.txt
Normal file
61
.sisyphus/evidence/task-T6-routine-scope.txt
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
============================= test session starts ==============================
|
||||
platform darwin -- Python 3.12.12, pytest-9.0.2, pluggy-1.6.0 -- /Users/piotr/dev/innercontext/backend/.venv/bin/python3
|
||||
cachedir: .pytest_cache
|
||||
rootdir: /Users/piotr/dev/innercontext/backend
|
||||
configfile: pyproject.toml
|
||||
plugins: anyio-4.12.1, cov-7.0.0
|
||||
collecting ... collected 1 item
|
||||
|
||||
tests/test_routines_auth.py::test_suggest_uses_current_user_profile_and_visible_products_only PASSED [100%]
|
||||
|
||||
================================ tests coverage ================================
|
||||
______________ coverage: platform darwin, python 3.12.12-final-0 _______________
|
||||
|
||||
Name Stmts Miss Cover Missing
|
||||
----------------------------------------------------------------------------------
|
||||
innercontext/api/__init__.py 0 0 100%
|
||||
innercontext/api/ai_logs.py 63 34 46% 18-30, 53-57, 69-81, 106-113
|
||||
innercontext/api/auth.py 68 18 74% 65-79, 100, 106-109, 122-129, 153-158, 166
|
||||
innercontext/api/auth_deps.py 25 13 48% 23, 36-48, 52-57
|
||||
innercontext/api/authz.py 100 79 21% 16, 20, 24-27, 31, 35-40, 48-51, 60-66, 75-83, 89-93, 105-108, 116-133, 141-150, 156-177
|
||||
innercontext/api/health.py 236 113 52% 77-81, 142-146, 156-163, 179-185, 195-204, 214, 231-243, 253-270, 285-298, 313-330, 341-353, 363-371, 395-463, 473-482, 492, 509-521, 531-539
|
||||
innercontext/api/inventory.py 30 13 57% 26, 36-44, 53-60
|
||||
innercontext/api/llm_context.py 106 58 45% 19-21, 31, 46, 59, 67, 77, 107-131, 138-149, 180-217
|
||||
innercontext/api/product_llm_tools.py 107 51 52% 12-17, 25, 31, 33, 37, 50-80, 133-134, 144, 155-161, 193
|
||||
innercontext/api/products.py 638 410 36% 81-89, 97, 106-126, 281-289, 299-301, 312-387, 396-431, 515, 519-537, 541-550, 560-566, 570-571, 581-631, 649-703, 714, 731, 853-891, 904-972, 981-992, 1002-1015, 1024-1029, 1043-1048, 1060-1072, 1081-1086, 1097-1232, 1238-1240, 1244-1257, 1263, 1296-1457
|
||||
innercontext/api/profile.py 39 3 92% 39, 62-63
|
||||
innercontext/api/routines.py 632 285 55% 67-84, 101-103, 112-117, 129-133, 309, 311, 313, 315, 319-324, 330, 334, 355, 398-399, 415-434, 451-479, 498-520, 552, 555, 559, 561, 563, 577-581, 587-600, 606, 620, 640-641, 664-693, 698, 709-710, 715, 719-721, 817, 819, 821, 827-833, 837-841, 927-929, 986-1002, 1019, 1023-1024, 1030, 1033, 1039, 1064-1065, 1069, 1115-1119, 1130, 1143-1348, 1358-1359, 1379-1386, 1397-1409, 1419-1427, 1443-1464, 1475-1491, 1501-1509, 1524-1529, 1540-1552, 1562-1570
|
||||
innercontext/api/skincare.py 150 53 65% 103, 147-149, 162-166, 178-255, 272, 274, 276, 322-333, 343-350
|
||||
innercontext/api/utils.py 22 7 68% 22-25, 43, 51, 59
|
||||
innercontext/auth.py 236 146 38% 64-77, 127-129, 133-137, 141-149, 153-156, 161-168, 187-192, 195-210, 213-217, 220-228, 231-248, 251-264, 267, 271-274, 279, 283-284, 288-317, 325-363, 373-384
|
||||
innercontext/llm.py 134 118 12% 22, 62-66, 74-102, 118-214, 231-326
|
||||
innercontext/llm_safety.py 18 14 22% 17-45, 58-61, 80-83
|
||||
innercontext/models/__init__.py 13 0 100%
|
||||
innercontext/models/ai_log.py 33 0 100%
|
||||
innercontext/models/api_metadata.py 15 0 100%
|
||||
innercontext/models/base.py 3 0 100%
|
||||
innercontext/models/domain.py 4 0 100%
|
||||
innercontext/models/enums.py 152 0 100%
|
||||
innercontext/models/health.py 64 0 100%
|
||||
innercontext/models/household.py 14 0 100%
|
||||
innercontext/models/household_membership.py 20 0 100%
|
||||
innercontext/models/pricing.py 19 0 100%
|
||||
innercontext/models/product.py 226 67 70% 78, 203-205, 209-230, 250, 253, 255, 257, 259, 261, 263, 265, 267, 269, 271, 273, 275-288, 291-298, 304, 306, 309-315, 318, 320, 331, 333, 336, 338, 340, 342, 349-354
|
||||
innercontext/models/profile.py 17 0 100%
|
||||
innercontext/models/routine.py 42 0 100%
|
||||
innercontext/models/skincare.py 37 0 100%
|
||||
innercontext/models/user.py 19 0 100%
|
||||
innercontext/services/__init__.py 0 0 100%
|
||||
innercontext/services/fx.py 57 42 26% 16, 20-22, 26-48, 54-67, 71-77
|
||||
innercontext/services/pricing_jobs.py 89 71 20% 28-49, 53-67, 71-80, 89-107, 111-130, 134-138
|
||||
innercontext/validators/__init__.py 7 0 100%
|
||||
innercontext/validators/base.py 22 3 86% 27, 35, 52
|
||||
innercontext/validators/batch_validator.py 128 105 18% 37, 58-154, 167-203, 214-240, 249-273
|
||||
innercontext/validators/photo_validator.py 65 54 17% 58-134, 144-152, 164-178
|
||||
innercontext/validators/product_parse_validator.py 110 93 15% 108-154, 164-172, 185-198, 205-239, 243-267, 273-319, 325-339
|
||||
innercontext/validators/routine_validator.py 146 90 38% 72-73, 92-95, 98-101, 107-147, 151, 158, 175, 182-197, 201-218, 229-246, 259-275, 288-309
|
||||
innercontext/validators/shopping_validator.py 78 58 26% 49-96, 102-114, 122-123, 136-142, 150-161, 169-203
|
||||
----------------------------------------------------------------------------------
|
||||
TOTAL 3984 1998 50%
|
||||
Coverage HTML written to dir htmlcov
|
||||
============================== 1 passed in 0.47s ===============================
|
||||
158
.sisyphus/evidence/task-T8-backend-qa.log
Normal file
158
.sisyphus/evidence/task-T8-backend-qa.log
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
INFO: Started server process [65594]
|
||||
INFO: Waiting for application startup.
|
||||
INFO: Application startup complete.
|
||||
INFO: Uvicorn running on http://127.0.0.1:8001 (Press CTRL+C to quit)
|
||||
INFO: 127.0.0.1:56744 - "GET /health-check HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56751 - "GET /health-check HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56758 - "GET /health-check HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56764 - "GET /health-check HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56770 - "GET /health-check HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56776 - "GET /health-check HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56782 - "GET /health-check HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56788 - "GET /health-check HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56794 - "GET /health-check HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56800 - "GET /health-check HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56806 - "GET /health-check HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56813 - "GET /health-check HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56820 - "GET /health-check HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56826 - "GET /health-check HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56832 - "GET /health-check HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56838 - "GET /health-check HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56844 - "GET /health-check HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56850 - "GET /health-check HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56856 - "GET /health-check HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56862 - "GET /health-check HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56868 - "GET /health-check HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56874 - "GET /health-check HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56880 - "GET /health-check HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56887 - "GET /health-check HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56893 - "GET /health-check HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56899 - "GET /health-check HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56905 - "GET /health-check HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56911 - "GET /health-check HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56917 - "GET /health-check HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56923 - "GET /health-check HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56940 - "POST /auth/session/sync HTTP/1.1" 500 Internal Server Error
|
||||
ERROR: Exception in ASGI application
|
||||
Traceback (most recent call last):
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1967, in _exec_single_context
|
||||
self.dialect.do_execute(
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/sqlalchemy/engine/default.py", line 952, in do_execute
|
||||
cursor.execute(statement, parameters)
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/psycopg/cursor.py", line 117, in execute
|
||||
raise ex.with_traceback(None)
|
||||
psycopg.errors.UndefinedColumn: column user_profiles.user_id does not exist
|
||||
LINE 1: SELECT user_profiles.id, user_profiles.user_id, user_profile...
|
||||
^
|
||||
|
||||
The above exception was the direct cause of the following exception:
|
||||
|
||||
Traceback (most recent call last):
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 416, in run_asgi
|
||||
result = await app( # type: ignore[func-returns-value]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 60, in __call__
|
||||
return await self.app(scope, receive, send)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/fastapi/applications.py", line 1158, in __call__
|
||||
await super().__call__(scope, receive, send)
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/starlette/applications.py", line 107, in __call__
|
||||
await self.middleware_stack(scope, receive, send)
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 186, in __call__
|
||||
raise exc
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 164, in __call__
|
||||
await self.app(scope, receive, _send)
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/starlette/middleware/cors.py", line 87, in __call__
|
||||
await self.app(scope, receive, send)
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 63, in __call__
|
||||
await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
|
||||
raise exc
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app
|
||||
await app(scope, receive, sender)
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__
|
||||
await self.app(scope, receive, send)
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/starlette/routing.py", line 716, in __call__
|
||||
await self.middleware_stack(scope, receive, send)
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/starlette/routing.py", line 736, in app
|
||||
await route.handle(scope, receive, send)
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/starlette/routing.py", line 290, in handle
|
||||
await self.app(scope, receive, send)
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/fastapi/routing.py", line 119, in app
|
||||
await wrap_app_handling_exceptions(app, request)(scope, receive, send)
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
|
||||
raise exc
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app
|
||||
await app(scope, receive, sender)
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/fastapi/routing.py", line 105, in app
|
||||
response = await f(request)
|
||||
^^^^^^^^^^^^^^^^
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/fastapi/routing.py", line 431, in app
|
||||
raw_response = await run_endpoint_function(
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/fastapi/routing.py", line 315, in run_endpoint_function
|
||||
return await run_in_threadpool(dependant.call, **values)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/starlette/concurrency.py", line 32, in run_in_threadpool
|
||||
return await anyio.to_thread.run_sync(func)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/anyio/to_thread.py", line 63, in run_sync
|
||||
return await get_async_backend().run_sync_in_worker_thread(
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/anyio/_backends/_asyncio.py", line 2502, in run_sync_in_worker_thread
|
||||
return await future
|
||||
^^^^^^^^^^^^
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/anyio/_backends/_asyncio.py", line 986, in run
|
||||
result = context.run(func, *args)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/Users/piotr/dev/innercontext/backend/innercontext/api/auth.py", line 158, in sync_session
|
||||
return _response(session, synced_user)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/Users/piotr/dev/innercontext/backend/innercontext/api/auth.py", line 143, in _response
|
||||
profile=_profile_public(_get_profile(session, current_user.user_id)),
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/Users/piotr/dev/innercontext/backend/innercontext/api/auth.py", line 100, in _get_profile
|
||||
return session.exec(
|
||||
^^^^^^^^^^^^^
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/sqlmodel/orm/session.py", line 75, in exec
|
||||
results = super().execute(
|
||||
^^^^^^^^^^^^^^^^
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 2351, in execute
|
||||
return self._execute_internal(
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 2249, in _execute_internal
|
||||
result: Result[Any] = compile_state_cls.orm_execute_statement(
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/sqlalchemy/orm/context.py", line 306, in orm_execute_statement
|
||||
result = conn.execute(
|
||||
^^^^^^^^^^^^^
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1419, in execute
|
||||
return meth(
|
||||
^^^^^
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/sqlalchemy/sql/elements.py", line 527, in _execute_on_connection
|
||||
return connection._execute_clauseelement(
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1641, in _execute_clauseelement
|
||||
ret = self._execute_context(
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1846, in _execute_context
|
||||
return self._exec_single_context(
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1986, in _exec_single_context
|
||||
self._handle_dbapi_exception(
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 2363, in _handle_dbapi_exception
|
||||
raise sqlalchemy_exception.with_traceback(exc_info[2]) from e
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1967, in _exec_single_context
|
||||
self.dialect.do_execute(
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/sqlalchemy/engine/default.py", line 952, in do_execute
|
||||
cursor.execute(statement, parameters)
|
||||
File "/Users/piotr/dev/innercontext/backend/.venv/lib/python3.12/site-packages/psycopg/cursor.py", line 117, in execute
|
||||
raise ex.with_traceback(None)
|
||||
sqlalchemy.exc.ProgrammingError: (psycopg.errors.UndefinedColumn) column user_profiles.user_id does not exist
|
||||
LINE 1: SELECT user_profiles.id, user_profiles.user_id, user_profile...
|
||||
^
|
||||
[SQL: SELECT user_profiles.id, user_profiles.user_id, user_profiles.birth_date, user_profiles.sex_at_birth, user_profiles.created_at, user_profiles.updated_at
|
||||
FROM user_profiles
|
||||
WHERE user_profiles.user_id = %(user_id_1)s::UUID]
|
||||
[parameters: {'user_id_1': UUID('c6968c10-98af-4a32-a794-708aca0cc362')}]
|
||||
(Background on this error at: https://sqlalche.me/e/20/f405)
|
||||
40
.sisyphus/evidence/task-T8-backend-sqlite.log
Normal file
40
.sisyphus/evidence/task-T8-backend-sqlite.log
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
INFO: Started server process [67156]
|
||||
INFO: Waiting for application startup.
|
||||
INFO: Application startup complete.
|
||||
INFO: Uvicorn running on http://127.0.0.1:8002 (Press CTRL+C to quit)
|
||||
INFO: 127.0.0.1:56962 - "GET /health-check HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:56974 - "POST /auth/session/sync HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57014 - "GET /routines?from_date=2026-02-26 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57015 - "GET /skincare?from_date=2026-01-11 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57016 - "GET /health/lab-results?latest_only=true&limit=8 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57024 - "GET /routines?from_date=2026-02-26 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57025 - "GET /skincare?from_date=2026-01-11 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57026 - "GET /health/lab-results?latest_only=true&limit=8 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57035 - "GET /routines?from_date=2026-02-26 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57036 - "GET /skincare?from_date=2026-01-11 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57037 - "GET /health/lab-results?latest_only=true&limit=8 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57035 - "GET /products/summary HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57035 - "GET /profile HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57035 - "GET /routines?from_date=2026-02-10 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57075 - "POST /auth/session/sync HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57075 - "GET /products/summary HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57089 - "POST /auth/session/sync HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57089 - "GET /routines?from_date=2026-02-26 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57090 - "GET /skincare?from_date=2026-01-11 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57091 - "GET /health/lab-results?latest_only=true&limit=8 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57089 - "GET /products/summary HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57109 - "POST /auth/session/sync HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57109 - "GET /routines?from_date=2026-02-26 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57110 - "GET /skincare?from_date=2026-01-11 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57111 - "GET /health/lab-results?latest_only=true&limit=8 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57166 - "GET /routines?from_date=2026-02-26 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57167 - "GET /skincare?from_date=2026-01-11 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57168 - "GET /health/lab-results?latest_only=true&limit=8 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57182 - "POST /auth/session/sync HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57182 - "GET /routines?from_date=2026-02-26 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57183 - "GET /skincare?from_date=2026-01-11 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57184 - "GET /health/lab-results?latest_only=true&limit=8 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57182 - "GET /routines?from_date=2026-02-26 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57183 - "GET /skincare?from_date=2026-01-11 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57184 - "GET /health/lab-results?latest_only=true&limit=8 HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:57401 - "GET /profile HTTP/1.1" 200 OK
|
||||
5
.sisyphus/evidence/task-T8-backend.log
Normal file
5
.sisyphus/evidence/task-T8-backend.log
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
INFO: Started server process [63874]
|
||||
INFO: Waiting for application startup.
|
||||
INFO: Application startup complete.
|
||||
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
INFO: 127.0.0.1:56616 - "GET /health-check HTTP/1.1" 200 OK
|
||||
44
.sisyphus/evidence/task-T8-frontend-qa.log
Normal file
44
.sisyphus/evidence/task-T8-frontend-qa.log
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
|
||||
> frontend@0.0.1 dev /Users/piotr/dev/innercontext/frontend
|
||||
> vite dev --host 127.0.0.1 --port 4174
|
||||
|
||||
✔ [paraglide-js] Compilation complete (locale-modules)
|
||||
|
||||
VITE v7.3.1 ready in 1355 ms
|
||||
|
||||
➜ Local: http://127.0.0.1:4174/
|
||||
|
||||
[1;31m[404] GET /favicon.ico[0m
|
||||
16:19:52 [vite] (ssr) page reload .svelte-kit/generated/server/internal.js
|
||||
16:19:52 [vite] (ssr) page reload .svelte-kit/generated/root.svelte
|
||||
16:19:52 [vite] (ssr) page reload .svelte-kit/generated/root.js
|
||||
16:19:53 [vite] (ssr) page reload src/lib/paraglide/server.js
|
||||
16:19:53 [vite] (ssr) page reload src/lib/paraglide/registry.js
|
||||
16:19:53 [vite] (ssr) page reload src/lib/paraglide/messages.js
|
||||
16:19:53 [vite] (ssr) page reload src/lib/paraglide/runtime.js
|
||||
16:19:53 [vite] (ssr) page reload src/lib/paraglide/messages/_index.js
|
||||
16:19:53 [vite] (ssr) page reload src/lib/paraglide/messages/en.js
|
||||
16:19:53 [vite] (ssr) page reload src/lib/paraglide/messages/pl.js
|
||||
16:19:53 [vite] (ssr) page reload src/lib/paraglide/messages/en.js
|
||||
16:19:53 [vite] (ssr) page reload src/lib/paraglide/messages/pl.js
|
||||
16:19:53 [vite] (ssr) page reload src/lib/paraglide/server.js
|
||||
16:19:53 [vite] (ssr) page reload src/lib/paraglide/messages.js
|
||||
16:19:53 [vite] (ssr) page reload src/lib/paraglide/runtime.js
|
||||
16:19:53 [vite] (ssr) page reload src/lib/paraglide/messages/pl.js
|
||||
16:19:53 [vite] (ssr) page reload src/lib/paraglide/registry.js
|
||||
16:19:53 [vite] (ssr) page reload src/lib/paraglide/messages/_index.js
|
||||
16:19:53 [vite] (ssr) page reload src/lib/paraglide/messages/en.js
|
||||
16:21:17 [vite] (ssr) page reload src/lib/api.ts
|
||||
16:23:49 [vite] (ssr) page reload src/routes/+layout.svelte
|
||||
16:24:41 [vite] (ssr) page reload .svelte-kit/generated/server/internal.js
|
||||
16:24:41 [vite] (ssr) page reload .svelte-kit/generated/root.svelte
|
||||
16:24:41 [vite] (ssr) page reload .svelte-kit/generated/root.js
|
||||
16:24:42 [vite] (ssr) page reload src/lib/paraglide/runtime.js
|
||||
16:24:42 [vite] (ssr) page reload src/lib/paraglide/server.js
|
||||
16:24:42 [vite] (ssr) page reload src/lib/paraglide/registry.js
|
||||
16:24:42 [vite] (ssr) page reload src/lib/paraglide/messages.js
|
||||
16:24:42 [vite] (ssr) page reload src/lib/paraglide/messages/en.js
|
||||
16:24:42 [vite] (ssr) page reload src/lib/paraglide/messages/_index.js
|
||||
16:24:42 [vite] (ssr) page reload src/lib/paraglide/messages/pl.js
|
||||
16:24:42 [vite] (ssr) page reload src/lib/paraglide/messages/_index.js
|
||||
16:24:42 [vite] (ssr) page reload src/lib/paraglide/messages/_index.js
|
||||
56
.sisyphus/evidence/task-T8-frontend-sqlite.log
Normal file
56
.sisyphus/evidence/task-T8-frontend-sqlite.log
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
|
||||
> frontend@0.0.1 dev /Users/piotr/dev/innercontext/frontend
|
||||
> vite dev --host 127.0.0.1 --port 4175
|
||||
|
||||
✔ [paraglide-js] Compilation complete (locale-modules)
|
||||
|
||||
VITE v7.3.1 ready in 1402 ms
|
||||
|
||||
➜ Local: http://127.0.0.1:4175/
|
||||
|
||||
[1;31m[404] GET /api/routines[0m
|
||||
|
||||
[1;31m[404] GET /api/skincare[0m
|
||||
|
||||
[1;31m[404] GET /api/health/lab-results[0m
|
||||
|
||||
[1;31m[500] GET /[0m
|
||||
Error: Not Found
|
||||
at request (src/lib/api.ts:68:11)
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
|
||||
at async Promise.all (index 0)
|
||||
at async load (src/routes/+page.server.ts:9:44)
|
||||
|
||||
[1;31m[404] GET /favicon.ico[0m
|
||||
16:21:17 [vite] (ssr) page reload src/lib/api.ts
|
||||
Avoid calling `fetch` eagerly during server-side rendering — put your `fetch` calls inside `onMount` or a `load` function instead
|
||||
Avoid calling `fetch` eagerly during server-side rendering — put your `fetch` calls inside `onMount` or a `load` function instead
|
||||
16:23:49 [vite] (client) hmr update /src/routes/+layout.svelte, /src/app.css
|
||||
16:23:49 [vite] (ssr) page reload src/routes/+layout.svelte
|
||||
16:24:41 [vite] (client) page reload .svelte-kit/generated/client/nodes/0.js
|
||||
16:24:41 [vite] (client) page reload .svelte-kit/generated/client/nodes/1.js
|
||||
16:24:41 [vite] (client) page reload .svelte-kit/generated/client/nodes/2.js
|
||||
16:24:41 [vite] (client) page reload .svelte-kit/generated/client/nodes/7.js
|
||||
16:24:41 [vite] (client) page reload .svelte-kit/generated/client/nodes/11.js
|
||||
16:24:41 [vite] (client) page reload .svelte-kit/generated/client/nodes/12.js
|
||||
16:24:41 [vite] (client) page reload .svelte-kit/generated/client/app.js
|
||||
16:24:41 [vite] (client) page reload .svelte-kit/generated/client/matchers.js
|
||||
16:24:41 [vite] (ssr) page reload .svelte-kit/generated/server/internal.js
|
||||
16:24:41 [vite] (client) page reload .svelte-kit/generated/root.js
|
||||
16:24:41 [vite] (ssr) page reload .svelte-kit/generated/root.js
|
||||
16:24:41 [vite] (ssr) page reload .svelte-kit/generated/root.svelte
|
||||
16:24:42 [vite] (client) hmr update /src/lib/components/LanguageSwitcher.svelte, /src/routes/+layout.svelte, /src/routes/+page.svelte, /src/routes/products/+page.svelte, /src/routes/profile/+page.svelte, /src/routes/routines/+page.svelte
|
||||
16:24:42 [vite] (ssr) page reload src/lib/paraglide/runtime.js
|
||||
16:24:42 [vite] (ssr) page reload src/lib/paraglide/server.js
|
||||
16:24:42 [vite] (client) hmr update /src/routes/+layout.svelte, /src/routes/+page.svelte, /src/routes/products/+page.svelte, /src/routes/profile/+page.svelte, /src/routes/routines/+page.svelte
|
||||
16:24:42 [vite] (ssr) page reload src/lib/paraglide/registry.js
|
||||
16:24:42 [vite] (client) hmr update /src/routes/+layout.svelte, /src/routes/+page.svelte, /src/routes/products/+page.svelte, /src/routes/profile/+page.svelte, /src/routes/routines/+page.svelte
|
||||
16:24:42 [vite] (ssr) page reload src/lib/paraglide/messages.js
|
||||
16:24:42 [vite] (client) hmr update /src/routes/+layout.svelte, /src/routes/+page.svelte, /src/routes/products/+page.svelte, /src/routes/profile/+page.svelte, /src/routes/routines/+page.svelte
|
||||
16:24:42 [vite] (ssr) page reload src/lib/paraglide/messages/_index.js
|
||||
16:24:42 [vite] (client) page reload src/lib/paraglide/messages/en.js
|
||||
16:24:42 [vite] (ssr) page reload src/lib/paraglide/messages/en.js
|
||||
16:24:42 [vite] (client) page reload src/lib/paraglide/messages/pl.js
|
||||
16:24:42 [vite] (ssr) page reload src/lib/paraglide/messages/pl.js
|
||||
16:24:42 [vite] (client) hmr update /src/routes/+layout.svelte, /src/routes/+page.svelte, /src/routes/products/+page.svelte, /src/routes/profile/+page.svelte, /src/routes/routines/+page.svelte
|
||||
16:24:42 [vite] (ssr) page reload src/lib/paraglide/messages/_index.js
|
||||
228
.sisyphus/evidence/task-T8-frontend.log
Normal file
228
.sisyphus/evidence/task-T8-frontend.log
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
|
||||
> frontend@0.0.1 dev /Users/piotr/dev/innercontext/frontend
|
||||
> vite dev --host 127.0.0.1 --port 4173
|
||||
|
||||
✔ [paraglide-js] Compilation complete (locale-modules)
|
||||
16:14:07 [vite] (client) Re-optimizing dependencies because lockfile has changed
|
||||
|
||||
VITE v7.3.1 ready in 1541 ms
|
||||
|
||||
➜ Local: http://127.0.0.1:4173/
|
||||
|
||||
[1;31m[500] GET /auth/login[0m
|
||||
Error: Missing required auth environment variable: OIDC_ISSUER
|
||||
at requiredEnv (src/lib/server/auth.ts:111:11)
|
||||
at getAuthConfig (src/lib/server/auth.ts:94:18)
|
||||
at getSecretKey (src/lib/server/auth.ts:136:22)
|
||||
at encryptValue (src/lib/server/auth.ts:160:15)
|
||||
at setLoginFlowCookie (src/lib/server/auth.ts:514:5)
|
||||
at createLoginRedirect (src/lib/server/auth.ts:533:3)
|
||||
at GET (src/routes/auth/login/+server.ts:6:26)
|
||||
|
||||
[1;31m[500] GET /auth/login[0m
|
||||
Error: Missing required auth environment variable: OIDC_ISSUER
|
||||
at requiredEnv (src/lib/server/auth.ts:111:11)
|
||||
at getAuthConfig (src/lib/server/auth.ts:94:18)
|
||||
at getSecretKey (src/lib/server/auth.ts:136:22)
|
||||
at encryptValue (src/lib/server/auth.ts:160:15)
|
||||
at setLoginFlowCookie (src/lib/server/auth.ts:514:5)
|
||||
at createLoginRedirect (src/lib/server/auth.ts:533:3)
|
||||
at GET (src/routes/auth/login/+server.ts:6:26)
|
||||
|
||||
[1;31m[500] GET /auth/login[0m
|
||||
Error: Missing required auth environment variable: OIDC_ISSUER
|
||||
at requiredEnv (src/lib/server/auth.ts:111:11)
|
||||
at getAuthConfig (src/lib/server/auth.ts:94:18)
|
||||
at getSecretKey (src/lib/server/auth.ts:136:22)
|
||||
at encryptValue (src/lib/server/auth.ts:160:15)
|
||||
at setLoginFlowCookie (src/lib/server/auth.ts:514:5)
|
||||
at createLoginRedirect (src/lib/server/auth.ts:533:3)
|
||||
at GET (src/routes/auth/login/+server.ts:6:26)
|
||||
|
||||
[1;31m[500] GET /auth/login[0m
|
||||
Error: Missing required auth environment variable: OIDC_ISSUER
|
||||
at requiredEnv (src/lib/server/auth.ts:111:11)
|
||||
at getAuthConfig (src/lib/server/auth.ts:94:18)
|
||||
at getSecretKey (src/lib/server/auth.ts:136:22)
|
||||
at encryptValue (src/lib/server/auth.ts:160:15)
|
||||
at setLoginFlowCookie (src/lib/server/auth.ts:514:5)
|
||||
at createLoginRedirect (src/lib/server/auth.ts:533:3)
|
||||
at GET (src/routes/auth/login/+server.ts:6:26)
|
||||
|
||||
[1;31m[500] GET /auth/login[0m
|
||||
Error: Missing required auth environment variable: OIDC_ISSUER
|
||||
at requiredEnv (src/lib/server/auth.ts:111:11)
|
||||
at getAuthConfig (src/lib/server/auth.ts:94:18)
|
||||
at getSecretKey (src/lib/server/auth.ts:136:22)
|
||||
at encryptValue (src/lib/server/auth.ts:160:15)
|
||||
at setLoginFlowCookie (src/lib/server/auth.ts:514:5)
|
||||
at createLoginRedirect (src/lib/server/auth.ts:533:3)
|
||||
at GET (src/routes/auth/login/+server.ts:6:26)
|
||||
|
||||
[1;31m[500] GET /auth/login[0m
|
||||
Error: Missing required auth environment variable: OIDC_ISSUER
|
||||
at requiredEnv (src/lib/server/auth.ts:111:11)
|
||||
at getAuthConfig (src/lib/server/auth.ts:94:18)
|
||||
at getSecretKey (src/lib/server/auth.ts:136:22)
|
||||
at encryptValue (src/lib/server/auth.ts:160:15)
|
||||
at setLoginFlowCookie (src/lib/server/auth.ts:514:5)
|
||||
at createLoginRedirect (src/lib/server/auth.ts:533:3)
|
||||
at GET (src/routes/auth/login/+server.ts:6:26)
|
||||
|
||||
[1;31m[500] GET /auth/login[0m
|
||||
Error: Missing required auth environment variable: OIDC_ISSUER
|
||||
at requiredEnv (src/lib/server/auth.ts:111:11)
|
||||
at getAuthConfig (src/lib/server/auth.ts:94:18)
|
||||
at getSecretKey (src/lib/server/auth.ts:136:22)
|
||||
at encryptValue (src/lib/server/auth.ts:160:15)
|
||||
at setLoginFlowCookie (src/lib/server/auth.ts:514:5)
|
||||
at createLoginRedirect (src/lib/server/auth.ts:533:3)
|
||||
at GET (src/routes/auth/login/+server.ts:6:26)
|
||||
|
||||
[1;31m[500] GET /auth/login[0m
|
||||
Error: Missing required auth environment variable: OIDC_ISSUER
|
||||
at requiredEnv (src/lib/server/auth.ts:111:11)
|
||||
at getAuthConfig (src/lib/server/auth.ts:94:18)
|
||||
at getSecretKey (src/lib/server/auth.ts:136:22)
|
||||
at encryptValue (src/lib/server/auth.ts:160:15)
|
||||
at setLoginFlowCookie (src/lib/server/auth.ts:514:5)
|
||||
at createLoginRedirect (src/lib/server/auth.ts:533:3)
|
||||
at GET (src/routes/auth/login/+server.ts:6:26)
|
||||
|
||||
[1;31m[500] GET /auth/login[0m
|
||||
Error: Missing required auth environment variable: OIDC_ISSUER
|
||||
at requiredEnv (src/lib/server/auth.ts:111:11)
|
||||
at getAuthConfig (src/lib/server/auth.ts:94:18)
|
||||
at getSecretKey (src/lib/server/auth.ts:136:22)
|
||||
at encryptValue (src/lib/server/auth.ts:160:15)
|
||||
at setLoginFlowCookie (src/lib/server/auth.ts:514:5)
|
||||
at createLoginRedirect (src/lib/server/auth.ts:533:3)
|
||||
at GET (src/routes/auth/login/+server.ts:6:26)
|
||||
|
||||
[1;31m[500] GET /auth/login[0m
|
||||
Error: Missing required auth environment variable: OIDC_ISSUER
|
||||
at requiredEnv (src/lib/server/auth.ts:111:11)
|
||||
at getAuthConfig (src/lib/server/auth.ts:94:18)
|
||||
at getSecretKey (src/lib/server/auth.ts:136:22)
|
||||
at encryptValue (src/lib/server/auth.ts:160:15)
|
||||
at setLoginFlowCookie (src/lib/server/auth.ts:514:5)
|
||||
at createLoginRedirect (src/lib/server/auth.ts:533:3)
|
||||
at GET (src/routes/auth/login/+server.ts:6:26)
|
||||
|
||||
[1;31m[500] GET /auth/login[0m
|
||||
Error: Missing required auth environment variable: OIDC_ISSUER
|
||||
at requiredEnv (src/lib/server/auth.ts:111:11)
|
||||
at getAuthConfig (src/lib/server/auth.ts:94:18)
|
||||
at getSecretKey (src/lib/server/auth.ts:136:22)
|
||||
at encryptValue (src/lib/server/auth.ts:160:15)
|
||||
at setLoginFlowCookie (src/lib/server/auth.ts:514:5)
|
||||
at createLoginRedirect (src/lib/server/auth.ts:533:3)
|
||||
at GET (src/routes/auth/login/+server.ts:6:26)
|
||||
|
||||
[1;31m[500] GET /auth/login[0m
|
||||
Error: Missing required auth environment variable: OIDC_ISSUER
|
||||
at requiredEnv (src/lib/server/auth.ts:111:11)
|
||||
at getAuthConfig (src/lib/server/auth.ts:94:18)
|
||||
at getSecretKey (src/lib/server/auth.ts:136:22)
|
||||
at encryptValue (src/lib/server/auth.ts:160:15)
|
||||
at setLoginFlowCookie (src/lib/server/auth.ts:514:5)
|
||||
at createLoginRedirect (src/lib/server/auth.ts:533:3)
|
||||
at GET (src/routes/auth/login/+server.ts:6:26)
|
||||
|
||||
[1;31m[500] GET /auth/login[0m
|
||||
Error: Missing required auth environment variable: OIDC_ISSUER
|
||||
at requiredEnv (src/lib/server/auth.ts:111:11)
|
||||
at getAuthConfig (src/lib/server/auth.ts:94:18)
|
||||
at getSecretKey (src/lib/server/auth.ts:136:22)
|
||||
at encryptValue (src/lib/server/auth.ts:160:15)
|
||||
at setLoginFlowCookie (src/lib/server/auth.ts:514:5)
|
||||
at createLoginRedirect (src/lib/server/auth.ts:533:3)
|
||||
at GET (src/routes/auth/login/+server.ts:6:26)
|
||||
|
||||
[1;31m[500] GET /auth/login[0m
|
||||
Error: Missing required auth environment variable: OIDC_ISSUER
|
||||
at requiredEnv (src/lib/server/auth.ts:111:11)
|
||||
at getAuthConfig (src/lib/server/auth.ts:94:18)
|
||||
at getSecretKey (src/lib/server/auth.ts:136:22)
|
||||
at encryptValue (src/lib/server/auth.ts:160:15)
|
||||
at setLoginFlowCookie (src/lib/server/auth.ts:514:5)
|
||||
at createLoginRedirect (src/lib/server/auth.ts:533:3)
|
||||
at GET (src/routes/auth/login/+server.ts:6:26)
|
||||
|
||||
[1;31m[500] GET /auth/login[0m
|
||||
Error: Missing required auth environment variable: OIDC_ISSUER
|
||||
at requiredEnv (src/lib/server/auth.ts:111:11)
|
||||
at getAuthConfig (src/lib/server/auth.ts:94:18)
|
||||
at getSecretKey (src/lib/server/auth.ts:136:22)
|
||||
at encryptValue (src/lib/server/auth.ts:160:15)
|
||||
at setLoginFlowCookie (src/lib/server/auth.ts:514:5)
|
||||
at createLoginRedirect (src/lib/server/auth.ts:533:3)
|
||||
at GET (src/routes/auth/login/+server.ts:6:26)
|
||||
|
||||
[1;31m[500] GET /auth/login[0m
|
||||
Error: Missing required auth environment variable: OIDC_ISSUER
|
||||
at requiredEnv (src/lib/server/auth.ts:111:11)
|
||||
at getAuthConfig (src/lib/server/auth.ts:94:18)
|
||||
at getSecretKey (src/lib/server/auth.ts:136:22)
|
||||
at encryptValue (src/lib/server/auth.ts:160:15)
|
||||
at setLoginFlowCookie (src/lib/server/auth.ts:514:5)
|
||||
at createLoginRedirect (src/lib/server/auth.ts:533:3)
|
||||
at GET (src/routes/auth/login/+server.ts:6:26)
|
||||
|
||||
[1;31m[500] GET /auth/login[0m
|
||||
Error: Missing required auth environment variable: OIDC_ISSUER
|
||||
at requiredEnv (src/lib/server/auth.ts:111:11)
|
||||
at getAuthConfig (src/lib/server/auth.ts:94:18)
|
||||
at getSecretKey (src/lib/server/auth.ts:136:22)
|
||||
at encryptValue (src/lib/server/auth.ts:160:15)
|
||||
at setLoginFlowCookie (src/lib/server/auth.ts:514:5)
|
||||
at createLoginRedirect (src/lib/server/auth.ts:533:3)
|
||||
at GET (src/routes/auth/login/+server.ts:6:26)
|
||||
|
||||
[1;31m[500] GET /auth/login[0m
|
||||
Error: Missing required auth environment variable: OIDC_ISSUER
|
||||
at requiredEnv (src/lib/server/auth.ts:111:11)
|
||||
at getAuthConfig (src/lib/server/auth.ts:94:18)
|
||||
at getSecretKey (src/lib/server/auth.ts:136:22)
|
||||
at encryptValue (src/lib/server/auth.ts:160:15)
|
||||
at setLoginFlowCookie (src/lib/server/auth.ts:514:5)
|
||||
at createLoginRedirect (src/lib/server/auth.ts:533:3)
|
||||
at GET (src/routes/auth/login/+server.ts:6:26)
|
||||
|
||||
[1;31m[500] GET /auth/login[0m
|
||||
Error: Missing required auth environment variable: OIDC_ISSUER
|
||||
at requiredEnv (src/lib/server/auth.ts:111:11)
|
||||
at getAuthConfig (src/lib/server/auth.ts:94:18)
|
||||
at getSecretKey (src/lib/server/auth.ts:136:22)
|
||||
at encryptValue (src/lib/server/auth.ts:160:15)
|
||||
at setLoginFlowCookie (src/lib/server/auth.ts:514:5)
|
||||
at createLoginRedirect (src/lib/server/auth.ts:533:3)
|
||||
at GET (src/routes/auth/login/+server.ts:6:26)
|
||||
|
||||
[1;31m[500] GET /auth/login[0m
|
||||
Error: Missing required auth environment variable: OIDC_ISSUER
|
||||
at requiredEnv (src/lib/server/auth.ts:111:11)
|
||||
at getAuthConfig (src/lib/server/auth.ts:94:18)
|
||||
at getSecretKey (src/lib/server/auth.ts:136:22)
|
||||
at encryptValue (src/lib/server/auth.ts:160:15)
|
||||
at setLoginFlowCookie (src/lib/server/auth.ts:514:5)
|
||||
at createLoginRedirect (src/lib/server/auth.ts:533:3)
|
||||
at GET (src/routes/auth/login/+server.ts:6:26)
|
||||
16:18:10 [vite] (ssr) page reload .svelte-kit/generated/server/internal.js
|
||||
16:18:10 [vite] (ssr) page reload .svelte-kit/generated/root.svelte
|
||||
16:18:10 [vite] (ssr) page reload .svelte-kit/generated/root.js
|
||||
16:18:10 [vite] (ssr) page reload src/lib/paraglide/runtime.js
|
||||
16:18:10 [vite] (ssr) page reload src/lib/paraglide/server.js
|
||||
16:19:52 [vite] (ssr) page reload .svelte-kit/generated/server/internal.js
|
||||
16:19:52 [vite] (ssr) page reload .svelte-kit/generated/root.svelte
|
||||
16:19:52 [vite] (ssr) page reload .svelte-kit/generated/root.js
|
||||
16:19:53 [vite] (ssr) page reload src/lib/paraglide/server.js
|
||||
16:19:53 [vite] (ssr) page reload src/lib/paraglide/runtime.js
|
||||
16:19:53 [vite] (ssr) page reload src/lib/paraglide/server.js
|
||||
16:19:53 [vite] (ssr) page reload src/lib/paraglide/runtime.js
|
||||
16:21:17 [vite] (ssr) page reload src/lib/api.ts
|
||||
16:24:41 [vite] (ssr) page reload .svelte-kit/generated/server/internal.js
|
||||
16:24:41 [vite] (ssr) page reload .svelte-kit/generated/root.svelte
|
||||
16:24:41 [vite] (ssr) page reload .svelte-kit/generated/root.js
|
||||
16:24:42 [vite] (ssr) page reload src/lib/paraglide/runtime.js
|
||||
16:24:42 [vite] (ssr) page reload src/lib/paraglide/server.js
|
||||
85
.sisyphus/evidence/task-T8-oidc-mock.log
Normal file
85
.sisyphus/evidence/task-T8-oidc-mock.log
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
"GET /.well-known/openid-configuration HTTP/1.1" 200 -
|
||||
"GET /.well-known/openid-configuration HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4174%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=Pe0C5a4zQ4Vi55paBNm20bGetmj3Y3yX&code_challenge=bq7aLLFrO4nIa6kvBUM47B56asCKazcoQbOkATvooYM&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"GET /.well-known/openid-configuration HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4174%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=vt-gcRpDGF4HG7V1QCVbA-NX2WLV6UAY&code_challenge=UH0-E3tc3A3U3TCc-FUZDzvzJ1asqarJbznagQ8Lj7o&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"GET /.well-known/openid-configuration HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4174%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=m3l7BolBJCvjhuxRcsSFDZ6gZE6rqTb1&code_challenge=2g7E4QZDpYNRMtQUt5ryXhaYycdglHIeFM1UxZ-XDDs&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"GET /.well-known/openid-configuration HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4174%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=eoKVLYkr20ziVr_dZ8V9JWBkGowz7NYI&code_challenge=vUxYDfnKXdVXnk5aHxY8LjHKCszU3SEiIebjzFPv4J0&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"GET /.well-known/openid-configuration HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4174%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=pd7rjNvJbBvu6NQYuRX6D8bF5szwi8y9&code_challenge=SWGABggwp25CFq8PLbTT7DLSTsvezc77M9PGX_YYNPY&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"GET /.well-known/openid-configuration HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4174%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=In2AvuYgIN7a4n1xiCp1gHtVBn0zpdg-&code_challenge=5ys7xQwmLRLdhb9ZPyI0h3e0bxfaPzonIBTYr4uj6Xg&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"GET /.well-known/openid-configuration HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4174%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=P5shwVgZUoH9xchcI0o078fsgVweezIS&code_challenge=RmboHw0sdVGiU1POAwcptydVlhwdgUzQLLjUMT9S8OU&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"GET /.well-known/openid-configuration HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4174%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=Kp2yUUykkn9ImErvLiLfeOAmJscmF6q6&code_challenge=epJaom98WkEBzjRkkNcLTAp89sB5NkzYrdrjZRxWLok&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"GET /.well-known/openid-configuration HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4174%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=L86d5LRsIOMdz6WD744sjrwSe6iKkW0L&code_challenge=uvl59gn613ivLBLxHhQLPnEFAv48m7jTe9PBGknM1A0&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"GET /.well-known/openid-configuration HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4174%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=vCs34wOnVVizzt0YuT44Mb35qRNttfUH&code_challenge=drdkN8hf7ScN7PSjYY4wmpVhmRv2BJYRyCia0P3oPwM&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"GET /.well-known/openid-configuration HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4174%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=x7j_uSKquOLIvhjzs6SRbF81uQo1TGb_&code_challenge=nBHiDMdcFNj6JjXbJnB4-Ogsp98QtRplWP8IZnHXZ84&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"GET /.well-known/openid-configuration HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4174%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=Kbw1x2FH82MPkXsIs_cK-8-5uHbTpXl1&code_challenge=XweHN-subsxNoIOcpvxoqUx9ILiGh6RG5eHJ6O2jmKI&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"GET /.well-known/openid-configuration HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4174%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=-PIRB74zLnjfijXRSXKeVht6x0jjARr8&code_challenge=nno5wTo4kvMXh6Hbv9Q4UQ42Ah64rdX1RPh1Qas8FTQ&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"GET /.well-known/openid-configuration HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4174%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=ttM5YXVAn1VugFsWVIw9DpnRtYnUfMWW&code_challenge=5cMexMQ8ioSPTSw1FAuAImlWZm5ogbZ5vemeAZtXjvs&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"GET /.well-known/openid-configuration HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4174%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=Psc20ibq2QaTNOYGWuGsWopRtcIYMyDt&code_challenge=wsR_Ly1BzlxHsHCFOcoLNXi5hbRVej1iowuBCynBEXQ&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"GET /.well-known/openid-configuration HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4174%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=Qynh8qyA--irimulhuBnjW7vheoMFv1d&code_challenge=UW4T2DllHIe-d48yu4B33kMEJ8CZuk4uG-g8xGELX2U&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"GET /.well-known/openid-configuration HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4174%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=6i9k2lfIJpNcPY_bE-BjmnEyatt6eSEO&code_challenge=LilRpHaBD6Iij-x69kT0jg9hebm66PUSGBP3CkPQ4R0&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"GET /.well-known/openid-configuration HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4174%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=hv06PULt9VCe6Z57ICw_kfH_rOA68Ye8&code_challenge=H6WP5l4QfrsPqEESZOUm61MWtHDrSrKe4xLl2j0Mqa4&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"GET /.well-known/openid-configuration HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4174%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=bPb6NuPvTTpSLSBf0lcEyiovQMrf25ZU&code_challenge=c8QWtQNvy9pNw9nfeoAym2SM20WpBVePYjG80kV59tY&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"GET /.well-known/openid-configuration HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4174%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=19pfKm4slbG0zxJTa_aNKZauy1pAlM24&code_challenge=fJsle6PvRo2Q53ibfrj2aHQYDfbLoXyWXH11-hJO1-8&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"GET /.well-known/openid-configuration HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4174%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=Ls5-Ps19zFfHr6vdvFrgZXPU4HK2cdMH&code_challenge=hIaTDVr0WpZVBppRxfd4h0nc48Cq6llSetMzG5NU6R0&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"GET /.well-known/openid-configuration HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4174%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=UCR6DlUCqwChXZiu5m3IezhnovkLU1hP&code_challenge=mf1NzdhG0OQnoB2_L_VQNlgohTdD3ZQ1gnrC-WM5xic&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"GET /.well-known/openid-configuration HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4174%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=cikc5ZIqH3gtF0JNS4xeB8ye36C0FeYK&code_challenge=jRsCnQlVsNs4qftFnFdHUm63CxT8tkiprb5QYGcvVQs&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"GET /.well-known/openid-configuration HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4174%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=sxqmLO0piajwnRePC4fq3rSE_EErnT3j&code_challenge=Pg_VsUw-qJXnF_JpdlJbUrxJTPRjzMY2q_rTad86iv4&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"GET /.well-known/openid-configuration HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4174%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=H2123ucRCauviiQcfOgL2ACEaMJMCnCd&code_challenge=J_32kAoALP8nRUhLdpWSnHr9uePiK9ek8K5gYXKrqrM&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"GET /.well-known/openid-configuration HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4174%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=QB4ItNBiVPTcsbvf8jw5fC0wCmLdrBaR&code_challenge=7IJ0bQzKs3-0atAvro4GR87lUJ3rYcUO5nWQ7fGBbJE&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"GET /.well-known/openid-configuration HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4174%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=8f4SjKIZk6Zr23J5PhkIKaWZcZOoHbNy&code_challenge=S0TxmFf5PZ0vgx2krjLl2WIcSyxHI5CcxVdH3SDu7GE&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"GET /.well-known/openid-configuration HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4174%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=gIsLo0NRxP-EP3W8oTjf1O2QS1Nijj-g&code_challenge=bnYTMZcj4cWQ32OPHKWN3638Nuoh3pzPH0wP0GmHLOc&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"GET /.well-known/openid-configuration HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4174%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=RVs6ZqxJdOCnK_RDdRHJbeJFLcjH8jDZ&code_challenge=ghcwJxfIcbS1vZuFbltcVmX9IHbobNEoIvFRrjRo4hc&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"GET /.well-known/openid-configuration HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4174%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=BaIv9zAbKGEmbOlhh7J8I0sye2qpRPcJ&code_challenge=yckMaHRptZd3J04kALAyxxCqIIulPIf9PrTmeA6eN7s&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4174%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=8ikyRz70r3g4_lJGDkx1wEl27neWvVFS&code_challenge=b5f8yNS9lEemYbrnFBnG3OANpefQSU3NXwwFkMS63A4&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"POST /token HTTP/1.1" 200 -
|
||||
"GET /userinfo HTTP/1.1" 200 -
|
||||
"GET /jwks HTTP/1.1" 200 -
|
||||
"GET /.well-known/openid-configuration HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4175%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=C0AvwQhDg-kdVylKE43TG9lawjgYQW0G&code_challenge=88-OcQzCn4HlOoJfXOJ_CQo1PV9YRJCgracnfsuO5LU&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4175%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=t_oQGVk1spVtWPABdSOUPjgdkk0GhGzR&code_challenge=bpLSYPmkEZpr_RbpzfcO6kYEKBBTuRFemoQDH9mBUbU&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"POST /token HTTP/1.1" 200 -
|
||||
"GET /userinfo HTTP/1.1" 200 -
|
||||
"GET /jwks HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4175%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=3wTcjLbHZ73Tq2RdHPs79-kJEcBcPBLQ&code_challenge=OMJ_4YniZmJEdxtS0kpHCgdbZfZWnNSNhMLOeom1y2g&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"POST /token HTTP/1.1" 200 -
|
||||
"GET /userinfo HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4175%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=Rhe95uXtrJH8dXF0T1e_bLVh4ALeny99&code_challenge=1C8cQjsJ1XMTbESSapVbalnDO7QITK1ovYIt2N2OQ-M&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"POST /token HTTP/1.1" 200 -
|
||||
"GET /userinfo HTTP/1.1" 200 -
|
||||
"GET /logout?client_id=innercontext-web&post_logout_redirect_uri=http%3A%2F%2F127.0.0.1%3A4175%2F HTTP/1.1" 303 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4175%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=yYJja-mcNuteTK_vfmRG2q1ngy8uQCYA&code_challenge=X-3bMxYVrLNx0WI_jBRjT33JGo-ge_2SMbuDjMQSB7o&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"POST /token HTTP/1.1" 200 -
|
||||
"GET /userinfo HTTP/1.1" 200 -
|
||||
"GET /authorize?client_id=innercontext-web&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A4175%2Fauth%2Fcallback&scope=openid+profile+email+groups+offline_access&state=y64pl2E_jbiDANFJFjySZe06mGwJxLPY&code_challenge=l3OC99rarYHtSPsiS01wxbIdThMXnTRPUCu_9dUSA5w&code_challenge_method=S256 HTTP/1.1" 303 -
|
||||
"POST /token HTTP/1.1" 200 -
|
||||
"GET /userinfo HTTP/1.1" 200 -
|
||||
"GET /jwks HTTP/1.1" 200 -
|
||||
BIN
.sisyphus/evidence/task-T8-qa.sqlite
Normal file
BIN
.sisyphus/evidence/task-T8-qa.sqlite
Normal file
Binary file not shown.
67
.sisyphus/evidence/task-T9-admin-households-denied.txt
Normal file
67
.sisyphus/evidence/task-T9-admin-households-denied.txt
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
============================= test session starts ==============================
|
||||
platform darwin -- Python 3.12.12, pytest-9.0.2, pluggy-1.6.0 -- /Users/piotr/dev/innercontext/backend/.venv/bin/python3
|
||||
cachedir: .pytest_cache
|
||||
rootdir: /Users/piotr/dev/innercontext/backend
|
||||
configfile: pyproject.toml
|
||||
plugins: anyio-4.12.1, cov-7.0.0
|
||||
collecting ... collected 15 items / 9 deselected / 6 selected
|
||||
|
||||
tests/test_admin_households.py::test_assign_member_rejects_unsynced_user PASSED [ 16%]
|
||||
tests/test_admin_households.py::test_admin_household_routes_forbidden_for_member[get-/admin/users-None] PASSED [ 33%]
|
||||
tests/test_admin_households.py::test_admin_household_routes_forbidden_for_member[post-/admin/households-None] PASSED [ 50%]
|
||||
tests/test_admin_households.py::test_admin_household_routes_forbidden_for_member[post-/admin/households/ad0a09c5-b0bb-4565-895c-eada9498db52/members-json_body2] PASSED [ 66%]
|
||||
tests/test_admin_households.py::test_admin_household_routes_forbidden_for_member[patch-/admin/households/25453802-90e7-44a8-99ab-3241db73c5c0/members/56c635a2-bb8b-48ff-876e-f085ae7cff6c-None] PASSED [ 83%]
|
||||
tests/test_admin_households.py::test_admin_household_routes_forbidden_for_member[delete-/admin/households/4390cd61-0028-4970-a573-a9fca06aff36/members/e5ba2298-ad10-44c0-a77a-b3ea7efa929f-None] PASSED [100%]
|
||||
|
||||
================================ tests coverage ================================
|
||||
______________ coverage: platform darwin, python 3.12.12-final-0 _______________
|
||||
|
||||
Name Stmts Miss Cover Missing
|
||||
----------------------------------------------------------------------------------
|
||||
innercontext/api/__init__.py 0 0 100%
|
||||
innercontext/api/admin.py 93 26 72% 78, 102-110, 142, 165-183, 195-206
|
||||
innercontext/api/ai_logs.py 63 34 46% 18-30, 53-57, 69-81, 106-113
|
||||
innercontext/api/auth.py 68 18 74% 65-79, 100, 106-109, 122-129, 153-158, 166
|
||||
innercontext/api/auth_deps.py 25 10 60% 23, 36-48
|
||||
innercontext/api/authz.py 100 79 21% 16, 20, 24-27, 31, 35-40, 48-51, 60-66, 75-83, 89-93, 105-108, 116-133, 141-150, 156-177
|
||||
innercontext/api/health.py 236 113 52% 77-81, 142-146, 156-163, 179-185, 195-204, 214, 231-243, 253-270, 285-298, 313-330, 341-353, 363-371, 395-463, 473-482, 492, 509-521, 531-539
|
||||
innercontext/api/inventory.py 30 13 57% 26, 36-44, 53-60
|
||||
innercontext/api/llm_context.py 106 91 14% 17-21, 30-36, 44-47, 57-79, 101-153, 180-217, 249-253
|
||||
innercontext/api/product_llm_tools.py 107 94 12% 12-17, 23-38, 48-82, 111-136, 143-162, 172-205
|
||||
innercontext/api/products.py 638 419 34% 81-89, 97, 106-126, 281-289, 299-301, 312-387, 396-431, 515, 519-537, 541-550, 560-566, 570-571, 581-631, 649-703, 712-727, 731, 853-891, 904-972, 981-992, 1002-1015, 1024-1029, 1043-1048, 1060-1072, 1081-1086, 1097-1232, 1238-1240, 1244-1257, 1263, 1296-1457
|
||||
innercontext/api/profile.py 39 15 62% 36-39, 55-69
|
||||
innercontext/api/routines.py 632 446 29% 64-84, 99-103, 109-117, 127-133, 301-304, 308-325, 329-334, 344-357, 372-373, 389-399, 415-434, 443-479, 488-520, 529-565, 574-583, 587-600, 606, 619-641, 664-693, 697-703, 707-710, 714-721, 814-842, 852-857, 871-1134, 1143-1348, 1358-1359, 1371-1386, 1397-1409, 1419-1427, 1443-1464, 1475-1491, 1501-1509, 1524-1529, 1540-1552, 1562-1570
|
||||
innercontext/api/skincare.py 150 70 53% 103, 145-149, 158-166, 178-255, 267-277, 287-296, 306, 322-333, 343-350
|
||||
innercontext/api/utils.py 22 4 82% 34, 43, 51, 59
|
||||
innercontext/auth.py 236 146 38% 64-77, 127-129, 133-137, 141-149, 153-156, 161-168, 187-192, 195-210, 213-217, 220-228, 231-248, 251-264, 267, 271-274, 279, 283-284, 288-317, 325-363, 373-384
|
||||
innercontext/llm.py 134 119 11% 22, 44, 62-66, 74-102, 118-214, 231-326
|
||||
innercontext/llm_safety.py 18 14 22% 17-45, 58-61, 80-83
|
||||
innercontext/models/__init__.py 13 0 100%
|
||||
innercontext/models/ai_log.py 33 0 100%
|
||||
innercontext/models/api_metadata.py 15 0 100%
|
||||
innercontext/models/base.py 3 0 100%
|
||||
innercontext/models/domain.py 4 0 100%
|
||||
innercontext/models/enums.py 152 0 100%
|
||||
innercontext/models/health.py 64 0 100%
|
||||
innercontext/models/household.py 14 0 100%
|
||||
innercontext/models/household_membership.py 20 0 100%
|
||||
innercontext/models/pricing.py 19 0 100%
|
||||
innercontext/models/product.py 226 106 53% 76-78, 203-205, 209-230, 238-356
|
||||
innercontext/models/profile.py 17 0 100%
|
||||
innercontext/models/routine.py 42 0 100%
|
||||
innercontext/models/skincare.py 37 0 100%
|
||||
innercontext/models/user.py 19 0 100%
|
||||
innercontext/services/__init__.py 0 0 100%
|
||||
innercontext/services/fx.py 57 42 26% 16, 20-22, 26-48, 54-67, 71-77
|
||||
innercontext/services/pricing_jobs.py 89 76 15% 19-24, 28-49, 53-67, 71-80, 89-107, 111-130, 134-138
|
||||
innercontext/validators/__init__.py 7 0 100%
|
||||
innercontext/validators/base.py 22 5 77% 23, 27, 31, 35, 52
|
||||
innercontext/validators/batch_validator.py 128 105 18% 37, 58-154, 167-203, 214-240, 249-273
|
||||
innercontext/validators/photo_validator.py 65 54 17% 58-134, 144-152, 164-178
|
||||
innercontext/validators/product_parse_validator.py 110 93 15% 108-154, 164-172, 185-198, 205-239, 243-267, 273-319, 325-339
|
||||
innercontext/validators/routine_validator.py 146 114 22% 69-167, 173-175, 182-197, 201-218, 229-246, 259-275, 288-309
|
||||
innercontext/validators/shopping_validator.py 78 58 26% 49-96, 102-114, 122-123, 136-142, 150-161, 169-203
|
||||
----------------------------------------------------------------------------------
|
||||
TOTAL 4077 2364 42%
|
||||
Coverage HTML written to dir htmlcov
|
||||
======================= 6 passed, 9 deselected in 0.41s ========================
|
||||
65
.sisyphus/evidence/task-T9-admin-households.txt
Normal file
65
.sisyphus/evidence/task-T9-admin-households.txt
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
============================= test session starts ==============================
|
||||
platform darwin -- Python 3.12.12, pytest-9.0.2, pluggy-1.6.0 -- /Users/piotr/dev/innercontext/backend/.venv/bin/python3
|
||||
cachedir: .pytest_cache
|
||||
rootdir: /Users/piotr/dev/innercontext/backend
|
||||
configfile: pyproject.toml
|
||||
plugins: anyio-4.12.1, cov-7.0.0
|
||||
collecting ... collected 15 items / 11 deselected / 4 selected
|
||||
|
||||
tests/test_admin_households.py::test_create_household_returns_new_household PASSED [ 25%]
|
||||
tests/test_admin_households.py::test_assign_member_creates_membership PASSED [ 50%]
|
||||
tests/test_admin_households.py::test_assign_member_rejects_already_assigned_user PASSED [ 75%]
|
||||
tests/test_admin_households.py::test_assign_member_rejects_unsynced_user PASSED [100%]
|
||||
|
||||
================================ tests coverage ================================
|
||||
______________ coverage: platform darwin, python 3.12.12-final-0 _______________
|
||||
|
||||
Name Stmts Miss Cover Missing
|
||||
----------------------------------------------------------------------------------
|
||||
innercontext/api/__init__.py 0 0 100%
|
||||
innercontext/api/admin.py 93 26 72% 78, 102-110, 142, 165-183, 195-206
|
||||
innercontext/api/ai_logs.py 63 34 46% 18-30, 53-57, 69-81, 106-113
|
||||
innercontext/api/auth.py 68 18 74% 65-79, 100, 106-109, 122-129, 153-158, 166
|
||||
innercontext/api/auth_deps.py 25 10 60% 23, 36-48
|
||||
innercontext/api/authz.py 100 79 21% 16, 20, 24-27, 31, 35-40, 48-51, 60-66, 75-83, 89-93, 105-108, 116-133, 141-150, 156-177
|
||||
innercontext/api/health.py 236 113 52% 77-81, 142-146, 156-163, 179-185, 195-204, 214, 231-243, 253-270, 285-298, 313-330, 341-353, 363-371, 395-463, 473-482, 492, 509-521, 531-539
|
||||
innercontext/api/inventory.py 30 13 57% 26, 36-44, 53-60
|
||||
innercontext/api/llm_context.py 106 91 14% 17-21, 30-36, 44-47, 57-79, 101-153, 180-217, 249-253
|
||||
innercontext/api/product_llm_tools.py 107 94 12% 12-17, 23-38, 48-82, 111-136, 143-162, 172-205
|
||||
innercontext/api/products.py 638 419 34% 81-89, 97, 106-126, 281-289, 299-301, 312-387, 396-431, 515, 519-537, 541-550, 560-566, 570-571, 581-631, 649-703, 712-727, 731, 853-891, 904-972, 981-992, 1002-1015, 1024-1029, 1043-1048, 1060-1072, 1081-1086, 1097-1232, 1238-1240, 1244-1257, 1263, 1296-1457
|
||||
innercontext/api/profile.py 39 15 62% 36-39, 55-69
|
||||
innercontext/api/routines.py 632 446 29% 64-84, 99-103, 109-117, 127-133, 301-304, 308-325, 329-334, 344-357, 372-373, 389-399, 415-434, 443-479, 488-520, 529-565, 574-583, 587-600, 606, 619-641, 664-693, 697-703, 707-710, 714-721, 814-842, 852-857, 871-1134, 1143-1348, 1358-1359, 1371-1386, 1397-1409, 1419-1427, 1443-1464, 1475-1491, 1501-1509, 1524-1529, 1540-1552, 1562-1570
|
||||
innercontext/api/skincare.py 150 70 53% 103, 145-149, 158-166, 178-255, 267-277, 287-296, 306, 322-333, 343-350
|
||||
innercontext/api/utils.py 22 4 82% 34, 43, 51, 59
|
||||
innercontext/auth.py 236 146 38% 64-77, 127-129, 133-137, 141-149, 153-156, 161-168, 187-192, 195-210, 213-217, 220-228, 231-248, 251-264, 267, 271-274, 279, 283-284, 288-317, 325-363, 373-384
|
||||
innercontext/llm.py 134 119 11% 22, 44, 62-66, 74-102, 118-214, 231-326
|
||||
innercontext/llm_safety.py 18 14 22% 17-45, 58-61, 80-83
|
||||
innercontext/models/__init__.py 13 0 100%
|
||||
innercontext/models/ai_log.py 33 0 100%
|
||||
innercontext/models/api_metadata.py 15 0 100%
|
||||
innercontext/models/base.py 3 0 100%
|
||||
innercontext/models/domain.py 4 0 100%
|
||||
innercontext/models/enums.py 152 0 100%
|
||||
innercontext/models/health.py 64 0 100%
|
||||
innercontext/models/household.py 14 0 100%
|
||||
innercontext/models/household_membership.py 20 0 100%
|
||||
innercontext/models/pricing.py 19 0 100%
|
||||
innercontext/models/product.py 226 106 53% 76-78, 203-205, 209-230, 238-356
|
||||
innercontext/models/profile.py 17 0 100%
|
||||
innercontext/models/routine.py 42 0 100%
|
||||
innercontext/models/skincare.py 37 0 100%
|
||||
innercontext/models/user.py 19 0 100%
|
||||
innercontext/services/__init__.py 0 0 100%
|
||||
innercontext/services/fx.py 57 42 26% 16, 20-22, 26-48, 54-67, 71-77
|
||||
innercontext/services/pricing_jobs.py 89 76 15% 19-24, 28-49, 53-67, 71-80, 89-107, 111-130, 134-138
|
||||
innercontext/validators/__init__.py 7 0 100%
|
||||
innercontext/validators/base.py 22 5 77% 23, 27, 31, 35, 52
|
||||
innercontext/validators/batch_validator.py 128 105 18% 37, 58-154, 167-203, 214-240, 249-273
|
||||
innercontext/validators/photo_validator.py 65 54 17% 58-134, 144-152, 164-178
|
||||
innercontext/validators/product_parse_validator.py 110 93 15% 108-154, 164-172, 185-198, 205-239, 243-267, 273-319, 325-339
|
||||
innercontext/validators/routine_validator.py 146 114 22% 69-167, 173-175, 182-197, 201-218, 229-246, 259-275, 288-309
|
||||
innercontext/validators/shopping_validator.py 78 58 26% 49-96, 102-114, 122-123, 136-142, 150-161, 169-203
|
||||
----------------------------------------------------------------------------------
|
||||
TOTAL 4077 2364 42%
|
||||
Coverage HTML written to dir htmlcov
|
||||
======================= 4 passed, 11 deselected in 0.41s =======================
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
# T10: Runtime Configuration and Validation
|
||||
|
||||
## Learnings
|
||||
- Nginx needs `X-Forwarded-Host` and `X-Forwarded-Port` for proper OIDC callback URL generation.
|
||||
- `curl -f` fails on 302 redirects, which are common when a page is protected by OIDC.
|
||||
- Health checks and deployment scripts must be updated to allow 302/303/307 status codes for the frontend root.
|
||||
- Bash `((errors++))` returns 1 if `errors` is 0, which can kill the script if `set -e` is active. Use `errors=$((errors + 1))` instead.
|
||||
- Documenting required environment variables in systemd service files and `DEPLOYMENT.md` is crucial for operators.
|
||||
- Authelia client configuration requires specific `redirect_uris` and `scopes` (openid, profile, email, groups).
|
||||
|
||||
## Verification
|
||||
- `scripts/validate-env.sh` correctly identifies missing OIDC and session variables.
|
||||
- `scripts/healthcheck.sh` and `deploy.sh` now handle auth redirects (302) for the frontend.
|
||||
5
.sisyphus/notepads/multi-user-authelia-oidc/decisions.md
Normal file
5
.sisyphus/notepads/multi-user-authelia-oidc/decisions.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
- Added `users`, `households`, and `household_memberships` tables with OIDC identity key (`oidc_issuer`, `oidc_subject`) and one-household-per-user enforced via unique `household_memberships.user_id`.
|
||||
- Added `is_household_shared` to `product_inventory` with default `False` so sharing remains per-row opt-in.
|
||||
- Migration enforces ownership in two phases: nullable + backfill to bootstrap admin, then non-null constraints on all owned tables.
|
||||
- Correction: migration 4b7d2e9f1c3a applies a two-step ownership rollout (nullable user_id, bootstrap+backfill, then NOT NULL on owned tables).
|
||||
- Centralized tenant authorization in `innercontext/api/authz.py` and exposed wrappers in `api/utils.py` so routers can move from global `get_or_404` to scoped helpers.
|
||||
3
.sisyphus/notepads/multi-user-authelia-oidc/issues.md
Normal file
3
.sisyphus/notepads/multi-user-authelia-oidc/issues.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
- Full backend pytest currently has pre-existing failures unrelated to this task scope (5 failing tests in routines/skincare helpers after schema changes in this branch context).
|
||||
- Existing historical migration executes , which breaks full SQLite-from-base upgrades; T2 QA used a synthetic DB pinned at revision to validate the new migration behavior in isolation.
|
||||
- Correction: historical migration 7c91e4b2af38 runs DROP TYPE IF EXISTS pricetier, which breaks SQLite full-chain upgrades; T2 evidence therefore uses a synthetic DB pinned to revision 9f3a2c1b4d5e for isolated migration validation.
|
||||
15
.sisyphus/notepads/multi-user-authelia-oidc/learnings.md
Normal file
15
.sisyphus/notepads/multi-user-authelia-oidc/learnings.md
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
- For ownership rollout without API auth wiring, `user_id` columns can be added as nullable to avoid breaking existing write paths and tests.
|
||||
- Alembic is needed for SQLite-safe ownership column/FK addition and later non-null enforcement across legacy tables.
|
||||
- Correction: Alembic batch_alter_table is required for SQLite-safe ownership column/FK addition and non-null enforcement across legacy tables.
|
||||
- New tenant helpers should keep unauthorized lookups indistinguishable from missing rows by raising `404` with model-not-found detail.
|
||||
- Product visibility and inventory access are separate checks: household-shared inventory can grant view access without granting update rights.
|
||||
- Products should be visible when user is owner, admin, or in the same household as at least one household-shared inventory row; inventory payloads must still be filtered to shared rows only for non-owners.
|
||||
- Shared inventory update rules differ from create/delete: household members in the same household can PATCH shared rows, but POST/DELETE inventory stays owner/admin only.
|
||||
- Product summary ownership should use Product.user_id (is_owned) rather than active inventory presence, so shared products render as accessible-but-not-owned.
|
||||
- SvelteKit can keep PKCE server-only by storing the verifier/state in a short-lived encrypted HTTP-only cookie and storing the refreshed app session in a separate encrypted HTTP-only cookie.
|
||||
- `handleFetch` is enough to attach bearer tokens for server loads/actions that hit `PUBLIC_API_BASE`, but browser-direct `$lib/api` calls to `/api` still need follow-up proxy/auth plumbing outside this task.
|
||||
- 2026-03-12 T6: Domain routers now enforce per-user ownership by default with explicit `?user_id=` admin override in profile/health/routines/skincare/ai-logs; routine suggestion product pool is constrained to owned+household-shared visibility and uses current user profile context.
|
||||
- 2026-03-12 T6: QA evidence generated at `.sisyphus/evidence/task-T6-domain-tenancy.txt` and `.sisyphus/evidence/task-T6-routine-scope.txt` with passing scenarios.
|
||||
- 2026-03-12 T9: Admin household management can stay backend-only by listing synced local `users` plus current membership state, creating bare `households`, and handling assign/move/remove as explicit membership operations.
|
||||
- 2026-03-12 T9: Unsynced identities should fail assignment via local `User` lookup rather than implicit creation, keeping Authelia as the only identity source and preserving the v1 one-household-per-user rule.
|
||||
- 2026-03-12 T8: Server-side frontend API helpers should call `PUBLIC_API_BASE` directly with the access token from `event.locals.session`; same-origin SvelteKit endpoints are still the right bridge for browser-only interactions like AI modals and inline PATCHes.
|
||||
3
.sisyphus/notepads/multi-user-authelia-oidc/problems.md
Normal file
3
.sisyphus/notepads/multi-user-authelia-oidc/problems.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
- Pending follow-up migration task is required to materialize new models/columns in PostgreSQL schema.
|
||||
- End-to-end SQLite from base revision remains blocked by pre-existing non-SQLite-safe migration logic () outside T2 scope.
|
||||
- Correction: full SQLite alembic upgrade head from base is still blocked by pre-existing DROP TYPE usage in migration 7c91e4b2af38 (outside T2 scope).
|
||||
604
.sisyphus/plans/multi-user-authelia-oidc.md
Normal file
604
.sisyphus/plans/multi-user-authelia-oidc.md
Normal file
|
|
@ -0,0 +1,604 @@
|
|||
# Multi-User Support with Authelia OIDC
|
||||
|
||||
## TL;DR
|
||||
> **Summary**: Convert the monorepo from a single-user personal system into a multi-user application authenticated by Authelia OIDC, with SvelteKit owning the login/session flow and FastAPI enforcing row-level ownership and household-scoped inventory sharing.
|
||||
> **Deliverables**:
|
||||
> - OIDC login/logout/session flow in SvelteKit
|
||||
> - FastAPI token validation, current-user resolution, and authorization helpers
|
||||
> - New local identity/household schema plus ownership migrations for existing data
|
||||
> - Household-shared inventory support with owner/admin product controls
|
||||
> - Updated infra, CI, and verification coverage for the new auth model
|
||||
> **Effort**: XL
|
||||
> **Parallel**: YES - 3 waves
|
||||
> **Critical Path**: T1 -> T2 -> T3 -> T4 -> T5/T6 -> T7/T8 -> T11
|
||||
|
||||
## Context
|
||||
### Original Request
|
||||
Add multi-user support with login handled by Authelia using OpenID Connect.
|
||||
|
||||
### Interview Summary
|
||||
- Auth model: app-managed OIDC with SvelteKit-owned session handling; FastAPI acts as the resource server.
|
||||
- Roles: `admin` and `member`; admins can manage member data and household memberships, but v1 excludes impersonation and a full user-management console.
|
||||
- Ownership model: records are user-owned by default; `products` stay user-owned in v1.
|
||||
- Sharing exception: product inventory may be shared among members of the same household; shared household members may view and update inventory entries, but only the product owner or an admin may edit/delete the underlying product.
|
||||
- Rollout: retrofit the existing application in one implementation plan rather than staging auth separately.
|
||||
- Identity source: Authelia remains the source of truth; no in-app signup/provisioning UI in v1.
|
||||
- Verification preference: do not add a permanent frontend test suite in this pass; still require backend tests plus agent-executed QA scenarios.
|
||||
|
||||
### Metis Review (gaps addressed)
|
||||
- Made household sharing explicit with a local `households` + `household_memberships` model instead of overloading OIDC groups.
|
||||
- Added a deterministic legacy-data backfill step so existing single-user records are assigned to the first configured admin identity during migration.
|
||||
- Called out `llm_context.py`, helper functions like `get_or_404()`, and all row-fetching routes as mandatory scoping points so no single-user path survives.
|
||||
- Chose JWT access-token validation via Authelia JWKS for FastAPI, with SvelteKit calling `userinfo` to hydrate the app session and local user record.
|
||||
- Kept browser QA agent-executed and out of repo while still requiring backend auth tests and CI enablement.
|
||||
|
||||
## Work Objectives
|
||||
### Core Objective
|
||||
Implement a secure, decision-complete multi-user architecture that uses Authelia OIDC for authentication, local app users/households for authorization, row ownership across existing data models, and household-scoped inventory sharing without broadening scope into a full account-management product.
|
||||
|
||||
### Deliverables
|
||||
- Backend identity/auth models for local users, households, memberships, and role mapping.
|
||||
- Alembic migration/backfill converting all existing domain data to owned records.
|
||||
- FastAPI auth dependencies, token validation, and authorization utilities.
|
||||
- Retrofitted API routes and LLM context builders that enforce ownership.
|
||||
- SvelteKit login, callback, logout, refresh, and protected-route behavior.
|
||||
- Auth-aware API access from frontend server actions and protected page loads.
|
||||
- Admin-only backend endpoints for household membership management without a UI console.
|
||||
- nginx, deploy, CI, and environment updates needed for OIDC rollout.
|
||||
|
||||
### Definition of Done (verifiable conditions with commands)
|
||||
- `cd backend && uv run pytest`
|
||||
- `cd backend && uv run ruff check .`
|
||||
- `cd frontend && pnpm check`
|
||||
- `cd frontend && pnpm lint`
|
||||
- `cd frontend && pnpm build`
|
||||
- `cd backend && uv run python -c "import json; from main import app; print(json.dumps(app.openapi())[:200])"`
|
||||
|
||||
### Must Have
|
||||
- OIDC Authorization Code flow with PKCE, server-handled callback, HTTP-only app session cookie, refresh-token renewal, and logout.
|
||||
- FastAPI bearer-token validation against Authelia JWKS; no trusted identity headers between app tiers.
|
||||
- Local `users`, `households`, and `household_memberships` tables keyed by `issuer + sub` rather than email.
|
||||
- `user_id` ownership enforcement across profile, health, routines, skincare, AI logs, and products.
|
||||
- Household inventory-sharing model that permits view/update of shared inventory by household members while preserving owner/admin control of product records.
|
||||
- Deterministic backfill of legacy records to a configured bootstrap admin identity.
|
||||
- Admin/member authorization rules enforced in backend dependencies and mirrored in frontend navigation/controls.
|
||||
- Backend auth and authorization tests, plus CI job enablement for those tests.
|
||||
|
||||
### Must NOT Have (guardrails, AI slop patterns, scope boundaries)
|
||||
- No proxy-header trust model between SvelteKit and FastAPI.
|
||||
- No in-app signup, password reset, email verification, impersonation, or full user-management console.
|
||||
- No multi-household membership per user in v1.
|
||||
- No global shared product catalog refactor in this pass.
|
||||
- No audit-log productization, notification system, or support tooling.
|
||||
- No permanent Playwright/Vitest suite added to the repo in this pass.
|
||||
|
||||
## Verification Strategy
|
||||
> ZERO HUMAN INTERVENTION - all verification is agent-executed.
|
||||
- Test decision: tests-after using existing backend `pytest` + `TestClient`; no new committed frontend suite, but include agent-executed browser QA and curl-based verification.
|
||||
- QA policy: every task includes happy-path and failure/edge-case scenarios with exact commands or browser actions.
|
||||
- Evidence: `.sisyphus/evidence/task-{N}-{slug}.{ext}`
|
||||
|
||||
## Execution Strategy
|
||||
### Parallel Execution Waves
|
||||
> Target: 5-8 tasks per wave. <3 per wave (except final) = under-splitting.
|
||||
> Extract shared dependencies as Wave-1 tasks for max parallelism.
|
||||
|
||||
Wave 1: T1 identity models, T2 ownership migration, T3 backend token validation, T4 tenant-aware authorization helpers
|
||||
|
||||
Wave 2: T5 product/inventory authorization retrofit, T6 remaining domain scoping retrofit, T7 SvelteKit auth/session flow, T8 frontend auth-aware plumbing and shell behavior
|
||||
|
||||
Wave 3: T9 admin household-management endpoints, T10 infra/env/CI/deploy updates, T11 backend auth regression coverage and release verification
|
||||
|
||||
### Dependency Matrix (full, all tasks)
|
||||
| Task | Depends On | Blocks |
|
||||
| --- | --- | --- |
|
||||
| T1 | - | T2, T3, T4, T9 |
|
||||
| T2 | T1 | T5, T6, T11 |
|
||||
| T3 | T1 | T4, T5, T6, T7, T8, T9, T11 |
|
||||
| T4 | T1, T3 | T5, T6, T9 |
|
||||
| T5 | T2, T3, T4 | T11 |
|
||||
| T6 | T2, T3, T4 | T11 |
|
||||
| T7 | T3 | T8, T10, T11 |
|
||||
| T8 | T7 | T11 |
|
||||
| T9 | T1, T2, T3, T4 | T11 |
|
||||
| T10 | T3, T7 | T11 |
|
||||
| T11 | T2, T3, T4, T5, T6, T7, T8, T9, T10 | Final verification |
|
||||
|
||||
### Agent Dispatch Summary (wave -> task count -> categories)
|
||||
- Wave 1 -> 4 tasks -> `deep`, `unspecified-high`
|
||||
- Wave 2 -> 4 tasks -> `deep`, `unspecified-high`, `writing`
|
||||
- Wave 3 -> 3 tasks -> `unspecified-high`, `writing`, `deep`
|
||||
|
||||
## TODOs
|
||||
> Implementation + Test = ONE task. Never separate.
|
||||
> EVERY task MUST have: Agent Profile + Parallelization + QA Scenarios.
|
||||
|
||||
- [x] T1. Add local identity, role, household, and sharing models
|
||||
|
||||
**What to do**: Add a new backend model module for `User`, `Household`, and `HouseholdMembership`; extend existing domain models with ownership fields; add a compact role enum (`admin`, `member`) and a household-membership role enum (`owner`, `member`). Use `issuer + subject` as the immutable OIDC identity key, enforce at most one household membership per user in v1, and add `is_household_shared: bool = False` to `ProductInventory` so sharing is opt-in per inventory row rather than automatic for an entire household.
|
||||
**Must NOT do**: Do not key users by email, do not introduce multi-household membership, do not split `Product` into catalog vs overlay tables in this pass, and do not add frontend management UI here.
|
||||
|
||||
**Recommended Agent Profile**:
|
||||
- Category: `deep` - Reason: cross-cutting schema design with downstream auth and authorization consequences
|
||||
- Skills: `[]` - Existing backend conventions are the main source of truth
|
||||
- Omitted: `svelte-code-writer` - No Svelte files belong in this task
|
||||
|
||||
**Parallelization**: Can Parallel: NO | Wave 1 | Blocks: T2, T3, T4, T9 | Blocked By: -
|
||||
|
||||
**References** (executor has NO interview context - be exhaustive):
|
||||
- Pattern: `backend/innercontext/models/profile.py:13` - Simple SQLModel table with UUID PK and timestamp conventions to follow for user-owned profile data.
|
||||
- Pattern: `backend/innercontext/models/product.py:138` - Main table-model style, JSON-column usage, and `updated_at` pattern.
|
||||
- Pattern: `backend/innercontext/models/product.py:353` - Existing `ProductInventory` table to extend with ownership and sharing fields.
|
||||
- Pattern: `backend/innercontext/models/__init__.py:1` - Export surface that must include every new model/type.
|
||||
- API/Type: `backend/innercontext/models/enums.py` - Existing enum location; add role enums here unless a dedicated auth model module makes more sense.
|
||||
|
||||
**Acceptance Criteria** (agent-executable only):
|
||||
- [ ] `backend/innercontext/models/` defines `User`, `Household`, and `HouseholdMembership` with UUID PKs, timestamps, uniqueness on `(oidc_issuer, oidc_subject)`, and one-household-per-user enforcement.
|
||||
- [ ] `Product`, `ProductInventory`, `UserProfile`, `MedicationEntry`, `MedicationUsage`, `LabResult`, `Routine`, `RoutineStep`, `GroomingSchedule`, `SkinConditionSnapshot`, and `AICallLog` each expose an ownership field (`user_id`) in model code, with `ProductInventory` also exposing `is_household_shared`.
|
||||
- [ ] `innercontext.models` re-exports the new auth/household types so metadata loading and imports continue to work.
|
||||
- [ ] `cd backend && uv run python -c "import innercontext.models as m; print(all(hasattr(m, name) for name in ['User','Household','HouseholdMembership']))"` prints `True`.
|
||||
|
||||
**QA Scenarios** (MANDATORY - task incomplete without these):
|
||||
```
|
||||
Scenario: Identity models load into SQLModel metadata
|
||||
Tool: Bash
|
||||
Steps: Run `cd backend && uv run python -c "import innercontext.models; from sqlmodel import SQLModel; print(sorted(t.name for t in SQLModel.metadata.sorted_tables if t.name in {'users','households','household_memberships'}))" > ../.sisyphus/evidence/task-T1-identity-models.txt`
|
||||
Expected: Evidence file lists `['household_memberships', 'households', 'users']`
|
||||
Evidence: .sisyphus/evidence/task-T1-identity-models.txt
|
||||
|
||||
Scenario: Product inventory sharing stays opt-in
|
||||
Tool: Bash
|
||||
Steps: Run `cd backend && uv run python -c "from innercontext.models.product import ProductInventory; f=ProductInventory.model_fields['is_household_shared']; print(f.default)" > ../.sisyphus/evidence/task-T1-sharing-default.txt`
|
||||
Expected: Evidence file contains `False`
|
||||
Evidence: .sisyphus/evidence/task-T1-sharing-default.txt
|
||||
```
|
||||
|
||||
**Commit**: YES | Message: `feat(auth): add local user and household models` | Files: `backend/innercontext/models/*`
|
||||
|
||||
- [x] T2. Add Alembic migration and bootstrap backfill for legacy single-user data
|
||||
|
||||
**What to do**: Create an Alembic revision that creates `users`, `households`, and `household_memberships`, adds `user_id` ownership columns and related foreign keys/indexes to all owned tables, and adds `is_household_shared` to `product_inventory`. Use a two-step migration: add nullable columns, create/bootstrap a local admin user + default household from environment variables, backfill every existing row to that bootstrap user, then enforce non-null ownership constraints. Use env names `BOOTSTRAP_ADMIN_OIDC_ISSUER`, `BOOTSTRAP_ADMIN_OIDC_SUB`, `BOOTSTRAP_ADMIN_EMAIL`, `BOOTSTRAP_ADMIN_NAME`, and `BOOTSTRAP_HOUSEHOLD_NAME`; abort the migration with a clear error if legacy data exists and the required issuer/sub values are missing.
|
||||
**Must NOT do**: Do not assign ownership based on email matching, do not silently create random bootstrap identities, and do not leave owned tables nullable after the migration completes.
|
||||
|
||||
**Recommended Agent Profile**:
|
||||
- Category: `deep` - Reason: schema migration, backfill, and irreversible data-shape change
|
||||
- Skills: `[]` - Use existing Alembic patterns from the repo
|
||||
- Omitted: `git-master` - Commit strategy is already prescribed here
|
||||
|
||||
**Parallelization**: Can Parallel: NO | Wave 1 | Blocks: T5, T6, T11 | Blocked By: T1
|
||||
|
||||
**References** (executor has NO interview context - be exhaustive):
|
||||
- Pattern: `backend/alembic/versions/` - Existing migration naming/layout conventions to follow.
|
||||
- Pattern: `backend/innercontext/models/product.py:180` - Timestamp/nullability expectations that migrated columns must preserve.
|
||||
- Pattern: `backend/db.py:17` - Metadata creation path; migration must leave runtime startup compatible.
|
||||
- API/Type: `backend/innercontext/models/profile.py:13` - Existing singleton-style table that must become owned data.
|
||||
- API/Type: `backend/innercontext/models/product.py:353` - Inventory table receiving the sharing flag.
|
||||
|
||||
**Acceptance Criteria** (agent-executable only):
|
||||
- [ ] A new Alembic revision exists under `backend/alembic/versions/` creating auth/household tables and ownership columns/indexes/foreign keys.
|
||||
- [ ] The migration backfills all existing owned rows to the bootstrap admin user and creates that user's default household + owner membership.
|
||||
- [ ] The migration aborts with a readable exception if legacy data exists and `BOOTSTRAP_ADMIN_OIDC_ISSUER` or `BOOTSTRAP_ADMIN_OIDC_SUB` is absent.
|
||||
- [ ] Owned tables end with non-null `user_id` constraints after upgrade.
|
||||
|
||||
**QA Scenarios** (MANDATORY - task incomplete without these):
|
||||
```
|
||||
Scenario: Migration upgrade succeeds with bootstrap identity configured
|
||||
Tool: Bash
|
||||
Steps: Create a disposable DB URL (for example `sqlite:///../.sisyphus/evidence/task-T2-upgrade.sqlite`), then run `cd backend && DATABASE_URL=sqlite:///../.sisyphus/evidence/task-T2-upgrade.sqlite BOOTSTRAP_ADMIN_OIDC_ISSUER=https://auth.example.test BOOTSTRAP_ADMIN_OIDC_SUB=legacy-admin BOOTSTRAP_ADMIN_EMAIL=owner@example.test BOOTSTRAP_ADMIN_NAME='Legacy Owner' BOOTSTRAP_HOUSEHOLD_NAME='Default Household' uv run alembic upgrade head > ../.sisyphus/evidence/task-T2-migration-upgrade.txt`
|
||||
Expected: Command exits 0 and evidence file shows Alembic reached `head`
|
||||
Evidence: .sisyphus/evidence/task-T2-migration-upgrade.txt
|
||||
|
||||
Scenario: Migration fails fast when bootstrap identity is missing for legacy data
|
||||
Tool: Bash
|
||||
Steps: Seed a disposable SQLite DB with one legacy row using the pre-migration schema, then run `cd backend && DATABASE_URL=sqlite:///../.sisyphus/evidence/task-T2-missing-bootstrap.sqlite uv run alembic upgrade head 2> ../.sisyphus/evidence/task-T2-migration-missing-bootstrap.txt`
|
||||
Expected: Upgrade exits non-zero and evidence contains a message naming both missing bootstrap env vars
|
||||
Evidence: .sisyphus/evidence/task-T2-migration-missing-bootstrap.txt
|
||||
```
|
||||
|
||||
**Commit**: YES | Message: `feat(db): backfill tenant ownership for existing records` | Files: `backend/alembic/versions/*`, `backend/innercontext/models/*`
|
||||
|
||||
- [x] T3. Implement FastAPI token validation, user sync, and current-user dependencies
|
||||
|
||||
**What to do**: Add backend auth modules that validate Authelia JWT access tokens via JWKS with cached key material, enforce issuer/audience/expiry checks, map role groups to local roles, and expose dependencies like `get_current_user()` and `require_admin()`. Create protected auth endpoints for session sync and self introspection (for example `/auth/session/sync` and `/auth/me`) so SvelteKit can exchange token-derived/userinfo-derived identity details for a local `User` row and current app profile. Use env/config values for issuer, JWKS URL/discovery URL, client ID, and group names instead of hard-coding them.
|
||||
**Must NOT do**: Do not trust `X-Forwarded-User`-style headers, do not skip signature validation, do not derive role from email domain, and do not make backend routes public except health-check.
|
||||
|
||||
**Recommended Agent Profile**:
|
||||
- Category: `unspecified-high` - Reason: focused backend auth implementation with security-sensitive logic
|
||||
- Skills: `[]` - No project skill is better than direct backend work here
|
||||
- Omitted: `svelte-code-writer` - No Svelte components involved
|
||||
|
||||
**Parallelization**: Can Parallel: NO | Wave 1 | Blocks: T4, T5, T6, T7, T8, T9, T11 | Blocked By: T1
|
||||
|
||||
**References** (executor has NO interview context - be exhaustive):
|
||||
- Pattern: `backend/main.py:37` - Current FastAPI app construction and router registration point.
|
||||
- Pattern: `backend/db.py:12` - Session dependency shape that auth dependencies must compose with.
|
||||
- Pattern: `backend/innercontext/api/profile.py:27` - Router/dependency style used throughout the API.
|
||||
- External: `https://www.authelia.com/configuration/identity-providers/openid-connect/provider/` - OIDC provider/discovery and JWKS behavior.
|
||||
- External: `https://www.authelia.com/integration/openid-connect/openid-connect-1.0-claims/` - Claims and userinfo behavior; use `issuer + sub` as identity key.
|
||||
|
||||
**Acceptance Criteria** (agent-executable only):
|
||||
- [ ] A backend auth module validates bearer tokens against Authelia JWKS with issuer/audience checks and cached key refresh.
|
||||
- [ ] Protected dependencies expose a normalized current user object with local `user_id`, role, and household membership information.
|
||||
- [ ] Backend includes protected auth sync/introspection endpoints used by SvelteKit to upsert local users from OIDC identity data.
|
||||
- [ ] Unauthenticated access to owned API routes returns `401`; authenticated access with a valid token reaches router logic.
|
||||
|
||||
**QA Scenarios** (MANDATORY - task incomplete without these):
|
||||
```
|
||||
Scenario: Valid bearer token resolves a current user
|
||||
Tool: Bash
|
||||
Steps: Run `cd backend && uv run pytest tests/test_auth.py -k sync > ../.sisyphus/evidence/task-T3-auth-sync.txt`
|
||||
Expected: Auth sync/introspection tests pass and evidence includes the protected auth endpoint names
|
||||
Evidence: .sisyphus/evidence/task-T3-auth-sync.txt
|
||||
|
||||
Scenario: Missing or invalid bearer token is rejected
|
||||
Tool: Bash
|
||||
Steps: Run `cd backend && uv run pytest tests/test_auth.py -k unauthorized > ../.sisyphus/evidence/task-T3-auth-unauthorized.txt`
|
||||
Expected: Tests pass and evidence shows `401` expectations
|
||||
Evidence: .sisyphus/evidence/task-T3-auth-unauthorized.txt
|
||||
```
|
||||
|
||||
**Commit**: YES | Message: `feat(auth): validate Authelia tokens in FastAPI` | Files: `backend/main.py`, `backend/innercontext/auth.py`, `backend/innercontext/api/auth*.py`
|
||||
|
||||
- [x] T4. Centralize tenant-aware fetch helpers and authorization predicates
|
||||
|
||||
**What to do**: Replace single-user helper assumptions with reusable authorization helpers that every router can call. Add tenant-aware helpers for owned lookup, admin override, same-household checks, and household-shared inventory visibility/update rules. Keep `get_session()` unchanged, but add helpers/dependencies that make it difficult for routers to accidentally query global rows. Update or supersede `get_or_404()` with helpers that scope by `user_id` and return `404` for unauthorized record lookups unless the route intentionally needs `403`.
|
||||
**Must NOT do**: Do not leave routers performing raw `session.get()` on owned models, do not duplicate household-sharing logic in every route, and do not use admin bypasses that skip existence checks.
|
||||
|
||||
**Recommended Agent Profile**:
|
||||
- Category: `deep` - Reason: authorization rules must become the shared execution path for many routers
|
||||
- Skills: `[]` - This is backend architecture work, not skill-driven tooling
|
||||
- Omitted: `frontend-design` - No UI work belongs here
|
||||
|
||||
**Parallelization**: Can Parallel: NO | Wave 1 | Blocks: T5, T6, T9 | Blocked By: T1, T3
|
||||
|
||||
**References** (executor has NO interview context - be exhaustive):
|
||||
- Pattern: `backend/innercontext/api/utils.py:9` - Existing naive `get_or_404()` helper that must no longer be used for owned records.
|
||||
- Pattern: `backend/innercontext/api/products.py:934` - Current direct object fetch/update/delete route pattern to replace.
|
||||
- Pattern: `backend/innercontext/api/inventory.py:14` - Inventory routes that currently expose rows globally.
|
||||
- Pattern: `backend/innercontext/api/health.py:141` - Representative list/get/update/delete health routes requiring shared helpers.
|
||||
- Pattern: `backend/innercontext/api/routines.py:674` - Another high-volume router that must consume the same authz utilities.
|
||||
|
||||
**Acceptance Criteria** (agent-executable only):
|
||||
- [ ] Backend provides shared helper/dependency functions for owned lookups, admin checks, same-household checks, and shared-inventory updates.
|
||||
- [ ] `get_or_404()` is either retired for owned data or wrapped so no owned router path still uses the unscoped helper directly.
|
||||
- [ ] Shared inventory authorization distinguishes product ownership from inventory update rights.
|
||||
- [ ] Helper tests cover owner access, admin override, same-household shared inventory access, and cross-household denial.
|
||||
|
||||
**QA Scenarios** (MANDATORY - task incomplete without these):
|
||||
```
|
||||
Scenario: Authorization helpers allow owner/admin/household-shared access correctly
|
||||
Tool: Bash
|
||||
Steps: Run `cd backend && uv run pytest tests/test_authz.py -k 'owner or admin or household' > ../.sisyphus/evidence/task-T4-authz-happy.txt`
|
||||
Expected: Tests pass and evidence includes owner/admin/household cases
|
||||
Evidence: .sisyphus/evidence/task-T4-authz-happy.txt
|
||||
|
||||
Scenario: Cross-household access is denied without leaking row existence
|
||||
Tool: Bash
|
||||
Steps: Run `cd backend && uv run pytest tests/test_authz.py -k denied > ../.sisyphus/evidence/task-T4-authz-denied.txt`
|
||||
Expected: Tests pass and evidence shows `404` or `403` assertions exactly where specified by the helper contract
|
||||
Evidence: .sisyphus/evidence/task-T4-authz-denied.txt
|
||||
```
|
||||
|
||||
**Commit**: YES | Message: `refactor(api): centralize tenant authorization helpers` | Files: `backend/innercontext/api/utils.py`, `backend/innercontext/api/authz.py`, router call sites
|
||||
|
||||
- [x] T5. Retrofit products and inventory endpoints for owned access plus household sharing
|
||||
|
||||
**What to do**: Update `products` and `inventory` APIs so product visibility is `owned OR household-visible-via-shared-inventory OR admin`, while product mutation remains `owner OR admin`. Keep `Product` user-owned. For household members, allow `GET` on shared products/inventory rows and `PATCH` on shared inventory rows, but keep `POST /products`, `PATCH /products/{id}`, `DELETE /products/{id}`, `POST /products/{id}/inventory`, and `DELETE /inventory/{id}` restricted to owner/admin. Reuse the existing `ProductListItem.is_owned` field so shared-but-not-owned products are clearly marked in summaries. Ensure suggestion and summary endpoints only use products accessible to the current user.
|
||||
**Must NOT do**: Do not expose non-shared inventory across a household, do not let household members edit `personal_tolerance_notes`, and do not return global product lists anymore.
|
||||
|
||||
**Recommended Agent Profile**:
|
||||
- Category: `deep` - Reason: most nuanced authorization rules live in product and inventory flows
|
||||
- Skills: `[]` - Backend logic and existing product patterns are sufficient
|
||||
- Omitted: `frontend-design` - No UI polish belongs here
|
||||
|
||||
**Parallelization**: Can Parallel: YES | Wave 2 | Blocks: T11 | Blocked By: T2, T3, T4
|
||||
|
||||
**References** (executor has NO interview context - be exhaustive):
|
||||
- Pattern: `backend/innercontext/api/products.py:605` - List route currently returning global products.
|
||||
- Pattern: `backend/innercontext/api/products.py:844` - Summary route already exposes `is_owned`; extend rather than replacing it.
|
||||
- Pattern: `backend/innercontext/api/products.py:934` - Detail/update/delete routes that currently use direct lookup.
|
||||
- Pattern: `backend/innercontext/api/products.py:977` - Product inventory list/create routes.
|
||||
- Pattern: `backend/innercontext/api/inventory.py:14` - Direct inventory get/update/delete routes that currently bypass ownership.
|
||||
- API/Type: `backend/innercontext/models/product.py:353` - Inventory model fields involved in household sharing.
|
||||
- Test: `backend/tests/test_products.py:38` - Existing CRUD/filter test style to extend for authz cases.
|
||||
|
||||
**Acceptance Criteria** (agent-executable only):
|
||||
- [ ] Product list/detail/summary/suggest endpoints only return products accessible to the current user.
|
||||
- [ ] Shared household members can `GET` shared products/inventory and `PATCH` shared inventory rows, but cannot mutate product records or create/delete another user's inventory rows.
|
||||
- [ ] Product summaries preserve `is_owned` semantics for shared products.
|
||||
- [ ] Product/inventory tests cover owner, admin, same-household shared member, and different-household member cases.
|
||||
|
||||
**QA Scenarios** (MANDATORY - task incomplete without these):
|
||||
```
|
||||
Scenario: Household member can view a shared product and update its shared inventory row
|
||||
Tool: Bash
|
||||
Steps: Run `cd backend && uv run pytest tests/test_products_auth.py -k 'shared_inventory_update or shared_product_visible' > ../.sisyphus/evidence/task-T5-product-sharing.txt`
|
||||
Expected: Tests pass and evidence shows `200` assertions for shared view/update cases
|
||||
Evidence: .sisyphus/evidence/task-T5-product-sharing.txt
|
||||
|
||||
Scenario: Household member cannot edit or delete another user's product
|
||||
Tool: Bash
|
||||
Steps: Run `cd backend && uv run pytest tests/test_products_auth.py -k 'cannot_edit_shared_product or cannot_delete_shared_product' > ../.sisyphus/evidence/task-T5-product-denied.txt`
|
||||
Expected: Tests pass and evidence shows `403` or `404` assertions matching the route contract
|
||||
Evidence: .sisyphus/evidence/task-T5-product-denied.txt
|
||||
```
|
||||
|
||||
**Commit**: YES | Message: `feat(api): scope products and inventory by owner and household` | Files: `backend/innercontext/api/products.py`, `backend/innercontext/api/inventory.py`, related tests
|
||||
|
||||
- [x] T6. Retrofit remaining domain routes, LLM context, and jobs for per-user ownership
|
||||
|
||||
**What to do**: Update profile, health, routines, skincare, AI log, and LLM-context code so every query is user-scoped by default and admin override is explicit. `UserProfile` becomes one-per-user rather than singleton; `build_user_profile_context()` and product-context builders must accept the current user and only include accessible data. Routine suggestion/batch flows must use the current user's profile plus products visible under the owned/shared rules from T5. Ensure background pricing/job paths preserve `user_id` on products and logs, and that list endpoints never aggregate cross-user data for non-admins.
|
||||
**Must NOT do**: Do not keep any `select(Model)` query unfiltered on an owned model, do not keep singleton profile lookups, and do not leak other users' AI logs or health data through helper functions.
|
||||
|
||||
**Recommended Agent Profile**:
|
||||
- Category: `deep` - Reason: many routers and helper layers need consistent tenancy retrofits
|
||||
- Skills: `[]` - Backend cross-module work only
|
||||
- Omitted: `svelte-code-writer` - No Svelte component work in this task
|
||||
|
||||
**Parallelization**: Can Parallel: YES | Wave 2 | Blocks: T11 | Blocked By: T2, T3, T4
|
||||
|
||||
**References** (executor has NO interview context - be exhaustive):
|
||||
- Pattern: `backend/innercontext/api/profile.py:27` - Current singleton profile route using `get_user_profile(session)`.
|
||||
- Pattern: `backend/innercontext/api/llm_context.py:10` - Single-user helper that currently selects the most recent profile globally.
|
||||
- Pattern: `backend/innercontext/api/health.py:141` - Medication and lab-result CRUD/list route layout.
|
||||
- Pattern: `backend/innercontext/api/routines.py:674` - Routine list/create/suggest entry points that need scoped product/profile data.
|
||||
- Pattern: `backend/innercontext/api/skincare.py:222` - Snapshot list/get/update/delete route structure.
|
||||
- Pattern: `backend/innercontext/api/ai_logs.py:46` - AI-log exposure that must become owned/admin-only.
|
||||
- Pattern: `backend/innercontext/services/pricing_jobs.py` - Background queue path that must preserve product ownership.
|
||||
|
||||
**Acceptance Criteria** (agent-executable only):
|
||||
- [ ] Every non-admin router outside products/inventory scopes owned data by `user_id` before returning or mutating rows.
|
||||
- [ ] `GET /profile` and `PATCH /profile` operate on the current user's profile, not the newest global profile.
|
||||
- [ ] Routine suggestion and batch suggestion flows use only the current user's profile plus accessible products.
|
||||
- [ ] AI logs are owned/admin-only, and background job/log creation stores `user_id` when applicable.
|
||||
|
||||
**QA Scenarios** (MANDATORY - task incomplete without these):
|
||||
```
|
||||
Scenario: Member only sees their own health, routine, profile, skin, and AI-log data
|
||||
Tool: Bash
|
||||
Steps: Run `cd backend && uv run pytest tests/test_tenancy_domains.py -k 'profile or health or routines or skincare or ai_logs' > ../.sisyphus/evidence/task-T6-domain-tenancy.txt`
|
||||
Expected: Tests pass and evidence shows only owned/admin-allowed access patterns
|
||||
Evidence: .sisyphus/evidence/task-T6-domain-tenancy.txt
|
||||
|
||||
Scenario: Routine suggestions ignore another user's products and profile
|
||||
Tool: Bash
|
||||
Steps: Run `cd backend && uv run pytest tests/test_routines_auth.py -k suggest > ../.sisyphus/evidence/task-T6-routine-scope.txt`
|
||||
Expected: Tests pass and evidence shows suggestion inputs are scoped to the authenticated user plus shared inventory visibility rules
|
||||
Evidence: .sisyphus/evidence/task-T6-routine-scope.txt
|
||||
```
|
||||
|
||||
**Commit**: YES | Message: `feat(api): enforce ownership across health routines and profile flows` | Files: `backend/innercontext/api/profile.py`, `backend/innercontext/api/health.py`, `backend/innercontext/api/routines.py`, `backend/innercontext/api/skincare.py`, `backend/innercontext/api/ai_logs.py`, `backend/innercontext/api/llm_context.py`
|
||||
|
||||
- [x] T7. Implement SvelteKit OIDC login, callback, logout, refresh, and protected-session handling
|
||||
|
||||
**What to do**: Add server-only auth utilities under `frontend/src/lib/server/` and implement `Authorization Code + PKCE` in SvelteKit using Authelia discovery/token/userinfo endpoints. Create `/auth/login`, `/auth/callback`, and `/auth/logout` server routes. Extend `hooks.server.ts` to decrypt/load the app session, refresh the access token when it is near expiry, populate `event.locals.user` and `event.locals.session`, and redirect unauthenticated requests on all application routes except `/auth/*` and static assets. Use an encrypted HTTP-only cookie named `innercontext_session` with `sameSite=lax`, `secure` in production, and a 32-byte secret from private env.
|
||||
**Must NOT do**: Do not store access or refresh tokens in `localStorage`, do not expose client secrets via `$env/static/public`, and do not protect routes with client-only guards.
|
||||
|
||||
**Recommended Agent Profile**:
|
||||
- Category: `unspecified-high` - Reason: server-side SvelteKit auth flow with cookies, hooks, and redirects
|
||||
- Skills: [`svelte-code-writer`] - Required for editing SvelteKit auth and route modules cleanly
|
||||
- Omitted: `frontend-design` - This task is auth/session behavior, not visual redesign
|
||||
|
||||
**Parallelization**: Can Parallel: YES | Wave 2 | Blocks: T8, T10, T11 | Blocked By: T3
|
||||
|
||||
**References** (executor has NO interview context - be exhaustive):
|
||||
- Pattern: `frontend/src/hooks.server.ts:1` - Current global request hook; auth must compose with existing Paraglide middleware rather than replacing it.
|
||||
- Pattern: `frontend/src/app.d.ts:3` - Add typed `App.Locals`/`PageData` session fields here.
|
||||
- Pattern: `frontend/src/routes/+layout.svelte:30` - App shell/navigation that will consume authenticated user state later.
|
||||
- Pattern: `frontend/src/routes/products/suggest/+page.server.ts:4` - Existing SvelteKit server action style using `fetch`.
|
||||
- External: `https://www.authelia.com/configuration/identity-providers/openid-connect/clients/` - Client configuration expectations for auth code flow and PKCE.
|
||||
|
||||
**Acceptance Criteria** (agent-executable only):
|
||||
- [ ] SvelteKit exposes login/callback/logout server routes that complete the OIDC flow against Authelia and create/destroy `innercontext_session`.
|
||||
- [ ] `hooks.server.ts` populates `event.locals.user`/`event.locals.session`, refreshes tokens near expiry, and redirects unauthenticated users away from protected pages.
|
||||
- [ ] The callback flow calls backend auth sync before treating the user as signed in.
|
||||
- [ ] Session cookies are HTTP-only and sourced only from private env/config.
|
||||
|
||||
**QA Scenarios** (MANDATORY - task incomplete without these):
|
||||
```
|
||||
Scenario: Login callback establishes an authenticated server session
|
||||
Tool: Playwright
|
||||
Steps: Navigate to `/products` while signed out, follow redirect to `/auth/login`, on the Authelia page fill the `Username` and `Password` fields using `E2E_AUTHELIA_USERNAME`/`E2E_AUTHELIA_PASSWORD`, submit the primary login button, wait for redirect back to the app, then save an accessibility snapshot to `.sisyphus/evidence/task-T7-login-flow.md`
|
||||
Expected: Final URL is inside the app, the protected page renders, and the session cookie exists
|
||||
Evidence: .sisyphus/evidence/task-T7-login-flow.md
|
||||
|
||||
Scenario: Expired or refresh-failed session redirects back to login
|
||||
Tool: Playwright
|
||||
Steps: Start from an authenticated session, replace the `innercontext_session` cookie with one containing an expired access token or invalidate the refresh endpoint in the browser session, reload `/products`, and save a snapshot to `.sisyphus/evidence/task-T7-refresh-failure.md`
|
||||
Expected: The app clears the session cookie and redirects to `/auth/login`
|
||||
Evidence: .sisyphus/evidence/task-T7-refresh-failure.md
|
||||
```
|
||||
|
||||
**Commit**: YES | Message: `feat(frontend): add Authelia OIDC session flow` | Files: `frontend/src/hooks.server.ts`, `frontend/src/app.d.ts`, `frontend/src/lib/server/auth.ts`, `frontend/src/routes/auth/*`
|
||||
|
||||
- [x] T8. Refactor frontend data access, route guards, and shell state around the server session
|
||||
|
||||
**What to do**: Refactor frontend API access so protected backend calls always originate from SvelteKit server loads/actions/endpoints using the access token from `event.locals.session`. Convert browser-side direct `$lib/api` usage to server actions or same-origin SvelteKit endpoints, add a `+layout.server.ts` that exposes authenticated user data to the shell, and update `+layout.svelte` to show the current user role/name plus a logout action. Regenerate OpenAPI types if backend response models change and keep `$lib/types` as the canonical import surface.
|
||||
**Must NOT do**: Do not keep browser-side bearer-token fetches, do not bypass the server session by calling backend APIs directly from components, and do not hardcode English auth labels without Paraglide message keys.
|
||||
|
||||
**Recommended Agent Profile**:
|
||||
- Category: `unspecified-high` - Reason: SvelteKit route plumbing plus shell-state integration
|
||||
- Skills: [`svelte-code-writer`] - Required because this task edits `.svelte` and SvelteKit route modules
|
||||
- Omitted: `frontend-design` - Preserve the existing editorial shell instead of redesigning it
|
||||
|
||||
**Parallelization**: Can Parallel: YES | Wave 2 | Blocks: T11 | Blocked By: T7
|
||||
|
||||
**References** (executor has NO interview context - be exhaustive):
|
||||
- Pattern: `frontend/src/lib/api.ts:25` - Current request helper branching between browser and server; replace with session-aware server usage.
|
||||
- Pattern: `frontend/src/routes/+layout.svelte:63` - Existing app shell where user state/logout should appear without breaking navigation.
|
||||
- Pattern: `frontend/src/routes/+page.server.ts` - Representative server-load pattern already used throughout the app.
|
||||
- Pattern: `frontend/src/routes/skin/new/+page.svelte` - Existing browser-side API import to eliminate or proxy through server logic.
|
||||
- Pattern: `frontend/src/routes/routines/[id]/+page.svelte` - Another browser-side API import that must stop calling the backend directly.
|
||||
- Pattern: `frontend/src/routes/products/suggest/+page.server.ts:4` - Server action pattern to reuse for auth-aware fetches.
|
||||
- API/Type: `frontend/src/lib/types.ts` - Keep as the only frontend import surface after any `pnpm generate:api` run.
|
||||
|
||||
**Acceptance Criteria** (agent-executable only):
|
||||
- [ ] Protected backend calls in frontend code use the server session access token and no longer depend on browser token storage.
|
||||
- [ ] Direct component-level `$lib/api` usage on protected paths is removed or wrapped behind same-origin server endpoints/actions.
|
||||
- [ ] App shell receives authenticated user/session data from server load and exposes a logout affordance.
|
||||
- [ ] `pnpm generate:api` is run if backend auth/API response changes require regenerated frontend types.
|
||||
|
||||
**QA Scenarios** (MANDATORY - task incomplete without these):
|
||||
```
|
||||
Scenario: Authenticated user navigates protected pages and sees session-aware shell state
|
||||
Tool: Playwright
|
||||
Steps: Log in, visit `/`, `/products`, `/profile`, and `/routines`; capture an accessibility snapshot to `.sisyphus/evidence/task-T8-protected-nav.md`
|
||||
Expected: Each page loads without redirect loops, and the shell shows the current user plus logout control
|
||||
Evidence: .sisyphus/evidence/task-T8-protected-nav.md
|
||||
|
||||
Scenario: Unauthenticated browser access cannot hit protected data paths directly
|
||||
Tool: Playwright
|
||||
Steps: Start from a signed-out browser, open a page that previously imported `$lib/api` from a component, attempt the same interaction, capture console/network output to `.sisyphus/evidence/task-T8-signed-out-network.txt`
|
||||
Expected: The app redirects or blocks cleanly without leaking backend JSON responses into the UI
|
||||
Evidence: .sisyphus/evidence/task-T8-signed-out-network.txt
|
||||
```
|
||||
|
||||
**Commit**: YES | Message: `refactor(frontend): route protected API access through server session` | Files: `frontend/src/lib/api.ts`, `frontend/src/routes/**/*.server.ts`, `frontend/src/routes/+layout.*`, selected `.svelte` files, `frontend/src/lib/types.ts`
|
||||
|
||||
- [x] T9. Add admin-only household management API without a frontend console
|
||||
|
||||
**What to do**: Add a small admin-only backend router for household administration so the app can support real household sharing without a management UI. Provide endpoints to list local users who have logged in, create a household, assign a user to a household, move a user between households, and remove a membership. Enforce the v1 rule that a user can belong to at most one household. Do not manage identity creation here; Authelia remains the identity source, and only locally synced users may be assigned. Non-bootstrap users should remain household-less until an admin assigns them.
|
||||
**Must NOT do**: Do not add Svelte pages for household management, do not let non-admins call these endpoints, and do not allow membership assignment for users who have never authenticated into the app.
|
||||
|
||||
**Recommended Agent Profile**:
|
||||
- Category: `unspecified-high` - Reason: contained backend admin surface with sensitive authorization logic
|
||||
- Skills: `[]` - Backend conventions already exist in repo
|
||||
- Omitted: `frontend-design` - Explicitly no console/UI in scope
|
||||
|
||||
**Parallelization**: Can Parallel: YES | Wave 3 | Blocks: T11 | Blocked By: T1, T2, T3, T4
|
||||
|
||||
**References** (executor has NO interview context - be exhaustive):
|
||||
- Pattern: `backend/main.py:50` - Router registration area; add a dedicated admin router here.
|
||||
- Pattern: `backend/innercontext/api/profile.py:41` - Simple patch/upsert route style for small admin mutation endpoints.
|
||||
- Pattern: `backend/innercontext/api/utils.py:9` - Error-handling pattern to preserve with tenant-aware replacements.
|
||||
- API/Type: `backend/innercontext/models/profile.py:13` - Example of owned record exposed without extra wrapper models.
|
||||
- Test: `backend/tests/conftest.py:34` - Dependency-override style for admin/member API tests.
|
||||
|
||||
**Acceptance Criteria** (agent-executable only):
|
||||
- [ ] Backend exposes admin-only household endpoints for list/create/assign/move/remove operations.
|
||||
- [ ] Membership moves preserve the one-household-per-user rule.
|
||||
- [ ] Membership assignment only works for users already present in the local `users` table.
|
||||
- [ ] Admin-route tests cover admin success, member denial, and attempted assignment of unsynced users.
|
||||
|
||||
**QA Scenarios** (MANDATORY - task incomplete without these):
|
||||
```
|
||||
Scenario: Admin can create a household and assign a logged-in member
|
||||
Tool: Bash
|
||||
Steps: Run `cd backend && uv run pytest tests/test_admin_households.py -k 'create_household or assign_member' > ../.sisyphus/evidence/task-T9-admin-households.txt`
|
||||
Expected: Tests pass and evidence shows admin-only success cases
|
||||
Evidence: .sisyphus/evidence/task-T9-admin-households.txt
|
||||
|
||||
Scenario: Member cannot manage households and unsynced users cannot be assigned
|
||||
Tool: Bash
|
||||
Steps: Run `cd backend && uv run pytest tests/test_admin_households.py -k 'forbidden or unsynced' > ../.sisyphus/evidence/task-T9-admin-households-denied.txt`
|
||||
Expected: Tests pass and evidence shows `403`/validation failures for forbidden assignments
|
||||
Evidence: .sisyphus/evidence/task-T9-admin-households-denied.txt
|
||||
```
|
||||
|
||||
**Commit**: YES | Message: `feat(api): add admin household management endpoints` | Files: `backend/main.py`, `backend/innercontext/api/admin*.py`, related tests
|
||||
|
||||
- [x] T10. Update runtime configuration, validation scripts, deploy checks, and operator docs for OIDC
|
||||
|
||||
**What to do**: Update runtime configuration for both services so frontend and backend receive the new OIDC/session env vars at runtime, and document the exact Authelia client/server setup required. Keep nginx in a pure reverse-proxy role (no `auth_request`), but make sure forwarded host/proto information remains sufficient for callback URL generation. Extend `scripts/validate-env.sh` and deploy validation so missing auth env vars fail fast, and update `scripts/healthcheck.sh` plus `deploy.sh` health expectations because authenticated pages may now redirect to login instead of returning `200` for signed-out probes. Document bootstrap-admin env usage for the migration.
|
||||
**Must NOT do**: Do not add proxy-level auth, do not require manual post-deploy DB edits, and do not leave deploy health checks assuming `/` must return `200` when the app intentionally redirects signed-out users.
|
||||
|
||||
**Recommended Agent Profile**:
|
||||
- Category: `writing` - Reason: configuration, deployment, and operator-facing documentation dominate this task
|
||||
- Skills: `[]` - Repo docs and service files are the governing references
|
||||
- Omitted: `svelte-code-writer` - No Svelte component changes needed
|
||||
|
||||
**Parallelization**: Can Parallel: YES | Wave 3 | Blocks: T11 | Blocked By: T3, T7
|
||||
|
||||
**References** (executor has NO interview context - be exhaustive):
|
||||
- Pattern: `nginx/innercontext.conf:1` - Current reverse-proxy setup that must remain proxy-only.
|
||||
- Pattern: `deploy.sh:313` - Service-wait and health-check functions to update for signed-out redirects and auth env validation.
|
||||
- Pattern: `deploy.sh:331` - Backend/frontend health-check behavior currently assuming public app pages.
|
||||
- Pattern: `scripts/validate-env.sh:57` - Existing required-env validation script to extend with OIDC/session/bootstrap keys.
|
||||
- Pattern: `scripts/healthcheck.sh:10` - Current frontend health check that assumes `/` returns `200`.
|
||||
- Pattern: `systemd/innercontext.service` - Backend runtime env injection point.
|
||||
- Pattern: `systemd/innercontext-node.service` - Frontend runtime env injection point.
|
||||
- Pattern: `docs/DEPLOYMENT.md` - Canonical operator runbook to update.
|
||||
|
||||
**Acceptance Criteria** (agent-executable only):
|
||||
- [ ] Backend and frontend runtime configs declare/document all required OIDC/session/bootstrap env vars.
|
||||
- [ ] Deploy validation fails fast when required auth env vars are missing.
|
||||
- [ ] Frontend health checks accept the signed-out auth redirect behavior or target a public route that remains intentionally available.
|
||||
- [ ] Deployment docs describe Authelia client config, callback/logout URLs, JWKS/issuer envs, and bootstrap-migration envs.
|
||||
|
||||
**QA Scenarios** (MANDATORY - task incomplete without these):
|
||||
```
|
||||
Scenario: Deploy validation rejects missing auth configuration
|
||||
Tool: Bash
|
||||
Steps: Run `scripts/validate-env.sh` (or the deploy wrapper that calls it) with one required OIDC/session variable removed, and redirect output to `.sisyphus/evidence/task-T10-missing-env.txt`
|
||||
Expected: Validation exits non-zero and names the missing variable
|
||||
Evidence: .sisyphus/evidence/task-T10-missing-env.txt
|
||||
|
||||
Scenario: Signed-out frontend health behavior matches updated deployment expectations
|
||||
Tool: Bash
|
||||
Steps: Run the updated `scripts/healthcheck.sh` or deploy health-check path and save output to `.sisyphus/evidence/task-T10-health-check.txt`
|
||||
Expected: Evidence shows a successful probe despite protected app routes (either via accepted redirect or a dedicated public health target)
|
||||
Evidence: .sisyphus/evidence/task-T10-health-check.txt
|
||||
```
|
||||
|
||||
**Commit**: YES | Message: `chore(deploy): wire OIDC runtime configuration` | Files: `nginx/innercontext.conf`, `deploy.sh`, `scripts/validate-env.sh`, `scripts/healthcheck.sh`, `systemd/*`, `docs/DEPLOYMENT.md`
|
||||
|
||||
- [ ] T11. Add shared auth fixtures, full regression coverage, and CI enforcement
|
||||
|
||||
**What to do**: Build reusable backend test fixtures for authenticated users, roles, households, and shared inventory, then add regression tests covering auth sync, unauthenticated access, admin/member authorization, household inventory sharing, routine/product visibility, and migration-sensitive ownership behavior. Use dependency overrides in tests instead of hitting a live Authelia server. Enable the existing backend CI job so these tests run in Forgejo, and make sure the final verification command set includes backend tests, lint, frontend check/lint/build, and any required API type generation.
|
||||
**Must NOT do**: Do not depend on a live Authelia instance in CI, do not leave the backend test job disabled, and do not add a committed frontend browser test suite in this pass.
|
||||
|
||||
**Recommended Agent Profile**:
|
||||
- Category: `unspecified-high` - Reason: broad regression coverage plus CI wiring across the monorepo
|
||||
- Skills: `[]` - Existing pytest/CI patterns are sufficient
|
||||
- Omitted: `playwright` - Browser QA stays agent-executed, not repository-committed
|
||||
|
||||
**Parallelization**: Can Parallel: NO | Wave 3 | Blocks: Final verification | Blocked By: T2, T3, T4, T5, T6, T7, T8, T9, T10
|
||||
|
||||
**References** (executor has NO interview context - be exhaustive):
|
||||
- Pattern: `backend/tests/conftest.py:16` - Per-test DB isolation and dependency override technique.
|
||||
- Pattern: `backend/tests/test_products.py:4` - Existing endpoint-test style to mirror for authz coverage.
|
||||
- Pattern: `.forgejo/workflows/ci.yml:83` - Disabled backend test job that must be enabled.
|
||||
- Pattern: `frontend/package.json:6` - Final frontend verification commands available in the repo.
|
||||
- Pattern: `backend/pyproject.toml` - Pytest command/config surface for any new test files.
|
||||
|
||||
**Acceptance Criteria** (agent-executable only):
|
||||
- [ ] Shared auth fixtures exist for admin/member identities, household membership, and shared inventory setup.
|
||||
- [ ] Backend tests cover `401`, owner success, admin override, same-household shared inventory update, and different-household denial across representative routes.
|
||||
- [ ] Forgejo backend tests run by default instead of being gated by `if: false`.
|
||||
- [ ] Final command set passes: backend tests + lint, frontend check + lint + build, and API type generation only if required by backend schema changes.
|
||||
|
||||
**QA Scenarios** (MANDATORY - task incomplete without these):
|
||||
```
|
||||
Scenario: Full backend auth regression suite passes locally
|
||||
Tool: Bash
|
||||
Steps: Run `cd backend && uv run pytest > ../.sisyphus/evidence/task-T11-backend-regression.txt`
|
||||
Expected: Evidence file shows the full suite passing, including new auth/tenancy tests
|
||||
Evidence: .sisyphus/evidence/task-T11-backend-regression.txt
|
||||
|
||||
Scenario: CI config now runs backend tests instead of skipping them
|
||||
Tool: Bash
|
||||
Steps: Read `.forgejo/workflows/ci.yml`, confirm the backend-test job no longer contains `if: false`, and save a grep extract to `.sisyphus/evidence/task-T11-ci-enabled.txt`
|
||||
Expected: Evidence shows the backend-test job is active and executes `uv run pytest`
|
||||
Evidence: .sisyphus/evidence/task-T11-ci-enabled.txt
|
||||
```
|
||||
|
||||
**Commit**: YES | Message: `test(auth): add multi-user regression coverage` | Files: `backend/tests/*`, `.forgejo/workflows/ci.yml`
|
||||
|
||||
## Final Verification Wave (4 parallel agents, ALL must APPROVE)
|
||||
- [ ] F1. Plan Compliance Audit - oracle
|
||||
- [ ] F2. Code Quality Review - unspecified-high
|
||||
- [ ] F3. Real Manual QA - unspecified-high (+ playwright if UI)
|
||||
- [ ] F4. Scope Fidelity Check - deep
|
||||
|
||||
## Commit Strategy
|
||||
- Use atomic commits after stable checkpoints: Wave 1 foundation, Wave 2 application integration, Wave 3 infra/tests.
|
||||
- Prefer conventional commits with monorepo scopes such as `feat(auth): ...`, `feat(frontend): ...`, `feat(api): ...`, `test(auth): ...`, `chore(deploy): ...`.
|
||||
- Do not merge unrelated refactors into auth/tenancy commits; keep schema, auth flow, frontend session, and infra/test changes reviewable.
|
||||
|
||||
## Success Criteria
|
||||
- Every protected route and API request resolves a concrete current user before touching owned data.
|
||||
- Non-admin users cannot read or mutate records outside their ownership, except household-shared inventory entries.
|
||||
- Household members can view/update shared inventory without gaining product edit rights.
|
||||
- Existing single-user data survives migration and becomes accessible to the bootstrap admin account after first login.
|
||||
- Frontend protected navigation/login/logout flow works without browser-stored bearer tokens.
|
||||
- Backend test suite and CI catch auth regressions before deploy.
|
||||
Loading…
Add table
Add a link
Reference in a new issue