Skip to content
Merged
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
50 changes: 50 additions & 0 deletions packages/contracts/src/data-rights-contract.typecheck.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {
DATA_RIGHTS_CONTRIBUTOR_CONTRACT_VERSION,
type DataRightsContributorEraseRequest,
type DataRightsContributorExportResponse,
type DataRightsContributorRequest,
type DataRightsContributorResponse,
} from './data-rights.js';

const WORKSPACE_ID = '22222222-2222-4222-8222-222222222222';
const USER_ID = '33333333-3333-4333-8333-333333333333';
const REQUEST_ID = '11111111-1111-4111-8111-111111111111';
const IDEMPOTENCY_KEY = '44444444-4444-4444-8444-444444444444';

/** Compile-time proof that erase authority cannot omit its replay identity. */
const eraseRequest: DataRightsContributorEraseRequest = {
contractVersion: DATA_RIGHTS_CONTRIBUTOR_CONTRACT_VERSION,
operation: 'erase',
workspaceId: WORKSPACE_ID,
requestedByUserId: USER_ID,
requestId: REQUEST_ID,
idempotencyKey: IDEMPOTENCY_KEY,
};

/** Compile-time proof that every operation belongs to the versioned request union. */
const requestUnion: DataRightsContributorRequest = eraseRequest;

/** Compile-time proof that export evidence is contributor-owned and digest-bearing. */
const exportResponse: DataRightsContributorExportResponse = {
contractVersion: DATA_RIGHTS_CONTRIBUTOR_CONTRACT_VERSION,
operation: 'export',
contributor: 'planning.service',
requestId: REQUEST_ID,
schemaVersion: 'planning.data-rights.v1',
recordCount: 1,
sha256: 'a'.repeat(64),
data: Object.freeze({
goals: Object.freeze([
Object.freeze({
id: '55555555-5555-4555-8555-555555555555',
title: 'Example goal',
}),
]),
}),
};

/** Compile-time proof that concrete evidence remains assignable to the response union. */
const responseUnion: DataRightsContributorResponse = exportResponse;

void requestUnion;
void responseUnion;
113 changes: 113 additions & 0 deletions packages/contracts/src/data-rights.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/** Versioned internal contract used by independently deployable data-rights contributors. */
export const DATA_RIGHTS_CONTRIBUTOR_CONTRACT_VERSION =
'life-os.data-rights-contributor.v1' as const;

/** JSON-safe primitive allowed in a bounded contributor export section. */
export type DataRightsJsonPrimitive = boolean | number | string | null;

/** JSON-safe array allowed in a bounded contributor export section. */
export interface DataRightsJsonArray extends ReadonlyArray<DataRightsJsonValue> {}

/** JSON-safe object allowed in a bounded contributor export section. */
export interface DataRightsJsonObject {
readonly [key: string]: DataRightsJsonValue;
}

/** JSON-safe value exchanged across the contributor contract. */
export type DataRightsJsonValue =
| DataRightsJsonPrimitive
| DataRightsJsonArray
| DataRightsJsonObject;

/** Operations exposed by one service-owned data-rights contributor. */
export type DataRightsContributorOperation =
| 'export'
| 'erase_preflight'
| 'erase'
| 'verify_erased';

interface DataRightsContributorRequestBase {
readonly contractVersion: typeof DATA_RIGHTS_CONTRIBUTOR_CONTRACT_VERSION;
readonly workspaceId: string;
readonly requestedByUserId: string;
readonly requestId: string;
}

/** Requests one deterministic bounded export section from the owning service. */
export interface DataRightsContributorExportRequest
extends DataRightsContributorRequestBase {
readonly operation: 'export';
}

/** Requests fail-closed erasure readiness without mutating service-owned data. */
export interface DataRightsContributorErasePreflightRequest
extends DataRightsContributorRequestBase {
readonly operation: 'erase_preflight';
}

/** Requests one idempotent owning-service erasure using an opaque replay key. */
export interface DataRightsContributorEraseRequest
extends DataRightsContributorRequestBase {
readonly operation: 'erase';
readonly idempotencyKey: string;
}

/** Requests post-erasure verification from the service that owns the data. */
export interface DataRightsContributorVerifyErasedRequest
extends DataRightsContributorRequestBase {
readonly operation: 'verify_erased';
}

/** Request union for the complete v1 contributor lifecycle. */
export type DataRightsContributorRequest =
| DataRightsContributorExportRequest
| DataRightsContributorErasePreflightRequest
| DataRightsContributorEraseRequest
| DataRightsContributorVerifyErasedRequest;

interface DataRightsContributorResponseBase {
readonly contractVersion: typeof DATA_RIGHTS_CONTRIBUTOR_CONTRACT_VERSION;
readonly contributor: string;
readonly requestId: string;
}

/** Deterministic service-owned export section plus exact digest evidence. */
export interface DataRightsContributorExportResponse
extends DataRightsContributorResponseBase {
readonly operation: 'export';
readonly schemaVersion: string;
readonly recordCount: number;
readonly sha256: string;
readonly data: DataRightsJsonValue;
}

/** Readiness result that cannot claim ready while blockers remain. */
export interface DataRightsContributorErasePreflightResponse
extends DataRightsContributorResponseBase {
readonly operation: 'erase_preflight';
readonly ready: boolean;
readonly blockers: readonly string[];
}

/** Owning-service erasure receipt with bounded aggregate count and digest. */
export interface DataRightsContributorEraseResponse
extends DataRightsContributorResponseBase {
readonly operation: 'erase';
readonly erasedRecords: number;
readonly receiptSha256: string;
}

/** Post-erasure verification evidence from the owning service. */
export interface DataRightsContributorVerifyErasedResponse
extends DataRightsContributorResponseBase {
readonly operation: 'verify_erased';
readonly erased: boolean;
readonly evidenceSha256: string;
}

/** Response union for the complete v1 contributor lifecycle. */
export type DataRightsContributorResponse =
| DataRightsContributorExportResponse
| DataRightsContributorErasePreflightResponse
| DataRightsContributorEraseResponse
| DataRightsContributorVerifyErasedResponse;
2 changes: 2 additions & 0 deletions packages/contracts/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export * from './data-rights.js';

export type WorkspaceRole = 'owner' | 'admin' | 'member' | 'viewer';

export interface RequestContext {
Expand Down
Loading