Skip to content

feat(mcp): hermiq's conversational intake can file a case through dossiq.fileCase - #3607

Merged
rubenvdlinde merged 29 commits into
developmentfrom
build/dq-l6-4
Oct 12, 2026
Merged

rubenvdlinde merged 29 commits into
developmentfrom
build/dq-l6-4

Conversation

@rubenvdlinde

@rubenvdlinde rubenvdlinde commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

What a user can now do

  • hermiq's conversational intake can file a case: dossiq.fileCase writes through the create form's own path, so a resident's conversation ends in a real case or in a handover to a person, never in a half-filed one.
  • A beheerder can say per case type where each AI feature appears (case, intake or none). Which model runs it, and where, stays in hermiq.

Changes

ai-features-on-the-case-consume-hermiq

  • 5.1 lib/Service/Mcp/IntakeTools.php: dossiq.fileCase with the citizenIntake mark, scope: create, action: create, reach: instance (decision 177). The six curated reads carry outsideAgent for hermiq's outbound surface (design D-5).
  • 5.2 lib/Service/Intake/CaseIntakeFiling.php: one saveObject() on the case schema, as the caller, never elevated; allowlisted payload (title, caseType, intakeChannel website, description from the transcript, initiatorDisplayName from hermiq's person); published case type by id or identifier. A refusal from the schema, intake requirements, duplicate policy or RBAC is thrown, so OpenRegister audits the call as failed and hermiq hands over. No intermediate intake object (decision 179).
  • 1.1 lib/Settings/register.d/43-case-type-ai-features.json: caseType.aiFeatures; register 0.20.25, info.xml bumped; en/nl strings.
  • 1.2, 2.1, 7.1, 7.2 ticked: already on development, file references in tasks.md.
  • screens.md added (DqZaakAssistent). Design D-5 and REQ-AIC-05 amended: the tool is dossiq.fileCase (the hand-written DossiqToolProvider the design named is gone), recognised by mark plus create scope/action.
  • Still open: 2.2, 3.1, 3.2, 4.x, 5.3, 6.1, 8.x. 3.1 needs a hermiq endpoint that runs an AI feature on a document reference; today only the assistant converse exists and it takes no feature or document (decision 156: a dependency to build in hermiq).

hermiq-ai-tooling

  • REQ-MCP-206 rewritten per decision 176: approval is hermiq policy; dossiq declares no approval floor and ships no grant or waiver. Design D2's approval column now reads as hermiq's default. 4.3 CHANGELOG entry. Archive after openregister#4546 lands (only 4.1, 4.2 and live 5.x remain).

Assumption (unattended)

hermiq's person is the conversation's own key for the resident (often an e-mail address), not a person object, so it fills initiatorDisplayName and leaves requester empty.

Stack and dependencies

Stacked on #3583 (< #3567 < #3558). Needs on the instance, in this order: openregister#4546 (reach), openregister#4554 (annotations), and hermiq#1147 (intake recognition). Against an OpenRegister without them #[McpTool(annotations: ...)] does not instantiate and the scanner skips the tool: absent, never wrongly marked. CI's StubApiDriftTest compares tests/Stubs/Mcp/Attribute/McpTool.php with the real attribute, so land this after openregister#4554.

New classes and their tests

  • CaseIntakeFiling: tests/Unit/Service/Intake/CaseIntakeFilingTest.php (7 tests: the write, identifier lookup, payload against the real case schema, missing subject, draft-only type, refusal from the create path and from RBAC, no storage).
  • IntakeTools: tests/Unit/Service/Mcp/IntakeToolsTest.php (3 tests).
  • Register: tests/Unit/Service/Ai/CaseTypeAiFeaturesDeclarationTest.php.

Verified locally (diff checks)

  • PHPUnit on touched classes, exit 0: CaseIntakeFilingTest 7, IntakeToolsTest 3, DossiqScannableServicesTest 6 (incl. testOnlyTheCreateToolCarriesTheIntakeMark, testOnlyTheReadsAreOfferedToTheOutsideSurface), DossiqMcpDialectTest 5, ReportingToolsTest 7, CaseToolsTest 14, ComplaintServiceTest 23, CaseTypeAiFeaturesDeclarationTest 3, AiSettingsControllerShapeTest 5.
  • phpcs on changed lib files: 0 errors.
  • check-schema-l10n: 0 uncovered; tests/l10n/check-l10n.js: OK (canonical order).
  • phpstan on changed files: no errors, exit 0.
  • Full composer check:strict / npm run lint: not run locally, the shared build slots were queued for over 30 minutes; CI is the full check.

Twelve schemas declare a curated x-openregister-mcp block, so OpenRegister
derives 20 read tools (dossiq.case.search, dossiq.statusRecord.search, ...).
The hand-written DossiqToolProvider and its helpers are deleted, so nothing
shadows the derived tools. OpenRegister RBAC is the only gate.

Archives dossiq-mcp-adoption; live tasks 4.1-4.4 stay owed (decision 139).
A change outside properties/required/authorization only reaches an instance
when the schema version moves (SchemaVersionFloorTest). Digests regenerated.
…nd workload figures

First IMcpScannableServices opt-in (DossiqScannableServices, registered under
OpenRegister's per-app alias). Curated #[McpTool] reads: getDeadlineDashboard,
getDoorlooptijdMetrics, getKpiOverview, getWorkload (ReportingTools),
listAvailableTransitions (CaseTools) and listOverdueComplaints on
ComplaintService, a projection that never carries the complainant. Each tool
runs the gate its controller runs, then calls the owning service.
…creens.md for the touched specs and the archived change
# Conflicts:
#	lib/Settings/dossiq_register.json
#	lib/Settings/register.d/60-termijnbewaking.json
#	tests/schemas/schema-version-digests.json
# Conflicts:
#	lib/Settings/dossiq_register.json
#	lib/Settings/register.d/60-termijnbewaking.json
#	tests/schemas/schema-version-digests.json
…them without a grant

Every curated read (deadline dashboard, lead times, KPIs, workload, available
transitions, overdue complaints) now declares reach: 'user'. Without it a
two-segment id resolves to external and needs an explicit grant.
Needs openregister build/dep-dossiq-mcptool-reach on the instance first.
… and work its terms

Curated write tools, each on the service its controller calls:
transitionCase (StatusTransitionService, guards and status record intact),
reassignCase (new CaseAssignmentService::reassign, coordinators only, the
receiver is notified), completeTask (the engine's complete verb),
extendDeadline/pauseDeadline/resumeDeadline (new TermTools: the term is read
and its CASE must be changeable by the caller before the term services run).
Refusals come back as envelopes with the service's own rule and sentence.

WIP: AppointmentTools and BeschikkingTools are listed but not written yet.
…chikking

AppointmentTools (scheduleAppointment, cancelAppointment; external reach: the
resident is told) run AppointmentController's case checks and call
AppointmentService. BeschikkingTools offers draftBeschikking only, through
BeschikkingService::compose(); approving, signing and sending stay with the
caseworker. A test holds the tool classes off ObjectService.

hermiq-ai-tooling 3.1-3.3 ticked; the spec names the services as found.
# Conflicts:
#	lib/Settings/register.d/60-termijnbewaking.json
#	tests/schemas/schema-version-digests.json
# Conflicts:
#	.debt-baseline.json
#	appinfo/info.xml
#	lib/Settings/dossiq_register.json
#	lib/Settings/register.d/60-termijnbewaking.json
#	tests/schemas/schema-version-digests.json
# Conflicts:
#	lib/Settings/register.d/60-termijnbewaking.json
#	tests/schemas/schema-version-digests.json
…duleAppointment (phpmd finds nothing without it)
…s no approval floor

Decision 176 (Q-dossiq-L6-2): REQ-MCP-206 now says hermiq decides which AI
writes wait for a person. dossiq declares readOnlyHint: false and a scope on
every write so hermiq can gate it, and ships no grant or waiver. CHANGELOG
entry for the curated tools (task 4.3).
…siq.fileCase

dossiq.fileCase carries the citizenIntake mark with scope and action create,
which is how hermiq now recognises an intake tool (decision 177). It writes
through the create form's own path: one save on the case schema as the caller,
so the schema, the intake requirements, the duplicate policy and RBAC all run,
and a refusal is thrown so hermiq hands the resident to a person. No
intermediate intake object (decision 179). The six curated reads carry
outsideAgent for hermiq's outbound surface.

ai-features-on-the-case-consume-hermiq 5.1, 5.2; screens.md added.
caseType.aiFeatures (register fragment 43) maps hermiq's feature slug to
case, intake or none, and holds no provider, model or residency. Register
0.20.25, info.xml bumped, en/nl strings. Ticks ai-features 1.1, and 1.2/2.1
with the files that already carry them.
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/dossiq @ 864ce70

Check PHP Vue Security License Tests
lint ✅
phpcs ✅
phpmd ❌
psalm ✅
phpstan ✅
phpmetrics ✅
eslint ✅
stylelint ✅
build ✅
check-manifest ✅
check-vue3-compile ✅
test-l10n ✅
format ✅
check-schema-l10n ✅
check-l10n-js ✅
check-debt-ratchet ✅
check-types-e2e ✅
composer ✅ ✅ 109/109
npm ✅ ✅ 659/659
app:check-code ⏭️
info.xml ✅
REUSE ❌
lockfile sync ✅
PHPUnit ❌ 7026/7028 · 3 skipped
Newman ⏭️
Playwright ⏭️ deferred: E2E runs locally and on the promotion path only. This pull request targets development, so the suite is asked once per promotion into beta and main rather than once per push per open pull request. Run it locally with npx playwright test, or from the Actions tab on a branch with no open pull request into development.
Hydra gates ❌

Quality workflow — 2026-10-10 14:56 UTC

Download the full PDF report from the workflow artifacts.

…spelled-out alias (gate 57 could not see AppointmentTools)
…y in CaseIntakeFiling (phpmd), REQ-MCP-206 anchor follows the rewritten heading (gate 46)
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/dossiq @ 838884c

Check PHP Vue Security License Tests
lint ✅
phpcs ✅
phpmd ❌
psalm ✅
phpstan ✅
phpmetrics ✅
eslint ✅
stylelint ✅
build ✅
check-manifest ✅
check-vue3-compile ✅
test-l10n ✅
format ✅
check-schema-l10n ✅
check-l10n-js ✅
check-debt-ratchet ✅
check-types-e2e ✅
composer ✅ ✅ 109/109
npm ✅ ✅ 659/659
app:check-code ⏭️
info.xml ✅
REUSE ❌
lockfile sync ✅
PHPUnit ❌ 7027/7028 · 3 skipped
Newman ⏭️
Playwright ⏭️ deferred: E2E runs locally and on the promotion path only. This pull request targets development, so the suite is asked once per promotion into beta and main rather than once per push per open pull request. Run it locally with npx playwright test, or from the Actions tab on a branch with no open pull request into development.
Hydra gates ❌

Quality workflow — 2026-10-10 16:28 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/dossiq @ 795ee45

Check PHP Vue Security License Tests
lint ✅
phpcs ✅
phpmd ✅
psalm ✅
phpstan ✅
phpmetrics ✅
eslint ✅
stylelint ✅
build ✅
check-manifest ✅
check-vue3-compile ✅
test-l10n ✅
format ✅
check-schema-l10n ✅
check-l10n-js ✅
check-debt-ratchet ❌
check-types-e2e ✅
composer ✅ ✅ 109/109
npm ✅ ✅ 659/659
app:check-code ⏭️
info.xml ✅
REUSE ❌
lockfile sync ✅
PHPUnit ❌ 7027/7028 · 3 skipped
Newman ⏭️
Playwright ⏭️ deferred: E2E runs locally and on the promotion path only. This pull request targets development, so the suite is asked once per promotion into beta and main rather than once per push per open pull request. Run it locally with npx playwright test, or from the Actions tab on a branch with no open pull request into development.
Hydra gates ❌

Quality workflow — 2026-10-10 16:54 UTC

Download the full PDF report from the workflow artifacts.

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.

1 participant