ADR-0015: FSC contract acceptance by policy¶
- Status: accepted
- Date: 2026-08-24 (updated 2026-11-02: ordered refusal codes, delegated grants)
- Satisfies: S04, P-07
- Deliberation: autosign.rego (design notes in comments), REQ-61, F-55, F-56, demo #491, PR #464
- Implemented in: policies/fsc/autosign.rego (ordered checks), services/dvtp-onboarding-register, pip-pull/dvtp-onboarding.yaml, fsc-infra/docker-compose.yml (Manager autosign call)
Context and problem statement¶
An FSC Manager can sign all incoming contracts automatically, or it can require a manual review. Neither option scales to an admission model. DvTP participation is a governed status, and a provider must accept contracts only from admitted parties. Admission comes from a register and not from decision policy (REQ-61).
Decision¶
The Manager of each provider sends every submitted contract through the
PDP. The AuthZEN autosign call of the Manager evaluates a dedicated
contract-acceptance policy (package doelbinding.auto_sign_contract).
The policy reads the admission register (toelatingsregister). OpenFTV pulls this register
every 5 seconds (attributes name, active, allowed_source_peer_ids,
acts_for).
The policy accepts grant type 2 (service connection) and grant type 3 (delegated service connection, ADR-0034). It runs eight checks in a fixed order, and the first check that fails names the refusal:
| # | Code | Refuses when |
|---|---|---|
| 1 | NOT_AN_AUTOSIGN_REQUEST |
The input is not a well-formed autosign request |
| 2 | GRANT_TYPE_NOT_ALLOWED |
The grants are not all type 2 or all type 3 |
| 3 | NO_COUNTERPARTY |
The contract has no party other than the provider itself |
| 4 | ADMISSION_REGISTER_UNAVAILABLE |
The PIP pull supplied no register |
| 5 | PARTY_NOT_IN_REGISTRY |
A party is not in the register |
| 6 | PARTY_NOT_ACTIVE |
A party is suspended |
| 7 | SOURCE_NOT_ALLOWED |
The party is not admitted for this source peer |
| 8 | DELEGATION_NOT_REGISTERED |
A delegated grant has no registered integration |
A missing register (check 4) differs from an empty register (check 5). An empty register is available data that admits nobody.
After a refusal, the contract stays proposed, so it can be submitted again (REQ-63). The contract does not become rejected.
Consequences¶
- Admission is data. If an operator activates or deactivates a participant in the register, the contract outcomes change without a policy edit. The register deactivates participants and does not delete them.
- The contract question ("may these parties connect at all") stays separate from the request question ("may this field be read now") on purpose (REQ-62). The request policy reads the same register only for integrator mandates.
- The autosign input of the Manager carries only peer IDs and grant types. So the policy decides about the parties and not about the services. Admission per service is a known limitation (F-56). Risks and technical debt tracks it.
- The Manager fixes the package name. If someone renames the package, the policy resolves to nothing and every contract stays pending.
- A suspended consumer keeps its existing contract and can still send queries (REQ-110, Q-53). Changes to admissions are not logged (REQ-123).