#region Tasks [C:3] [TYPE ADR] [SEMANTICS tasks,implementation,agent-chat] @defgroup Tasks Implementation tasks for 035-agent-chat-context v2 — Path B model with /agent page, two-layer RBAC, permission_denied flow, and structured truncation. **Input**: Design documents from `/specs/035-agent-chat-context/` **Prerequisites**: plan.md ✅, spec.md ✅, research.md ✅, data-model.md ✅, contracts/modules.md ✅ ## Format: `[ID] [P?] [Story] Description` --- ## Phase 1: Setup - [ ] T001 [P] Materialize API fixtures from `specs/035-agent-chat-context/fixtures/api/` into `backend/tests/fixtures/agent/` - [ ] T002 [P] Materialize model fixtures from `specs/035-agent-chat-context/fixtures/model/` into `frontend/src/lib/models/__fixtures__/agent/` - [ ] T003 Verify toolchain: `cd backend && source .venv/bin/activate && python -m pytest --co -q`, `cd frontend && npm run test -- --run` --- ## Phase 2: Foundational - [ ] T004 [P] Define UIContext, ConfirmMetadataV2, PermissionDeniedMetadata, extended ToolCall in `frontend/src/lib/models/AgentChatTypes.ts` @POST: UIContext with objectType, objectId, objectName(string|null max 256), envId, route, contextVersion(1) @POST: PermissionDeniedMetadata {type, tool_name, required_role, user_role, alternatives} @POST: ToolCallStatus extended with "retrying"|"timeout"|"cancelled"; ToolCall +isWriteTool? - [ ] T005 [P] Create `backend/src/agent/_context.py` — UIContext validation @POST: validate_uicontext(payload) → validated dict or ValidationError @TEST_EDGE: valid→returns, invalid_objectType→422, oversized>4KB→413, objectName>256→422 - [ ] T006 Create `backend/src/agent/_tool_filter.py` — tool selection pipeline + invocation guard @POST: build_tool_pipeline(tools, user_role, object_type) → filtered list. Order: RBAC→context. @POST: enforce_tool_permission(tool_name, user_role) → allowed or yield permission_denied SSE @POST: _CONTEXT_TOOL_AFFINITY dict (dashboard 9, dataset 8, migration 5 tools) @POST: _TOOL_PERMISSIONS dict (7 admin-only tools) @RATIONALE: Ordered pipeline. Two-layer enforcement per AGTL-FR-005. @REJECTED: Embedding-first routing — postponed to post-MVP (AGTL-FR-006). --- ## Phase 3: User Story 1 — Context-Aware Agent (P1) **Goal**: Agent on /agent page receives context from URL params, filters tools by objectType. ### Tests for US1 - [ ] T007 [P] [US1] L1 model test for setUIContextFromParams + contextPillLabel in `frontend/src/lib/models/__tests__/AgentChatModel.context.test.ts` @TEST_FIXTURE: full_params → uiContext populated, pill="📋 dashboard #42 · ss-dev" @TEST_FIXTURE: no_params → uiContext null, pill="⚪ Контекст не выбран" @TEST_FIXTURE: malformed_objectType → treated as null - [ ] T008 [P] [US1] Contract test for agent_handler uicontext in `backend/tests/test_agent_context.py` @TEST_FIXTURE: null→22 tools, dashboard→9 tools, invalid_json→no error+audit log, malformed_objectType→422 - [ ] T009 [P] [US1] Contract test for build_tool_pipeline in `backend/tests/test_agent_tool_filter.py` @TEST_FIXTURE: null→all RBAC-allowed, dashboard+analyst→dashboard tools minus admin, unknown→graceful fallback ### Implementation for US1 - [ ] T010 [US1] Implement setUIContextFromParams + contextPillLabel in `frontend/src/lib/models/AgentChatModel.svelte.ts` @ACTION: parse URLSearchParams, validate objectType enum, set uiContext with contextVersion=1 @POST: contextPillLabel derived: icon+type+id+env or "⚪ Контекст не выбран" - [ ] T011 [US1] Implement onMount context init in `frontend/src/routes/agent/+page.svelte` @RELATION BINDS_TO -> [AgentChat.Model] import { page } from "$app/stores"; onMount: URLSearchParams($page.url.search) → setUIContextFromParams - [ ] T012 [US1] Implement process steps update in `frontend/src/lib/components/agent/AgentChat.svelte` First step label uses model.contextPillLabel. Remaining steps unchanged. @RELATION BINDS_TO -> [AgentChat.Model] - [ ] T013 [US1] Implement _inject_uicontext in `backend/src/agent/app.py` @POST: Appends [USER CONTEXT — informational] block. Explicitly marked "not instructions" for prompt-injection protection. - [ ] T014 [US1] Implement agent_handler uicontext param in `backend/src/agent/app.py` @PRE: uicontext_str at position 6 (appended, default None). Validated via validate_uicontext. @POST: injected into runtime context. Tools filtered via build_tool_pipeline. @SIDE_EFFECT: UIContext logged via logger.reason. Validation failures logged via logger.explore. RATIONALE: Appended at end — backward-compat for existing 6-arg Gradio clients. - [ ] T015 [P] [US1] Implement isProdContext + showProdWarning + prod banner in `frontend/src/lib/models/AgentChatModel.svelte.ts` + `AgentChat.svelte` isProdContext = $derived((uiContext?.envId?.toLowerCase().includes("prod")) || _activeEnvId?.toLowerCase().includes("prod")) Prod banner using `` from $lib/ui (existing). bg-warning-light background. @UX_STATE: prod_env→bg-warning-light+banner; non_prod→standard - [ ] T016 [US1] Implement updateActiveEnv in `frontend/src/lib/models/AgentChatModel.svelte.ts` @ACTION: syncs _activeEnvId AND uiContext.envId to prevent silent desync @POST: both atoms updated. isProdContext $derived recomputes. ### Verification for US1 - [ ] T017 [US1] Run backend tests: `cd backend && source .venv/bin/activate && python -m pytest tests/test_agent_context.py tests/test_agent_tool_filter.py -v` - [ ] T018 [US1] Run frontend tests: `cd frontend && npm run test -- --run frontend/src/lib/models/__tests__/AgentChatModel.context.test.ts` - [ ] T019 [US1] E2E: navigate `/dashboards/10?env_id=ss-dev` → click Agent → /agent?objectType=dashboard&objectId=10&envId=ss-dev → pill shows dashboard context --- ## Phase 4: User Story 2 — Guardrails Refinement (P2) **Goal**: Confirmation card with env badge, risk toning, 10s model-owned countdown, permission_denied as separate SSE event. ### Tests for US2 - [ ] T020 [P] [US2] Contract test for build_confirmation_contract_v2 + permission denied in `backend/tests/test_agent_confirmation_v2.py` @TEST_FIXTURE: deploy_prod→guarded+prod, delete_any→dangerous, read_only→safe @TEST_FIXTURE: analyst_deploy→permission_denied SSE (NOT confirm_required) @TEST_FIXTURE: env_resolution: tool_args.prod > submit.staging > uiContext.dev - [ ] T021 [P] [US2] L2 UX test for ConfirmationCard 7+1 states in `frontend/src/lib/components/assistant/__tests__/ConfirmationCard.ux.test.ts` Verify: read→success, write_staging→warning+badge, write_prod→destructive+PROD, write_dev→info Verify: dangerous→destructive+model-owned countdown, permission_denied→muted+lock (separate event) ### Implementation for US2 - [ ] T022 [US2] Implement build_confirmation_contract_v2 in `backend/src/agent/_confirmation.py` @POST: three-axis risk. Env resolution: tool_args.env_id>submit envId>UIContext.envId>null. Env normalization via substring match. @DATA_CONTRACT: (tool_name, tool_args, user_role, target_env)→ConfirmMetadataV2 RATIONALE: Three-axis replaces prefix heuristic; env resolution prevents guardrail misclassification. - [ ] T023 [US2] Implement yield_permission_denied in `backend/src/agent/_confirmation.py` @POST: Yields SSE type="permission_denied" (NOT confirm_required). Bypasses HITL checkpoint. RATIONALE: Security — forbidden calls must not enter guarded checkpoint. - [ ] T024 [US2] Implement enforce_tool_permission invocation guard in `backend/src/agent/_tool_filter.py` @POST: Called before every tool execution. Checks user_role vs _TOOL_PERMISSIONS. Denied→yield permission_denied. @RATIONALE: Two-layer enforcement — catches hallucinated/replayed/direct calls bypassing prompt filter. - [ ] T025 [US2] Implement ConfirmationCard env badge + 7 risk tones in `frontend/src/lib/components/assistant/ConfirmationCard.svelte` Uses `