|
|
|
@@ -0,0 +1,151 @@
|
|
|
|
|
# First external operation proposal
|
|
|
|
|
|
|
|
|
|
Status: **PROPOSED — NOT ACCEPTED**
|
|
|
|
|
|
|
|
|
|
Task: `ARCH-000005`, revision 1
|
|
|
|
|
|
|
|
|
|
Base: `91d03b730d1bdbbe8e67b831fb21046768c4df5e`
|
|
|
|
|
|
|
|
|
|
## Objective
|
|
|
|
|
|
|
|
|
|
Choose the smallest useful real-world operation that exercises Domovoy's existing safety path without creating a generic mutation escape hatch:
|
|
|
|
|
|
|
|
|
|
`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.
|
|
|
|
|
|
|
|
|
|
## Current gap
|
|
|
|
|
|
|
|
|
|
Foundation and the Creator console prove internal Continuity execution, durable attempts, `UNKNOWN_OUTCOME`, and reconciliation. No production Executor currently mutates a system outside Assistant-owned canonical state. Before adding one, V1 needs an explicit decision for:
|
|
|
|
|
|
|
|
|
|
- the semantic operation and subject;
|
|
|
|
|
- who may request it and with which live justification;
|
|
|
|
|
- how a destination is bound, revised, disabled, and recovered;
|
|
|
|
|
- which exact external protocol makes duplicate prevention and reconciliation provable;
|
|
|
|
|
- where credentials live and how they rotate;
|
|
|
|
|
- which ambiguous failures become `UNKNOWN_OUTCOME`.
|
|
|
|
|
|
|
|
|
|
## Alternatives considered
|
|
|
|
|
|
|
|
|
|
### Typed Prospective notification — recommended
|
|
|
|
|
|
|
|
|
|
Deliver one server-constructed notification about one Creator-owned `ProspectiveItem` to one preconfigured Creator destination. This extends existing Continuity product behavior while keeping delivery distinct from satisfaction or commitment fulfilment.
|
|
|
|
|
|
|
|
|
|
The semantic operation is `deliver-prospective-notification-v1`; HTTP is only its first adapter mechanism.
|
|
|
|
|
|
|
|
|
|
### Arbitrary webhook — rejected
|
|
|
|
|
|
|
|
|
|
Accepting a URL, headers, method, or free-form JSON from a browser/model would be a universal mutation capability, an SSRF surface, and a substitute for typed domain contracts. It cannot be the first operation.
|
|
|
|
|
|
|
|
|
|
### Direct email, Telegram, or chat-provider send — deferred
|
|
|
|
|
|
|
|
|
|
These are useful delivery mechanisms but their duplicate and reconciliation semantics differ. Selecting one before a recipient and provider contract exist would embed provider behavior into the domain decision. A provider may be used later only behind the accepted typed operation and Executor port.
|
|
|
|
|
|
|
|
|
|
### File or NAS export — deferred
|
|
|
|
|
|
|
|
|
|
An export is mechanically idempotent, but meaningful payload export requires Artifact metadata/payload lifecycle that V1 has not implemented. Creating unowned files first would bypass Artifact ownership questions.
|
|
|
|
|
|
|
|
|
|
### Git mutation — rejected for V1
|
|
|
|
|
|
|
|
|
|
Repository mutation belongs to the separately deferred Development Control Plane and would give the first product Executor disproportionate authority.
|
|
|
|
|
|
|
|
|
|
## Proposed semantic operation
|
|
|
|
|
|
|
|
|
|
Capability: `prospective-notification-delivery`
|
|
|
|
|
|
|
|
|
|
Operation: `deliver-prospective-notification-v1`
|
|
|
|
|
|
|
|
|
|
Subject and immutable commit evidence:
|
|
|
|
|
|
|
|
|
|
- `ProspectiveItemID` and expected Prospective revision;
|
|
|
|
|
- owner Principal, Scope and Goal observed from Continuity;
|
|
|
|
|
- live Work `TaskTarget` justification and revision;
|
|
|
|
|
- server-selected notification template code `prospective-delivered-v1`;
|
|
|
|
|
- current `CapabilityBindingID` and binding revision;
|
|
|
|
|
- `ActionIntentID`, AuthorizedAction ID and authorization time.
|
|
|
|
|
|
|
|
|
|
The browser supplies only the selected Prospective item, expected revision, Work target and an explicit confirmation. It never supplies Actor, Principal, grant, capability, operation, destination URL, authorization header, template, message body, Action IDs, or provider fields.
|
|
|
|
|
|
|
|
|
|
The owner must validate that the Prospective item belongs to the authenticated Principal and is currently `DELIVERED`. Notification success does **not** change the Prospective item to `SATISFIED`, fulfil a Commitment, or prove that a human read the message.
|
|
|
|
|
|
|
|
|
|
## Destination binding and secret lifecycle
|
|
|
|
|
|
|
|
|
|
The existing Capability owner already owns `CapabilityBinding`. An implementation should materialize a versioned binding rather than use ambient configuration as correctness state. Minimum binding meaning:
|
|
|
|
|
|
|
|
|
|
- stable Binding ID and revision;
|
|
|
|
|
- owner Principal and capability ID;
|
|
|
|
|
- fixed HTTPS origin and fixed delivery/receipt path template;
|
|
|
|
|
- active/retired lifecycle;
|
|
|
|
|
- declared idempotency and reconciliation protocol version;
|
|
|
|
|
- external secret reference, never literal secret material;
|
|
|
|
|
- verification time and health state.
|
|
|
|
|
|
|
|
|
|
Commit records the binding ID and revision used for authorization. A retired, missing, unhealthy, owner-mismatched, or revised binding fails closed before a new external attempt. Historical actions retain their original binding evidence. Rotation creates a new secret version/reference; it does not rewrite old envelopes.
|
|
|
|
|
|
|
|
|
|
Secret bytes are mounted only into the isolated Commit Runtime Executor. They must not enter PostgreSQL, Creator responses, browser storage, image layers, task packets, Git, logs, or cognitive context.
|
|
|
|
|
|
|
|
|
|
## Required external protocol
|
|
|
|
|
|
|
|
|
|
The first adapter may use HTTPS only if the selected destination implements a narrow receipt protocol:
|
|
|
|
|
|
|
|
|
|
1. `PUT <fixed-delivery-path>/<ActionIntentID>` creates the delivery exactly once.
|
|
|
|
|
2. The body is the server-rendered typed V1 notification; its canonical digest is recorded before execution.
|
|
|
|
|
3. Repeating the same intent and digest returns the original receipt without redelivery.
|
|
|
|
|
4. Reusing an intent with a different digest returns an integrity conflict without mutation.
|
|
|
|
|
5. `GET <fixed-receipt-path>/<ActionIntentID>` is read-only and returns whether the delivery exists plus the stored digest/receipt identity.
|
|
|
|
|
6. Success is accepted only when the receipt identity and digest match the committed request.
|
|
|
|
|
|
|
|
|
|
The endpoint origin and paths come only from the validated binding. Redirects are disabled. DNS resolution, certificate validation, response size, content type and timeouts are bounded. No request field can select another host, scheme, path, header or credential.
|
|
|
|
|
|
|
|
|
|
## Failure and reconciliation semantics
|
|
|
|
|
|
|
|
|
|
- Binding/authority/owner/revision failure: reject before Commit or external attempt as appropriate.
|
|
|
|
|
- Definite protocol rejection before mutation: `FAILED` with typed reason.
|
|
|
|
|
- Timeout, connection loss after send, malformed success, unexpected 5xx, or receipt mismatch: `UNKNOWN_OUTCOME`.
|
|
|
|
|
- `UNKNOWN_OUTCOME` blocks another delivery attempt for the same action.
|
|
|
|
|
- Explicit reconciliation issues only the receipt GET and creates a new attempt identity.
|
|
|
|
|
- Matching receipt/digest reconciles to `SUCCEEDED`; explicit absence remains unknown unless the provider contract proves absence is authoritative after its consistency window.
|
|
|
|
|
- Executor restart loads the immutable envelope and latest attempt; no process-local queue, mutex or timer is correctness state.
|
|
|
|
|
- Binding retirement blocks new authorization but preserves reconciliation access for historical actions until an explicit recovery/retention decision exists.
|
|
|
|
|
|
|
|
|
|
## Security constraints
|
|
|
|
|
|
|
|
|
|
- No arbitrary URL, HTTP method, headers, body, template or provider operation.
|
|
|
|
|
- No redirects and no fallback host.
|
|
|
|
|
- No ambient machine credential or credential shared with another capability.
|
|
|
|
|
- No direct call from UI, Core, Continuity, cognitive worker or model adapter.
|
|
|
|
|
- No logging of body, bearer secret or full provider response.
|
|
|
|
|
- No automatic retry of ambiguous mutation.
|
|
|
|
|
- No implication that delivery equals reading, satisfaction or fulfilment.
|
|
|
|
|
- No `docker-test` deployment or verification.
|
|
|
|
|
|
|
|
|
|
## Acceptance evidence required from an implementation
|
|
|
|
|
|
|
|
|
|
- adversarial browser/model fields cannot alter the operation or destination;
|
|
|
|
|
- foreign owner, wrong Prospective state, stale item/Work/binding revision, revoked grant and unhealthy binding are denied;
|
|
|
|
|
- duplicate delivery with the same intent produces one external receipt;
|
|
|
|
|
- lost acknowledgement records `UNKNOWN_OUTCOME` and read-only reconciliation finds the original receipt;
|
|
|
|
|
- mismatched digest is an integrity failure and never redelivers;
|
|
|
|
|
- restart recovery uses durable Commit state and provider receipt only;
|
|
|
|
|
- secret rotation and binding retirement fail closed without rewriting history;
|
|
|
|
|
- Commit Runtime is the only component with the delivery credential;
|
|
|
|
|
- production smoke uses the selected real destination and does not use `docker-test`.
|
|
|
|
|
|
|
|
|
|
## Implementation slices after acceptance
|
|
|
|
|
|
|
|
|
|
1. Accept the semantic/protocol decision in an ADR-level task; confirm that the existing registry dependencies remain sufficient.
|
|
|
|
|
2. Implement Capability-owned binding lifecycle and owner-local persistence, with only an external secret reference.
|
|
|
|
|
3. Extend the typed Commit envelope for the notification subject, binding revision and request digest.
|
|
|
|
|
4. Implement a deterministic fake receiver and adversarial/idempotency/recovery tests.
|
|
|
|
|
5. Implement the isolated HTTPS Executor/reconciler with strict destination policy and secret-file injection.
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
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.
|