Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions CHANGELOG.d/2.14.1-naruon-calendar-projection-contract.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
## Added

- Added a strict, bounded v1 consumer contract for calendar occurrences already
authorized and policy-filtered by Naruon, including recurrence occurrence
identity, provider revision, timezone/all-day semantics, disclosure level,
and observed provenance.

## Changed

- Clarified that LineageWeave owns post-grounded commitments and issue/todo
records, while Naruon owns provider CalDAV synchronization and writeback.
The earlier custom JSON `/events` feed must not be described as CalDAV.

## Security

- The new consumer rejects unsafe base URLs, end-user/provider credential
shapes, unbounded pages and windows, naive timestamps, duplicate occurrences,
unknown fields/vocabularies, and URL-shaped opaque references.
57 changes: 37 additions & 20 deletions docs/adr/0038-calendar-source-contract.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,54 @@
# ADR 0038: Separate CalDAV events from internal commitments
# ADR 0038: Separate external calendar events from internal commitments

- Status: Accepted
- Status: Superseded in part by ADR 0123
- Date: 2026-08-18

## Context

The buyer Calendar destination needs both external calendar events and
actionable records derived from LineageWeave posts. They have different
ownership and evidence boundaries. PR #251 defines CalDAV as an independent
consumer port, while the current application already stores authorized
commitments and issue tickets.
ownership and evidence boundaries. PR #251 defined the external calendar as an
independent consumer port, while the current application already stores
authorized commitments and issue tickets.

## Decision
The first implementation read a custom JSON `GET {CALDAV_BASE_URL}/events`
feed. Despite the module and setting names, that feed was not a CalDAV client or
CalDAV server contract. It did not implement RFC 4791 WebDAV discovery/REPORT,
RFC 5545 iCalendar recurrence and timezone semantics, RFC 6578 synchronization,
or provider revision and authorization behavior.

`GET /api/calendar` returns two independent collections:
## Original decision retained

- `events`: events read from `CALDAV_BASE_URL/events` through
`lineageweave.caldav_client`; malformed external rows are ignored.
The Buyer Calendar returns two independent collections:

- `events`: externally observed calendar occurrences; and
- `commitments`: the existing authorized internal commitment projection,
filtered by the requesting account's `post_read` RBAC and post ABAC rules.

When CalDAV is unset or temporarily unavailable, `events` is empty and the
response includes a next action in `calendar_sources`; the internal
commitments remain available. The backend never invents an external event.
When the external calendar channel is unset or temporarily unavailable,
`events` is empty and the internal commitments remain available. The backend
never invents an external event.

LineageWeave does not add a second calendar database, CalDAV server, provider
credential store, or writeback engine.

## Superseding decision

ADR 0123 replaces the custom `/events` transport and CalDAV naming with a
versioned, read-only Naruon calendar projection contract. Naruon is the authority
for customer-owned CalDAV provider access, source registry, synchronization,
provider revisions, writeback, retries, and reconciliation. LineageWeave
consumes only bounded, already-authorized `observed` occurrence projections.

This checkpoint does not add a second calendar database. A persistent event
store and sync history may be added when offline access, change tracking, or
CalDAV write-back becomes a product requirement.
The original separation between `events` and `commitments` remains mandatory.
An external event is not converted to an internal issue/commitment without a
separate source-grounded LineageWeave decision and evidence trail.

## Consequences

- The Calendar screen is useful with the existing synthetic commitment data,
even without an external calendar server.
- External events cannot be mistaken for post-grounded commitments.
- CalDAV transport failures do not turn the entire buyer surface into a
fail-closed blank screen.
- The Calendar remains useful with authorized commitment data when Naruon is
unavailable.
- External observations cannot be mistaken for post-grounded commitments.
- Product documentation no longer represents a custom JSON feed as CalDAV.
- Runtime activation waits for Naruon's matching read endpoint and service
audience; absence continues to fail closed rather than fabricate events.
151 changes: 151 additions & 0 deletions docs/adr/0123-naruon-calendar-projection-boundary.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# ADR 0123: Consume calendar observations through Naruon, not provider CalDAV

- Status: Proposed
- Date: 2026-08-21
- Issue: #336
- Stack parent: #261
- Related authority: `ContextualWisdomLab/naruon#978`, `ContextualWisdomLab/naruon#998`

## Context

LineageWeave derives customer commitments from authorized post evidence and
stores them as issue tickets with due dates. The Buyer Calendar can therefore
show two different kinds of records:

1. LineageWeave-authoritative commitments and To Do records; and
2. external calendar events observed in a customer-owned provider.

ADR 0038 correctly separated these collections but named a custom JSON
`GET {CALDAV_BASE_URL}/events` feed as CalDAV. That endpoint does not implement
RFC 4791 discovery, WebDAV REPORT, iCalendar recurrence or VTIMEZONE, RFC 6578
synchronization, ETag reconciliation, scheduling, or provider authorization.
The name therefore overstates the shipped product.

Naruon is the CWL authority for customer-owned mail, calendar, contact, and file
provider interaction. Its scheduling contract owns typed Event/Commitment
semantics, DAV capability discovery, synchronization, provider revisions,
writeback, retries, and reconciliation. Reimplementing those responsibilities
inside LineageWeave would duplicate credentials and provider state and would
turn LineageWeave into a second calendar product.

## Decision

LineageWeave will consume a **read-only, versioned Naruon calendar projection**.
It will not connect to a CalDAV provider directly.

The contract is implemented by:

- `lineageweave.naruon_calendar_projection`;
- `docs/contracts/naruon-calendar-projection-v1.schema.json`; and
- exact parser/transport tests in `tests/test_naruon_calendar_projection.py`.

The projection endpoint is conceptually:

```text
GET {Naruon base}/api/calendar/events
?window_start=<RFC3339>
&window_end=<RFC3339>
&limit=<1..200>
[&cursor=<opaque>]
```

The request uses an audience-scoped **service credential** configured for the
LineageWeave deployment. It does not forward a browser or end-user bearer token,
and it never receives provider credentials.

Each occurrence carries only:

```text
event_reference
occurrence_reference
source_reference
provider_revision
display_text
starts_at
ends_at
all_day
time_zone
status_code
disclosure_code
truth_status_code = observed
observed_at
```

Naruon applies tenant, source, participant, and disclosure policy before the
response crosses the service boundary. `busy_only` rows contain only safe
Naruon-supplied display text. Attendees, descriptions, provider URLs, private
conflict reasons, access tokens, and raw DAV payloads are outside this contract.

LineageWeave keeps the two truth domains separate:

```text
LineageWeave commitment
- authoritative post-derived work record
- issue/todo identity
- source-post evidence and ontology/provenance

Naruon event projection
- observed provider occurrence
- opaque Naruon source/event/occurrence identity
- provider revision and observation time
```

An observed external event is never promoted into an internal commitment merely
because it appears in the same Calendar screen.

## Validation and failure posture

The LineageWeave consumer rejects:

- non-HTTP(S), userinfo-bearing, query-bearing, or fragment-bearing base URLs;
- missing or control-bearing service credentials;
- windows longer than 366 days;
- pages larger than 200 events;
- unknown fields, schema versions, status, disclosure, or truth vocabularies;
- naive timestamps, invalid intervals, and duplicate occurrence references;
- URL-shaped opaque references and cursors.

The adapter follows no redirects through the current shared HTTP client. Errors
identify the configured host but never include the service credential.

Until Naruon ships the matching read endpoint and service-audience contract,
LineageWeave runtime wiring remains fail-closed. Existing internal commitments
remain available even when the external event channel is unavailable.

## Consequences

### Positive

- Product language no longer implies a CalDAV implementation that does not
exist.
- Provider credentials, sync cursors, ETags, recurrence reconciliation, and
scheduling remain in one authority.
- LineageWeave gains a strict, bounded ontology/provenance-compatible event
observation contract without creating another event store.
- Calendar commitments and external observations remain auditable and cannot be
silently conflated.

### Costs and limitations

- The Buyer Calendar will not show external events until Naruon implements and
releases the corresponding read projection.
- The two repositories require consumer/provider contract tests before runtime
activation.
- This PR establishes the consumer and contract only; it does not claim provider
interoperability, CalDAV conformance, or a completed Naruon connector.

## Merge and activation gate

This ADR remains Proposed and the PR remains Draft until:

1. #258 → #260 → #261 are integrated or this stack is restacked on their
protected descendants;
2. Naruon publishes the matching endpoint, media type, service audience, and
conformance fixtures;
3. LineageWeave wires configuration and the Buyer API without forwarding an
end-user token;
4. exact-head tests, security checks, and independent review pass.

## References

See `docs/doctoring/NARUON_CALENDAR_PROJECTION_REFERENCES.md`.
122 changes: 122 additions & 0 deletions docs/contracts/naruon-calendar-projection-v1.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://contextualwisdomlab.org/schemas/naruon-calendar-projection-v1.schema.json",
"title": "Naruon Calendar Projection v1",
"description": "A bounded, policy-filtered event page observed by Naruon and consumed read-only by LineageWeave. This is not a CalDAV provider response.",
"type": "object",
"additionalProperties": false,
"required": ["schema_version", "projection_revision", "events"],
"properties": {
"schema_version": {
"const": "1.0"
},
"projection_revision": {
"$ref": "#/$defs/opaque_reference"
},
"events": {
"type": "array",
"maxItems": 200,
"items": {
"$ref": "#/$defs/calendar_occurrence"
}
},
"next_cursor": {
"oneOf": [
{
"$ref": "#/$defs/cursor"
},
{
"type": "null"
}
]
}
},
"$defs": {
"opaque_reference": {
"type": "string",
"minLength": 1,
"maxLength": 256,
"pattern": "^(?!.*://)\\S+$"
},
"cursor": {
"type": "string",
"minLength": 1,
"maxLength": 1024,
"pattern": "^(?!.*://)\\S+$"
},
"rfc3339": {
"type": "string",
"format": "date-time",
"maxLength": 64
},
"calendar_occurrence": {
"type": "object",
"additionalProperties": false,
"required": [
"event_reference",
"occurrence_reference",
"source_reference",
"provider_revision",
"display_text",
"starts_at",
"ends_at",
"all_day",
"time_zone",
"status_code",
"disclosure_code",
"truth_status_code",
"observed_at"
],
"properties": {
"event_reference": {
"$ref": "#/$defs/opaque_reference"
},
"occurrence_reference": {
"$ref": "#/$defs/opaque_reference"
},
"source_reference": {
"$ref": "#/$defs/opaque_reference"
},
"provider_revision": {
"type": "string",
"minLength": 1,
"maxLength": 256,
"pattern": "^(?!.*://)[^\\u0000-\\u001F\\u007F]+$"
},
"display_text": {
"type": "string",
"minLength": 1,
"maxLength": 512,
"pattern": "^[^\\u0000-\\u001F\\u007F]+$"
},
"starts_at": {
"$ref": "#/$defs/rfc3339"
},
"ends_at": {
"$ref": "#/$defs/rfc3339"
},
"all_day": {
"type": "boolean"
},
"time_zone": {
"type": "string",
"minLength": 1,
"maxLength": 128,
"pattern": "^\\S+$"
},
"status_code": {
"enum": ["confirmed", "tentative", "desired", "cancelled"]
},
"disclosure_code": {
"enum": ["busy_only", "summary_visible"]
},
"truth_status_code": {
"const": "observed"
},
"observed_at": {
"$ref": "#/$defs/rfc3339"
}
}
}
}
}
20 changes: 20 additions & 0 deletions docs/doctoring/NARUON_CALENDAR_PROJECTION_REFERENCES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Naruon calendar projection references

## Product traceability

| Source | Product decision | Evidence |
|---|---|---|
| RFC 4791 | Do not call the current JSON `/events` feed CalDAV; provider DAV behavior belongs to Naruon. | ADR 0123; issue #336 |
| RFC 6578 | Sync tokens and collection reconciliation are provider-authority concerns, not LineageWeave read-model fields. | ADR 0123; Naruon #978/#998 |
| RFC 5545 | Recurrence, occurrence identity, timezone, and all-day semantics must survive the Naruon projection. | Projection v1 schema and parser tests |
| PROV-O | External rows remain `observed`; LineageWeave commitments retain separate authoritative post provenance. | `truth_status_code`; ADR 0123 |

## APA 7th references

Daboo, C., Desruisseaux, B., & Dusseault, L. M. (2007). *Calendaring extensions to WebDAV (CalDAV)* (RFC 4791). RFC Editor. https://doi.org/10.17487/RFC4791

Daboo, C., & Quillaud, A. (2012). *Collection synchronization for Web Distributed Authoring and Versioning (WebDAV)* (RFC 6578). RFC Editor. https://doi.org/10.17487/RFC6578

Desruisseaux, B. (2009). *Internet calendaring and scheduling core object specification (iCalendar)* (RFC 5545). RFC Editor. https://doi.org/10.17487/RFC5545

World Wide Web Consortium. (2013). *PROV-O: The PROV ontology*. https://www.w3.org/TR/prov-o/
Loading
Loading