Skip to content

feat: build open OpenSpec changes (dossiq L6, part 3): agent write tools with reach - #3583

Merged
rubenvdlinde merged 22 commits into
developmentfrom
build/dq-l6-3
Oct 12, 2026
Merged

rubenvdlinde merged 22 commits into
developmentfrom
build/dq-l6-3

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

What an agent can now do

hermiq-ai-tooling phase 3: an assistant (through hermiq) can move a case on, hand it to another handler, complete a task, extend, pause or resume a statutory term, book or cancel an appointment, and draft a beschikking. Every tool runs the check its controller runs and calls the service its controller calls; refusals come back as envelopes with the service's own rule and sentence. All 15 curated tools now declare their reach (REQ-MCP-205): reads user, case and term writes instance, appointments external, the beschikking draft user.

Stacked on #3567 (< #3558). Must land AFTER ConductionNL/openregister#4546 (reach on #[McpTool]): against an OpenRegister without that parameter the attribute fails to instantiate and the scanner skips the tool.

Changes

  • hermiq-ai-tooling: 3.1, 3.2, 3.3 built and ticked (open: 4.x at archive time, 5.x live pass, decision 139). Not archived: the approval clause of REQ-MCP-206 waits on Q-dossiq-L6-2.
    • lib/Service/Mcp/CaseTools.php: transitionCase (StatusTransitionService::execute as the caller; a failed guard returns the failing guards), reassignCase (coordinators only), completeTask (the engine task verb; a task with required form fields is refused with the field named).
    • lib/Service/Mcp/TermTools.php (new): extendDeadline, pauseDeadline, resumeDeadline. The term is read and the caller must be allowed to change its CASE; the term controller only checks the session.
    • lib/Service/Mcp/AppointmentTools.php (new): scheduleAppointment, cancelAppointment, with AppointmentController's case checks.
    • lib/Service/Mcp/BeschikkingTools.php (new): draftBeschikking only (BeschikkingService::compose); no approve, sign or send (design D3).
    • lib/Service/CaseAssignmentService.php: new reassign(), the single-case form of the caseload release (there was none). Writes assignee only, refuses a no-op, notifies the receiver with the existing cases_reassigned subject.
    • lib/Service/Mcp/ToolEnvelopes.php (new trait): the shared error and refusal envelopes.
    • lib/Mcp/DossiqScannableServices.php: lists the three new tool classes.
  • Spec amended to the services as they exist on development (REQ-MCP-204): reassignCase -> CaseAssignmentService::reassign(), completeTask -> CaseTaskActions::complete(), draftBeschikking -> BeschikkingService::compose().
  • No board: these are agent tools with no screen (the change's screens.md already says so).

New classes and their tests (coverage guard)

  • TermTools: tests/Unit/Service/Mcp/TermToolsTest.php (8 cases: no session, unknown term, case not changeable, extend with date normalised, unreadable date, pause, service refusal, resume with and without a date).
  • AppointmentTools: tests/Unit/Service/Mcp/AppointmentToolsTest.php (7 cases).
  • BeschikkingTools: tests/Unit/Service/Mcp/BeschikkingToolsTest.php (5 cases, including no approve/sign/send method).
  • ToolEnvelopes (trait): exercised through all four tool tests.
  • CaseAssignmentService::reassign(): tests/Unit/Service/CaseAssignmentServiceTest.php (5 cases; the patch is checked against the real case schema fragment).
  • CaseTools writes: 11 new cases in CaseToolsTest. DossiqScannableServicesTest pins every tool's reach and holds the tool classes off ObjectService.
  • Red first: dq-l6-logs/red-reach-dossiq.log, red-reassign.log, red-termtools.log, red-appt-besch.log.

Dependencies built (decision 156)

Questions added

  • Q-dossiq-L6-2: may an app declare an approval floor on a tool, or does approval stay hermiq policy (recommended)?
  • Q-dossiq-L6-3: how hermiq's conversational intake recognises an intake tool (blocks ai-features 5.1/5.2).

Checks

  • PHPUnit tests/Unit/Settings, tests/Unit/Mcp, tests/Unit/Service/Mcp, CaseAssignment service and controller tests after merging origin/development: OK (361 tests).
  • phpcs and phpmd on every changed lib file: clean. phpstan on the changed files: 3 dead catches in TermTools, fixed.
  • origin/development merged (conflicts: 60-termijnbewaking.json version, took 1.5.0; schema digests regenerated, SchemaVersionFloorTest OK).
  • Full composer check:strict and npm run lint NOT run locally (one heavy command per lane, the slot held by the openregister check). PHP only, no src/ change. CI is the full check.

Still owed (live pass, decision 139)

hermiq-ai-tooling 5.1-5.4: tools/list shows 15 curated tools with the D2 reach; a fresh agent is denied dossiq.reassignCase and may call dossiq.getDeadlineDashboard; a granted reassign pends in hermiq approvals and executes through CaseAssignmentService::reassign(); the three chat scenarios of design D4.

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
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/dossiq @ f4e4a74

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 ❌ 6961/6962 · 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 10:58 UTC

Download the full PDF report from the workflow artifacts.

# 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)
…spelled-out alias (gate 57 could not see AppointmentTools)
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/dossiq @ df999ac

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 ❌ 7012/7013 · 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:26 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/dossiq @ 5694cfb

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 ❌ 7012/7013 · 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:53 UTC

Download the full PDF report from the workflow artifacts.

@rubenvdlinde
rubenvdlinde merged commit 8fec037 into development Oct 12, 2026
46 of 50 checks passed
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