Skip to content

feat(#4): ticket intake form — US-012#5

Open
smarcetic wants to merge 6 commits into
mainfrom
design/4-ticket-intake-form
Open

feat(#4): ticket intake form — US-012#5
smarcetic wants to merge 6 commits into
mainfrom
design/4-ticket-intake-form

Conversation

@smarcetic

Copy link
Copy Markdown

Summary

Implements US-012: as a field technician, I want a web-based intake form so I can submit support requests without cURL or API tooling.

Closes #4


What's in this PR

Layer File Status
Architecture docs/adr/ADR-0005-intake-form-templating.md ✅ committed
Tests tests/test_intake_form.py ✅ 10 xfail + 1 regression passing
Implementation src/triage_assistant/api/templates/intake.html ❌ needs implementation
Implementation src/triage_assistant/api/main.py (GET /) ❌ needs implementation
Implementation pyproject.toml (jinja2 dep) ❌ needs implementation

TDD Status

All 10 intake form tests are xfail(strict=True). Regression test passes now.

Verified: uv run pytest -> 4 passed, 10 xfailed, 0 failed

Remove @pytest.mark.xfail decorators once all tests pass — do not modify the assertions.


Implementation instructions

  1. Add jinja2>=3.1.0 to pyproject.toml and run uv sync
  2. Create src/triage_assistant/api/templates/intake.html — all 6 HelpRequest fields with required attribute, noscript warning, vanilla JS fetch() POST to /triage
  3. In main.py: mount Jinja2Templates + GET / route returning TemplateResponse
  4. Remove all @pytest.mark.xfail decorators once tests pass

Do not change the POST /triage request/response schema. Data contract is locked per ADR-0005.

Design: docs/adr/ADR-0005-intake-form-templating.md

smarcetic added 2 commits May 13, 2026 20:01
All 10 form tests are marked xfail(strict=True) — they pass once the
implementation is complete (jinja2 dep, GET / route, intake.html).

The regression test (test_health_route_unaffected_by_intake_form) passes
now and must continue to pass after implementation.

Verified: uv run pytest -> 4 passed, 10 xfailed, 0 failed

AC coverage:
- AC-1: 200 + text/html response
- AC-2: required attribute on all 6 inputs
- AC-4: content-type confirms Jinja2 template path
- AC-5: all 6 HelpRequest field names present in rendered HTML
- ADR-0005: <noscript> warning present

Design: docs/adr/ADR-0005-intake-form-templating.md
Copilot AI review requested due to automatic review settings May 14, 2026 00:21

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR sets up the test-first scaffolding for US-012 (a browser-based intake form for field contractors), adding a new ADR that selects Jinja2 templating with a JS fetch() submission strategy and a pytest module of xfail-marked behavioral tests against a future GET / route. Implementation files (intake.html, main.py route, pyproject.toml dependency) are deliberately deferred to a follow-up per the PR description.

Changes:

  • Add ADR-0005 documenting the Jinja2 + vanilla fetch() decision and the locked HelpRequest/TriageResult data contract.
  • Add tests/test_intake_form.py with 10 xfail(strict=True) async tests covering AC-1, AC-2, AC-4, AC-5 and a non-xfail /health regression test.
  • Document an httpx.ASGITransport helper to bypass FastAPI lifespan startup in CI.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
docs/adr/ADR-0005-intake-form-templating.md New ADR choosing Jinja2 + JS fetch() and locking the POST /triage contract.
tests/test_intake_form.py New TDD test suite for GET / (xfail) plus a /health regression test.
Comments suppressed due to low confidence (2)

tests/test_intake_form.py:35

  • All test functions in this file are declared async def, but none carry an @pytest.mark.asyncio (or anyio) marker, and there is no pyproject.toml/pytest.ini in the repo configuring asyncio_mode = "auto" or registering pytest-asyncio. Without that, plain pytest will not await the coroutines: it emits a PytestUnhandledCoroutineWarning and the tests do not actually execute the assertions. Combined with xfail(strict=True), this means once triage_assistant is importable, the xfail tests will likely flip to XPASS/ERROR rather than the intended "xfailed" state. Please add pytest-asyncio (or anyio) as a dev dependency and configure it (e.g. asyncio_mode = "auto" or per-test markers) so these async tests are actually driven.
async def _get(path: str) -> httpx.Response:
    async with httpx.AsyncClient(
        transport=httpx.ASGITransport(app=app), base_url="http://test"
    ) as client:
        return await client.get(path)

tests/test_intake_form.py:109

  • response.text.count("required") >= 6 is a brittle proxy for "every input has the required attribute". The substring "required" can match unrelated copy in labels, error-message text, the <noscript> warning, JS validation strings, ADR comments, or even a CSS class. The assertion can pass without any input element actually having the required attribute, and conversely could fail in a perfectly valid template that happens to also use the word elsewhere. Consider parsing the HTML (e.g. with html.parser/BeautifulSoup) and asserting that each of the six named inputs/textareas carries the required attribute, or at minimum match required adjacent to each name="…" attribute.
    response = await _get("/")
    assert response.text.count("required") >= 6

Comment thread tests/test_intake_form.py
import pytest
import httpx

from triage_assistant.api.main import app
Comment on lines +138 to +139
- [ADR-0001 — Python Triage Architecture](ADR-0001-python-triage-architecture.md) — API contract (HelpRequest / TriageResult)
- [ADR-0002 — API Framework](ADR-0002-api-framework.md) — FastAPI + uvicorn decisions
- Add jinja2>=3.1.0 to pyproject.toml
- Mount Jinja2Templates in api/main.py; add GET / route
- Create src/triage_assistant/api/templates/intake.html
  - All 6 HelpRequest fields with required attribute
  - <noscript> warning for JS-disabled browsers
  - Vanilla JS fetch() POST to /triage with result display
  - Secure HTML escaping in result renderer
- Remove @pytest.mark.xfail decorators now that all tests pass

POST /triage request/response contract unchanged (ADR-0001, ADR-0005).
uv run pytest -> 11 passed, 0 failed
@shawnewallace

Copy link
Copy Markdown
Contributor

We will not be merging your solution to main. You should just keep in your team's branch.

smarcetic added 3 commits May 15, 2026 10:21
…lient updates

- Updated ADR-0004 to reflect the use of `azure.ai.inference.aio.EmbeddingsClient` for embeddings in the POC, replacing `FoundryEmbeddingClient`.
- Specified the embedding model as `cohere-embed-v3-english`, highlighting serverless MaaS availability.
- Revised rationale to clarify the transition from `FoundryEmbeddingClient` to `AsyncEmbeddingsClient` due to RBAC constraints.
- Enhanced production upgrade path documentation for Azure AI Search integration.
- Updated decision history to capture changes in embedding client and model.
- Modified pitch deck to reflect current architecture and production path.
- Implemented `InMemoryTriageQueueStore` for persisting classified requests, including methods for saving and listing classified requests.
- Introduced `ITriageQueueStore` interface for queue storage, ensuring non-fatal behavior on save failures in `TriageService`.
- Added tests for `InMemoryTriageQueueStore` to validate functionality and ensure compliance with acceptance criteria.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

US-012 · Ticket Intake Form — Field Contractor Support Submission

3 participants