Private product edges / JobCache Core boundary
Status: implemented, migrated and live at both product edges and the JobCache Core API. The App Worker/D1, scoped credentials, scheduled erasure drain and public API/MCP domains are deployed.
The system has two private edges around one JobCache-owned shared core:
JobCache App D1 session-private observer state
│
│ privacy seam
▼
JobCache Core shared ads, roles, evidence, search and intelligence
▲
│ privacy seam
│
CareerVector D1/Yjs workspace-private applicant state
JobCache Core is not a neutral third product. It is the Core zone of JobCache and owns neither edge's local identities.
Data ownership
| Store/zone | Authoritative for |
|---|---|
| CareerVector D1/Yjs | workspace, CV/CL, notes, evaluations, workspace jobs, interactions and local snapshots |
| JobCache App D1 | session, saved views, dashboard state, observer interactions and local snapshots |
| JobCache Core CrateDB | ads, roles, public evidence, embeddings, corpus projections and accepted graph facts |
| JobCache Core operational store | claims, leases, retries, receipts and quarantine |
The same fact cannot be independently authoritative in an edge and Core. A product snapshot is a materialized result from a versioned Core computation, not a second owner of corpus facts.
Sparse role/ad/workspace resolution
CareerVector's job projection remains:
workspace value if present
else ad value if present
else role value if present
else absent
Absence means inheritance, not unknown or disagreement. Workspace overrides remain private. Ads are public evidence; roles are JobCache Core projections over one or more ads. JobCache Core owns stable role identity and aliases when roles merge or split.
Allowed upward movement
Every egress contract declares one privacy class:
| Class | Identifier | Required controls |
|---|---|---|
| pseudonymous individual | versioned person_key or observer_key |
explicit purpose, allowlisted fields, consent/lawful basis, retention, erasure and key rotation |
| anonymous aggregate | none | aggregation at the edge, configured minimum cohort, bounded dimensions and fail-closed thresholding |
Raw workspace_id, session_id, inverse pseudonym maps, CV/CL text, notes, collaborator
identity and product-local UI state do not enter JobCache Core. Raw text may leave an edge
only through a separately declared processor contract required to produce an approved
artifact; that does not make the text corpus data.
A named reducer is code with an output schema and version, not a runtime visibility flag. It declares source data class, purpose, emitted privacy class, forbidden fields and deletion behavior. A hashed identifier is still pseudonymous; it is never relabelled anonymous.
Cross-store protocol
D1 and JobCache Core are not one transaction. Reliable movement uses stable identities and receipts:
- The product edge commits its local action and durable fact/outbox state atomically.
- JobCache Core claims facts under an authenticated worker-owned lease.
- Core durably commits accepted facts; rejected facts receive itemized reasons and remain in quarantine.
- Ack advances only the exact accepted partition and records a durable receipt.
- Core delivers immutable result snapshots with a stable batch ID; the edge commits the snapshot and pointer atomically and records the delivery receipt.
Retries are safe. The same fact ID or delivery batch cannot create a second logical event, and the same result ID cannot name different bytes.
Failure behavior
Committed local state remains usable during a Core outage. A compatible immutable snapshot may be served as fallback with its actual age and provenance. There is no guarantee of an answer on first use or for an unsupported request. Response path, result origin, persistence, freshness and health are represented separately.
Product cases
| Case | Private edge | JobCache Core |
|---|---|---|
| applicant workspace | owns documents, choices and local interactions | supplies role/ad projections and approved recommendations |
| public ad import | records workspace job and local differences | ensures ad evidence and role projection |
| individualized recommendation | reduces applicant state and emits person_key facts |
searches/matches only against person facts |
| market analytics | emits thresholded anonymous cohorts | computes shared metrics without edge identity |
| individualized observer view | owns session state and emits observer_key only when continuity is required |
materializes the saved view; never treats observer activity as demand |
| public workspace sharing | grants access at the CareerVector edge | not involved unless an independent reducer/export runs |
As built
CareerVector owns private D1/Yjs workspace state and JobCache Core owns the CrateDB corpus.
The shared contracts, CareerVector seam, Core participant lifecycle and JobCache App
observer installation now exist in code. jobcache/api/ provides the App D1 adapter and
jobcache/mcp/ calls only that API. Production provisioning and the final removal of
CareerVector's direct-database/public-search compatibility gateways remain outstanding.