diff --git a/architecture/adrs/ADR-0005-prospective-notification-delivery.md b/architecture/adrs/ADR-0005-prospective-notification-delivery.md new file mode 100644 index 0000000..fcb98a3 --- /dev/null +++ b/architecture/adrs/ADR-0005-prospective-notification-delivery.md @@ -0,0 +1,58 @@ +# ADR-0005: Prospective Notification Delivery + +Status: Accepted + +Date: 2026-08-16 + +Decision authority: Creator continuation after the explicit `ARCH-000005` acceptance request + +## Context + +Domovoy has a durable Commit/Executor safety path, but no accepted operation that crosses the Assistant canonical-state boundary. `ARCH-000005` compared alternatives and proposed a typed notification about one Creator-owned `ProspectiveItem`. The Creator accepted that recommendation and selected local Windows notification display as the first channel. + +## Decision + +1. The first external operation is `deliver-prospective-notification-v1` under capability `prospective-notification-delivery`. +2. The subject is one Creator-owned `ProspectiveItem` at an expected revision in `DELIVERED`; delivery does not change Continuity state and does not prove reading, satisfaction, or commitment fulfilment. +3. The Creator client supplies only the item, expected revision, live Work target, and explicit confirmation. The server derives authority, operation, binding, destination, template, body, and action identities. +4. Capability owns a versioned, owner-local `CapabilityBinding`. Commit records its ID and revision; secrets remain external references and bytes are available only to the relevant adapters. +5. Commit/Executor is the only Assistant component permitted to issue the mutating delivery request. It uses the fixed HTTPS destination and receipt paths from the active binding, disables redirects, and accepts only bounded typed responses. +6. Delivery uses `PUT /`. Same intent and digest returns the original receipt; a different digest is an integrity conflict. Read-only reconciliation uses `GET /`. +7. Ambiguous send outcomes become `UNKNOWN_OUTCOME`; they are never blindly retried. Reconciliation compares the durable request digest with the external receipt. +8. The initial destination is a dedicated receipt receiver deployed on `docker-prod`, exposed through the existing `https://assistent.cin.su` origin. It has no access to Assistant canonical databases and persists immutable external receipts in its own durable volume. +9. The destination uses separate credentials for Commit write/reconciliation and Windows read access. Credentials are generated and stored outside Git, database rows, images, logs, browser storage, and cognitive context. +10. A current-user Windows agent reads accepted receipts, shows local operating-system notifications, and keeps only local projection state needed to avoid redisplay. Receiver acceptance is the Commit outcome; operating-system display and human reading are explicitly outside that outcome. +11. Binding retirement blocks new sends while preserving bounded reconciliation for historical actions. Secret rotation creates a new secret version and binding revision without rewriting history. +12. `docker-test` is prohibited for implementation, verification, and deployment of this capability. + +## Rationale + +The operation adds useful external behavior without introducing arbitrary webhooks, provider payloads, SSRF-controlled destinations, or provider-specific semantics. A compatible receiver makes duplicate prevention and read-only reconciliation testable. Separating the receipt outcome from Windows display keeps Commit evidence honest while permitting eventual local delivery when the workstation is available. + +## Consequences + +- Capability binding lifecycle and persistence must be implemented before authorization can succeed. +- Commit requires a typed notification envelope and durable digest evidence in addition to the existing Continuity transition envelope. +- The receiver and Windows reader are adapters, not owners of Continuity or Commit canonical state. +- A receiver outage or ambiguous response cannot trigger an automatic duplicate send. +- The receiver requires durable backup/retention and operational health checks; local Windows projection loss may cause redisplay but cannot cause a second external receipt. +- No new cross-module dependency or canonical owner is introduced; existing registry permissions are sufficient. + +## Validity conditions + +- Owner, Work justification, Authority grant, expected Prospective revision, and exact binding revision are validated before Commit execution. +- Receiver receipt identity and digest are stable and queryable by `ActionIntentID`. +- Only the isolated Executor can read the write credential. +- Windows read access cannot create or alter receipts. +- Tests cover hostile input, duplicate intents, digest conflicts, lost acknowledgement, restart recovery, retirement, and rotation. + +## Revisit triggers + +- A provider cannot implement authoritative idempotency and read-only receipt lookup. +- Notification content requires Artifact payload ownership rather than the bounded V1 template. +- A requirement appears to prove operating-system display or human reading. +- Multi-recipient routing, arbitrary templates, or another provider/channel is requested. + +## Migration and rollback + +Implementation is additive. Rollback retires the binding, revokes both external credentials, stops the Windows agent and receiver, and preserves Commit attempts plus receiver receipts for audit and reconciliation. Existing internal Continuity actions remain unchanged. diff --git a/dev/ACTIVE_TASK.json b/dev/ACTIVE_TASK.json index 2139f3e..62dafc2 100644 --- a/dev/ACTIVE_TASK.json +++ b/dev/ACTIVE_TASK.json @@ -1,5 +1,5 @@ { - "task_file": "dev/tasks/ARCH-000005-first-external-operation-proposal.json", - "task_id": "ARCH-000005", + "task_file": "dev/tasks/ARCH-000006-accept-prospective-notification-delivery.json", + "task_id": "ARCH-000006", "task_revision": 1 } diff --git a/dev/tasks/ARCH-000006-accept-prospective-notification-delivery.json b/dev/tasks/ARCH-000006-accept-prospective-notification-delivery.json new file mode 100644 index 0000000..36e62f8 --- /dev/null +++ b/dev/tasks/ARCH-000006-accept-prospective-notification-delivery.json @@ -0,0 +1,76 @@ +{ + "task_id": "ARCH-000006", + "task_revision": 1, + "architecture_revision": "ADR-0004", + "base_repo_revision": "b4f86b8c46870fe6a1c38f9cfdf35f0a818f9065", + "risk_tier": "E", + "intent": "Accept the typed prospective notification operation, compatible receipt protocol, docker-prod receiver destination, and local Windows display channel proposed by ARCH-000005.", + "requirement_ids": ["INV-AUTH-001", "INV-OWN-001", "INV-TOPO-001", "CONSTITUTION-1.3.5", "CONSTITUTION-1.3.14", "CONSTITUTION-1.3.31"], + "allowed_change_scope": { + "modules": [], + "paths": [ + "architecture/adrs/ADR-0005-prospective-notification-delivery.md", + "docs/FIRST_EXTERNAL_OPERATION_PROPOSAL.md", + "dev/ACTIVE_TASK.json", + "dev/tasks/ARCH-000006-accept-prospective-notification-delivery.json" + ] + }, + "forbidden_change_scope": { + "paths": [ + "architecture/ARCHITECTURE_CONSTITUTION.md", + "architecture/CORE_SEMANTIC_MODEL_V1.md", + "architecture/architecture-registry.yaml", + "architecture/architecture-registry.json", + "ci/**", + ".gitea/**", + "security/**", + "database/**", + "modules/**", + "contracts/**", + "adapters/**", + "cmd/**", + "deploy/**", + "tests/**" + ] + }, + "allowed_architecture_delta": { + "new_cross_module_dependencies": 0, + "new_canonical_owners": 0, + "new_privileges": 2, + "new_third_party_dependencies": 0 + }, + "contracts": { + "consume": ["contracts.authority@v1", "contracts.capability@v1", "contracts.work@v1", "contracts.continuity@v1", "contracts.commit@v1"], + "may_change": ["typed Commit notification envelope", "CapabilityBinding lifecycle", "prospective notification executor port"] + }, + "semantic_owner": "Capability owns binding; Commit owns action evidence; Continuity owns ProspectiveItem; the receiver is an external adapter system", + "canonical_state": ["no canonical state added by this acceptance task"], + "state_transitions": ["no runtime transition in this acceptance task", "future delivery never changes ProspectiveItem state"], + "side_effects_and_privileges": [ + "accept one future Commit write/reconciliation credential scoped to the fixed receiver protocol", + "accept one future read-only Windows receiver credential", + "no credential generation, endpoint call, deployment, or runtime mutation in this task" + ], + "persistence_and_migrations": ["none in this acceptance task"], + "failure_retry_restart": [ + "ambiguous send outcome is UNKNOWN_OUTCOME and is never blindly retried", + "reconciliation is read-only and compares immutable digest evidence", + "Windows projection failure cannot alter receiver or canonical Commit outcomes" + ], + "assumptions": [ + "The Creator's continuation after the explicit acceptance request accepts the ARCH-000005 recommendation and local Windows channel", + "The compatible receiver is an external adapter boundary even when deployed on docker-prod beside Assistant containers", + "The existing architecture registry ownership and dependency graph is sufficient", + "docker-test remains prohibited" + ], + "acceptance_scenarios": [ + "ADR accepts only the typed notification operation and no arbitrary webhook surface", + "CapabilityBinding remains Capability-owned and secrets remain outside canonical state", + "Commit success means receiver receipt acceptance, not Windows display or human reading", + "receiver write and Windows read credentials are separate and least-privileged", + "timeout remains UNKNOWN_OUTCOME and reconciliation remains read-only", + "no registry change, credential creation, implementation, or deployment occurs in this task" + ], + "required_tests": ["architecture preflight", "exact diff scope", "constitutional and ADR semantic review", "go test", "go vet", "CI", "independent Tier E review before promotion"], + "terminal_gap_states": ["BLOCKED_BY_ARCHITECTURE_GAP", "BLOCKED_BY_SPEC_GAP", "BLOCKED_BY_CONFLICT"] +} diff --git a/docs/FIRST_EXTERNAL_OPERATION_PROPOSAL.md b/docs/FIRST_EXTERNAL_OPERATION_PROPOSAL.md index a99d35a..89af1ba 100644 --- a/docs/FIRST_EXTERNAL_OPERATION_PROPOSAL.md +++ b/docs/FIRST_EXTERNAL_OPERATION_PROPOSAL.md @@ -1,6 +1,6 @@ # First external operation proposal -Status: **PROPOSED — NOT ACCEPTED** +Status: **ACCEPTED by ADR-0005** Task: `ARCH-000005`, revision 1 @@ -12,7 +12,7 @@ Choose the smallest useful real-world operation that exercises Domovoy's existin `Creator session → owner validation → live Work justification → Capability binding revision → Authority validation → durable Commit → isolated Executor → external receipt → durable attempt/outcome → read-only reconciliation` -This proposal changes no runtime, contract, schema, architecture authority, credential, endpoint, or deployment state. Its Tier E task packet selects itself in `dev/ACTIVE_TASK.json` only so fail-closed promotion CI validates the proposal's exact diff. +The proposal task changed no runtime, contract, schema, credential, endpoint, or deployment state. Its recommendation and the local Windows display channel were subsequently accepted by `ADR-0005` under task `ARCH-000006`. ## Current gap @@ -141,11 +141,6 @@ The endpoint origin and paths come only from the validated binding. Redirects ar 6. Add the explicit Creator confirmation flow and action-history rendering. 7. Configure one concrete compatible destination, generate its credential outside Git, deploy on `docker-prod`, and run exact-artifact production smoke. -## Decision still required +## Resolution -Implementation is `BLOCKED_BY_SPEC_GAP` until both are explicitly accepted: - -1. the typed operation and safety protocol in this proposal; -2. one concrete destination base URL that implements the receipt protocol, including where the resulting notification is ultimately shown to the Creator. - -No credential should be generated before that destination exists. +`ADR-0005` accepts this typed operation and protocol. The first compatible receiver will run on `docker-prod` behind the existing `https://assistent.cin.su` origin, and a separately authorized local Windows agent will show accepted receipts to the Creator. Receiver acceptance is the external Commit outcome; operating-system display and human reading are not.