---
title: Pocket Chronicle bounded text import contract v1
classification: memorialize
status: active
owner: Founders / Engineering
created: 2026-10-08
last-reviewed: 2026-10-08
---

# Pocket Chronicle bounded text import contract v1

## Status and authority

**Accepted by the user on 2026-10-08 for [#946](https://github.com/helloorigo/origo/issues/946),
together with the JSON Schema and [ADR-0024 amendment](https://github.com/helloorigo/origo/blob/main/docs/02-architecture/pocket-chronicle-import-adr-0024-amendment.md).**
The accepted design is integrated into [ADR-0024 §10A](https://github.com/helloorigo/origo/blob/main/docs/02-architecture/decisions/0024-pocket-chronicle-0.1-local-storage-and-export-boundary.md).
This approval does not claim an implemented or released importer. Merge the
approved artifacts and verify them in the freshly fetched implementation base
before dispatching a separate implementation agent.

This is a Pocket adapter contract, not a replacement for Chronicle Core's source,
authority, lifecycle, or interchange semantics. It creates no platform runtime.
The JSON candidates below are not conforming `source-record-v1` records: they
cannot assert a preserver, authorship, or historical human approval. Import is an
explicit adoption of supplied text. It does not establish who authored it.

## Public distribution and versioning

The schema, synthetic example, and this contract are distributed as static files
under `https://helloorigo.com/trust/`, linked from the trust page. Their canonical
sources remain in `apps/pocket-chronicle/contracts/` and `docs/02-architecture/`;
`apps/hello-origo/scripts/sync-trust-material.mjs` copies them verbatim and CI
checks freshness. Publication of the specification does not claim that the
importer is released. The example is invented test content, not a validation corpus.

Pocket must bundle its supported validation rules; import must not fetch the
public schema at runtime. JSON Schema alone does not enforce all the semantic,
byte-size, duplicate-member, conflict, and persistence rules below.
Preserve the v1 format and public addresses. Breaking format changes require a
new version and address while v1 remains available. Editorial clarifications
must not change the accepted v1 input semantics.

## Confirmed product scope

Import on iPhone accepts an encrypted Pocket v1 export or the documented JSON
list. The primary use is reproducible synthetic validation; end users use the
same production validation and confirmation path. Import preserves original IDs,
original source text, dates, and available source category. The person previews
and confirms the whole validated batch; individual selection is excluded.

Skip identical existing sources. A differing source with an existing ID blocks
the entire batch. Require explicit IDs and dates; the future fixture tool may
generate these before writing a file, but the importer cannot invent them.
Synthetic/test text is supported as an explicit declaration separate from import
origin. This extension was requested by the user on 2026-10-08 before the v1
contract PR merged or any v1 importer shipped. Optional enabled local labeling
is off by default and runs only after successful commit and explicit selection. Existing opt-in and availability rules apply.

## Inputs and schema

### Generic JSON thought list

The [schema](https://helloorigo.com/trust/pocket-thought-list-v1.schema.json)
uses JSON Schema Draft 2020-12; its `$id` is the public schema address. The
[synthetic example](https://helloorigo.com/trust/pocket-thought-list-v1.example.json)
also exercises the production import validation path under #946.

| Field | Meaning |
|---|---|
| `format` | Exactly `com.helloorigo.pocket-chronicle.thought-list`. |
| `version` | Integer `1`; the list version, independent of encryption/storage versions. |
| `records` | Array of zero to 1,000 source candidates. File order has no chronological authority. |
| Record `id` | Required lowercase UUID; non-nil, unique within the file. Preserved exactly. |
| Record `content` | Exact Unicode source text. Nonempty and not wholly Unicode White_Space. |
| Record `captureSource` | Required supplied original category: `typed_text` or `voice_transcript`. |
| Record `sourceCapturedAt` | Required supplied original articulation date. |
| Record `createdAt` | Required supplied original source-record acceptance/creation date. |
| Record `sourceSchemaVersion` | Integer `1`; the supported Pocket text-source projection. |
| Record `materialKind` | Optional `synthetic` or `unspecified`; declared material metadata, separate from import origin. Omission is unspecified. |

The six original source fields are required to share Pocket v1's explicit source
tuple. The optional `materialKind` is separate metadata, not a seventh original
source field or a new capture category.
Requiring `captureSource` was proposed in the schema and approved with this
contract on 2026-10-08. A file that cannot supply one of the two categories is unsupported in this slice; do not guess a default. Dates may be
asserted fixture values. Neither a category nor a date establishes real-world
capture, authorship, transcript fidelity, or prior human approval.

Dates are real Gregorian UTC instants in years 0001–9999, encoded as
`YYYY-MM-DDTHH:mm:ss.SSSZ`. No offsets, absent values, leap seconds, or rounding.
There is no guessed chronology constraint between the two dates: a historical
clock discrepancy is preserved as supplied, not repaired. Future dates are not
proof of future events and are not silently adjusted. Unknown members, nulls,
unsupported versions/categories, duplicate object member names, invalid UTF-8,
a byte-order mark, trailing non-whitespace, and unpaired Unicode surrogates are
rejected. Pretty printing and trailing JSON whitespace are allowed; generic
JSON need not be RFC 8785 canonical on disk. Text is never trimmed or normalized.
Expected labels, evaluation scores, context, links, and authorship declarations
are not fields in this format. Keep expected validation outcomes in a separate
evaluation artifact that the importer does not consume.

### Encrypted Pocket export

Recognize the documented envelope by its format/version and exact members,
not by extension alone. Validate v1 cryptographic parameters and bounded Base64
lengths before key derivation. The password's exact UTF-8 bytes feed the existing
PBKDF2-HMAC-SHA256/600,000/AES-256-GCM design; do not trim or normalize it. No
new password-length requirement is imposed when opening an existing export.

Authenticate using the existing v1 authenticated parameters. Before preview,
check outer/payload canonical encoding, exact field sets, source version,
record count, records SHA-256, UUIDs, source fields, dates, and all limits.
[The existing independent verifier](https://github.com/helloorigo/origo/blob/main/apps/pocket-chronicle/Tools/verify-export.mjs)
is the interoperability reference; Swift encoding remains frozen. A legitimate
empty export is a no-op. Authentication failure or unsupported input never
falls back to interpreting ciphertext as a JSON list. Do not read v2 audio or
full Chronicle export formats through this path.

Encryption authenticates the supplied file under its password; it does not prove
human authorship, a native capture event, or witnessed historical time. The export
UUID and export creation date describe the package, not a source UUID/date.

## Hard limits and additional semantic validation

| Quantity | Inclusive bound |
|---|---:|
| Selected input file | 10 MiB (10,485,760 bytes) |
| Authenticated decrypted JSON payload | 10 MiB |
| Sources per input | 1,000 |
| Each decoded content value in UTF-8 | 64 KiB (65,536 bytes) |
| JSON container nesting | 4 levels; count the root container as level 1 |

The selected-file limit includes formatting/escape overhead. Enforce actual read
counts even if provider-reported size is absent or wrong. Abort bounded reads at
the limit plus one byte. Bound ciphertext and decoded/decrypted sizes before
allocating/deriving where possible. No compression, archives, remote URL loading,
silent truncation, streaming partial commits, or automatic batch splitting.

Use a standards-compliant schema validator with `uuid`/`date-time` assertions
explicitly enabled, or an equivalent implementation with conformance evidence.
The schema's `maxLength` measures characters, not UTF-8 bytes. Schema validation
cannot establish UUID uniqueness, duplicate JSON member detection, byte limits,
strict calendar validity in every validator, database conflicts, or authentication.
Those checks are mandatory independent of a schema pass.

## Imported origin and declared synthetic material

Every newly imported record has observed origin **imported**, regardless of its
original supplied `captureSource`. Native thoughts already collected on this
phone retain their original origin; an identical skip cannot relabel them imported.
`materialKind` independently declares whether the candidate is synthetic/test
content. Accepted JSON values are `synthetic` and `unspecified`; omission also
means unspecified. This is an import/provenance declaration, not a new Chronicle
source kind, authority class, type label, classifier prediction, or claim that
unmarked material is human-authored. Synthetic text may be generated manually or
with tools; explicit batch adoption does not promote it to observed lived history.

Preserve `synthetic` atomically as encrypted, source-owned declared metadata.
Record that the importing person adopted the input's declaration at confirmation;
never infer the declaration from words, filenames, model output, or test execution.
The fixture generator must emit `materialKind: "synthetic"` for generated test
thoughts. End-user JSON may mix marked/unmarked records. The user selects which
input to adopt, not a file-wide switch that silently marks existing thoughts.
Frozen encrypted Pocket v1 has no material-kind field: new candidates from that
format are unspecified; do not modify its envelope, trust absent provenance, or
relabel decrypted words as synthetic by guessing.

The preview must show total declared synthetic/new/identical/conflicting counts,
with synthetic counts described as overlapping source counts rather than added
into the total. Expose the declaration beside candidate text. Newly imported rows
show a quiet **Imported** origin indicator; declared synthetic rows additionally
show **Synthetic test content**. Detail/provenance inspection and VoiceOver must
state both facts and the distinction from locally observed capture. Existing
native rows and their origin are unchanged. Synthetic thoughts remain readable,
searchable, and eligible for explicitly requested existing local labeling; the
marker cannot become a machine-derived thought label or expected test result.
Do not add automatic deletion, evaluation execution, or a separate test-only store.

An identical source tuple with an incoming `synthetic` declaration is skippable
only if the existing source already has that declaration. If it is unmarked or
unspecified, reject the batch as a material-declaration conflict; do not relabel
an existing native/imported source. A missing/`unspecified` incoming declaration
asserts nothing and cannot clear an existing synthetic marker: an otherwise
identical tuple is skipped with all existing metadata retained. This also makes
legacy encrypted Pocket v1 re-import idempotent against already marked sources.
Input/schema validation cannot adjudicate whether a declaration is truthful.

## Normalization and provenance

Normalize both inputs into the six-field source tuple without changing content,
UUIDs, source categories, or millisecond instants. Sorting for display/storage
uses the existing capture-date-descending, UUID-descending rule, not file order.
The values `createdAt` and `sourceCapturedAt` remain the supplied original dates;
the observed local import commit time is separate and never overwrites them.

Newly imported sources must atomically receive encrypted, source-owned origin
metadata recording at least: import kind (`pocket_export_v1` or `thought_list_v1`),
input/source versions, observed import time, explicit batch adoption, the declared
material kind when synthetic, and that historical dates/category were supplied by the input rather than observed here.
Pocket package identity/date may be retained as package claims, not source facts.
Do not retain the file path, password, raw package, or a second content archive.
Do not infer author, speaker, account, device, original approval, or testimony.

The persistence adapter must distinguish supplied original `captureSource` from
the observed act of import. Calling the ordinary typed/voice capture method and
backdating it without that distinction is non-conforming. Any required storage
extension must keep these meanings separate and bind origin metadata to source
identity under existing authenticated encryption. Reuse accepted Chronicle
provenance vocabulary; do not invent a product-only authority class. If current
Core vocabulary cannot represent explicit imported adoption without stronger
claims, record that gap for approval before persistence implementation.

Inspection/help must disclose import origin and supplied dates. Ordinary capture
continues to record its own observed acceptance time. Original text and dates
must remain inspectable even if local edits later create revisions. The generic
JSON is plaintext in the holder's custody; deleting an imported thought does not
delete that input. The original selected file is never modified or deleted.

Frozen Pocket export v1 carries neither import-origin metadata nor synthetic
declarations. A re-export/re-import into a different store therefore cannot
restore either distinction; new records remain imported with unspecified material
kind, never inferred native or human-authored. Disclose this loss of metadata.
Re-export can preserve the six source fields but is not a provenance-complete
restore or a new witness claim. A future portable format change is separate work,
not a silent extension to v1.

## Preview, conflicts, and atomic commit

1. Select/read/decrypt/validate locally into bounded memory. Do not mutate the
   Chronicle or enqueue processing before confirmation.
2. Compare each candidate to the existing **original** six-field source tuple.
   Do not compare against current revision text, file ordering, context, labels,
   import timestamps, or package digests. Same content/different UUIDs are distinct.
   Apply the additional explicit-synthetic conflict rule above without modifying
   an existing source's origin or material declaration.
3. Show total, new, identical, and conflicting counts that sum to the input count;
   supplied date range; source-only/import-origin and input-file custody limits;
   and an off-by-default labeling option. Provide access to the candidate texts
   for batch review. Any conflict disables Import; invalid input never reaches
   an importable preview. Include per-record synthetic declarations and their
   overlapping count. Empty/all-identical files are successful no-ops, with
   no fabricated new import metadata or labeling work.
4. Explicit Import adopts the whole validated batch. Recheck the tuples under
   the serialized transaction. If the source snapshot changed so preview counts
   or decisions differ, stop without writes and require a refreshed preview and
   confirmation. Do not silently change what was authorized.
5. Commit every new source, its initial original articulation/version, and
   mandatory origin and declared synthetic metadata in one transaction. Skip
   identical sources without altering their revisions/context/relationships or other metadata. A differing
   existing UUID rejects the entire batch; repeated UUIDs within input are invalid.
6. Report success only after confirmed durable commit and authenticated readback.
   The atomic commit is the cancellation boundary: cancellation before it writes
   nothing; after it, sources are kept and must not be silently deleted as undo.
   A crash before commit rolls back. A crash after commit leaves all sources; an
   identical retry skips them. If acknowledgement/readback is uncertain, say so
   and reconcile the original UUIDs before retry; never claim rollback or success
   without evidence. Do not hold a UI decision open inside a database transaction.

On confirmed success, reconcile ordinary in-memory browsing/search. Store/key
failure is fail-closed; never replace keys, reset the store, or erase existing data
to make import work. Newly imported records use the existing device key, Complete
File Protection, backup exclusion, and source-owned cascade deletion. Re-import
of a previously deleted UUID is explicit re-adoption of the selected external
copy; no tombstone, inferred deletion history, or background resurrection is added.

## Optional labeling after commit

Only explicit selection permits existing enabled local labelers to run on new
sources after successful commit. Do not process identical skips. Respect existing
rules/Apple opt-in and processor availability; unavailable processors are reported,
not enabled or substituted. A labeling failure neither rolls back sources nor
changes successful import into failure. Results remain machine derivatives;
separate their pending/failure status from the import result. No new provider,
cloud fallback, generated expected-label adoption, or inference inside commit.

## Required conformance evidence and completion boundary

Implementation under #946 needs valid Pocket and generic-list round trips,
Unicode/whitespace fidelity, original/current articulation distinctions, schema
and supplemental validation failures, boundary limits, identical/conflicting IDs,
transaction rollback, crash/uncertain acknowledgement, and conditional labeling
coverage. Also prove marked/unmarked/mixed JSON validation, rejection of invalid
material kinds, synthetic persistence across relaunch and local edits, origin
inspection/VoiceOver, no inference for unmarked Pocket v1, material conflicts,
no clearing of existing synthetic markers by unspecified/legacy input, native
origin preservation on identical skips, and cascade deletion of declarations.
Include two visually similar but Unicode-distinct texts with the same UUID as a conflict case; comparison must not rely on Swift's canonically equivalent
string equality. Compare exact decoded Unicode scalar/UTF-8 values for content.

Physical iPhone evidence uses synthetic files, Airplane Mode, relaunch, VoiceOver,
preview/cancel, protected-storage failure, and source deletion. Source text and
passwords never enter diagnostics. This contract change supplies schema and a
positive example only; production importer, generator/validator CLI, negative
fixture corpus, and these runtime checks remain implementation work.

No full database restore, new export version, audio bytes, relationship/context/
book/revision restore, web importer, proprietary adapters, schema bypass, account,
sync, or general migration framework is authorized by this slice.


## Implementation record for #946

PR #947 merged as `9de1968b57d28d467e00458ea2e4cf3d3155dc66`, verified as an
ancestor of freshly fetched `origin/main` before implementation. The user approved
[the shared provenance vocabulary and encrypted physical mapping](https://github.com/helloorigo/origo/blob/main/docs/02-architecture/pocket-chronicle-import-persistence.md)
on 2026-10-08 after the implementation review identified the closed v1 vocabulary
gap. See [end-user/tooling instructions](https://github.com/helloorigo/origo/blob/main/docs/01-product/pocket-chronicle-import-guide.md)
and [validation evidence](https://github.com/helloorigo/origo/blob/main/apps/pocket-chronicle/Validation/issue-946/README.md).
These records distinguish implementation from remaining manual release validation.
