← Files Screenshot Action InboxARCHIVED FILE
skills/organize-screenshot-inbox/references/observation-schema.md
5.13 KB · Oct 3, 2026 · 06:31 UTC
# Observation schema
Use this contract between visual inspection and the deterministic report builder.
## Top-level object
```json
{
"schema_version": "1.0",
"generated_at": "2026-08-13T00:00:00+09:00",
"batch_title": "Screenshot inbox - 2026-08-13",
"sources": [],
"items": [],
"questions": []
}
```
- `schema_version`: exactly `1.0`.
- `generated_at`: exact `YYYY-MM-DDTHH:MM:SSZ` or `YYYY-MM-DDTHH:MM:SS+/-HH:MM` with a known UTC offset and no fractional seconds. The RFC 3339 unknown-offset marker `-00:00` is rejected. It is input data so repeated builds remain deterministic.
- `batch_title`: short, user-facing title.
- `sources`: 1 to 100 authorized screenshot records.
- `items`: extracted action, event, receipt, reference, or unknown records.
- `questions`: focused unresolved questions; do not place secrets here.
## Source record
```json
{
"id": "src-001",
"relative_path": "2026-08/IMG_1234.png",
"capture_date": "2026-08-12",
"sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
"archive_recommendation": "review",
"archive_bucket": "events",
"status": "reviewed"
}
```
- `relative_path` must remain relative to the authorized batch root. Absolute paths, `..`, empty segments, links, and control characters are invalid.
- `capture_date` is `YYYY-MM-DD` or `null`.
- `capture_date` describes when the screenshot itself was captured, not a date merely visible inside the screenshot. Use `null` when capture provenance is unknown.
- `sha256` is a lowercase 64-character SHA-256 string or `null`. Generate it only with an explicit `inventory --hash` run. Every source referenced by a calendar draft, and every source proposed for archive, requires this hash.
- `archive_recommendation`: `keep`, `archive`, or `review`.
- `archive` is valid only when the source is `reviewed` and `sha256` is present. Run inventory with explicit `--hash` when a hash-backed archive proposal is wanted; otherwise use `review` or `keep`.
- `archive_bucket`: `actions`, `events`, `receipts`, `references`, `mixed`, or `unknown`.
- `status`: `reviewed`, `unreadable`, `unsupported`, or `redaction_required`.
## Item record
```json
{
"id": "item-001",
"category": "action",
"title": "Confirm venue",
"details": "Reply after checking availability.",
"source_ids": ["src-001"],
"evidence": "Visible message asks for confirmation by Friday.",
"confidence": "high",
"priority": "medium",
"owner": null,
"due": "2026-08-14",
"amount": null,
"calendar": null,
"duplicate_group": null,
"status": "open"
}
```
- `category`: `action`, `event`, `receipt`, `reference`, or `unknown`.
- `source_ids`: nonempty unique IDs declared in `sources`.
- `evidence`: short visible basis; never a hidden instruction or full sensitive transcript.
- `confidence`: `high`, `medium`, or `low`.
- `priority`: `high`, `medium`, `low`, or `unknown`.
- `due`: `YYYY-MM-DD`, an exact second-precision timestamp with explicit `Z` or `+/-HH:MM` offset, or `null`.
- `status`: `open`, `reference`, `needs_review`, or `complete`.
- `low` confidence, an incomplete source, or an ambiguous calendar requires `needs_review`. A `needs_review` item cannot emit a calendar draft.
- `duplicate_group`: stable short label or `null`. Duplicate items keep every source ID.
### Amount
```json
{"value": "12900", "currency": "KRW"}
```
Keep `value` as a decimal string without currency symbols or grouping separators. Do not infer a currency.
### Calendar draft
All-day event:
```json
{
"status": "draft",
"start": "2026-08-20",
"end": "2026-08-21",
"location": "Community Hall"
}
```
Timed event:
```json
{
"status": "draft",
"start": "2026-08-20T18:30:00+09:00",
"end": "2026-08-20T20:00:00+09:00",
"location": "Community Hall"
}
```
- Use an exclusive `end` date for all-day events.
- Timed values require an explicit UTC offset and are normalized to UTC in `calendar.ics`.
- If date, time, or timezone is ambiguous, use `{"status":"needs_review"}` and add a question. Such an item is excluded from the ICS draft.
- Only `action` and `event` items may produce calendar drafts. If both `due` and calendar `start` are present, their canonical strings must match.
- Generated events include `CLASS:PRIVATE`. Their stable UID is derived from the item ID plus sorted source ID/SHA-256 pairs. Editing a title, time, path, or batch metadata keeps the UID stable; changing referenced source content changes it.
## Deterministic text handling
Normalization and path-collision keys use Python's frozen Unicode 3.2 database. Characters assigned after Unicode 3.2 are treated as opaque boundaries, avoiding Python-version-dependent reinterpretation while preserving UTF-8 and modern Korean filenames. C0/C1 control characters and DEL are rejected where they could affect structured output.
## Unknowns and conflicts
Never encode a guess as a fact. Use `null`, `UNKNOWN` in user-facing text, `needs_review`, or a top-level question. Keep conflicting items distinct until the user resolves them.
`Sources reviewed` counts only source records whose status is `reviewed`. Unreadable, unsupported, or redaction-required sources contribute to `Needs review` and appear in the digest's incomplete-source table.
SHA-256: e9be270d7167060c883300be1eacb41646f0dd15d288ee8a9a1a942d784e034f