DisclosureOS documentation · v2 Beta
Observation records
Attach a source, record what it says and handle the validation result.
Use an observation to connect source material, reported values, measurements and processing history. It can hold an incomplete or disputed report. Including a value in a record does not establish that the value is true; attributed interpretations belong in a separate claim history.
This guide takes the next step after your first record. You will use one source from the fictional DisclosureOS example case, save a small observation and test a broken reference. The full case remains available in the showcase.
Requirements: Node.js 22 and the published @disclosureos/records@2.0.0-beta.4 package. Reuse your quickstart directory, or install that exact version in a new npm project. The observation's document version remains 0.1.0; it is separate from the package version.
1. Read the source
Open the example station log. It identifies itself as synthetic and describes a four-minute field session:
The four-minute session begins at 21:00 UTC on 14 August 2026.
We can represent that declared session as an interval from 21:00 to 21:04 UTC. The log does not provide geographic coordinates, so the position stays unknown. This is a teaching draft assembled from the same source used by the showcase, with the recordings and other material left out.
Your application retains the source file and decides how people access it. The observation stores its identity and, optionally, a URI and digest. The parser does not download or read the file.
2. Build the observation
Save the complete example below as source-record.mjs in your project directory. It needs only the records package and Node's built-in file writer.
import { writeFileSync } from "node:fs";
import { parseExperimentalObservation } from "@disclosureos/records/experimental/v2";
const observation = {
kind: "observation",
schemaVersion: "0.1.0",
id: "docs-field-session",
status: "draft",
createdAt: "2026-10-16T00:00:00Z",
updatedAt: "2026-10-16T00:00:00Z",
eventTime: {
state: "known",
value: {
kind: "interval",
start: {
kind: "instant",
value: "2026-08-14T21:00:00.000Z",
timeScale: "UTC",
},
end: {
kind: "instant",
value: "2026-08-14T21:04:00.000Z",
timeScale: "UTC",
},
},
sourceRefs: ["source:station-log"],
},
position: { state: "unknown", reason: "not_collected" },
sources: [
{
id: "station-log",
title: "Field session log",
kind: "document",
access: "public",
uri: "https://os.disclosure.org/examples/meridian/station-log.txt",
},
],
products: [],
methods: [],
frames: [],
assertions: [],
measurements: [],
processing: [],
};
const result = parseExperimentalObservation(observation);
console.log(
JSON.stringify(
{
success: result.success,
checks: result.checks,
uncheckedRefs: result.uncheckedRefs,
},
null,
2
)
);
if (!result.success) {
console.error(JSON.stringify(result.issues, null, 2));
process.exitCode = 1;
} else {
writeFileSync(
"source-observation.json",
JSON.stringify(result.data, null, 2) + "\n"
);
console.log("Saved source-observation.json");
}Four details connect this record to its source:
- Source identity:
sources[0].idgives the log a local ID,station-log. - Source reference:
eventTime.sourceRefsusessource:station-logto point to that entry. The prefix identifies the kind of reference; it is not a URL. - Reported time:
eventTime.valueholds the interval described in the log.state: "known"means a value is supplied with support, not independently confirmed. - Document dates:
createdAtandupdatedAtdescribe the document's lifecycle. They do not replace the event time.
status: "draft" is a declared lifecycle state. Changing it to published does not upload the document or certify it. The empty arrays are allowed; this example has no instrument measurements or declared processing.
3. Validate and save
Run the file from your project directory:
node source-record.mjsYou should see this result, followed by Saved source-observation.json:
{
"success": true,
"checks": {
"structural": "passed",
"semantic": "passed",
"profile": "not_checked",
"external": "not_checked"
},
"uncheckedRefs": ["source:station-log"]
}The structure is valid and the local source reference resolves. The parser has not opened the log, compared the declared interval with its text or verified its authenticity. That is why the source remains in uncheckedRefs and external remains not_checked. A profile check has not run either.
The example writes result.data only after success is true. In your application, show or log result.issues on failure and stop that import. A failed run leaves any previously saved file untouched; use the exit status to decide whether the current run produced a valid output.
To inspect the saved result visually, open the browser inspector, use Open JSON to load source-observation.json, then choose Check document. Your input stays in the browser. Saving or inspecting the record does not publish it.
4. Try a broken reference
In eventTime.sourceRefs, replace source:station-log with source:missing. Keep the source inventory unchanged, then run the script again.
The document still has the right shape, but its reference no longer resolves. success becomes false, structural stays passed, and semantic becomes failed. The script exits with status 1 and prints this issue:
[
{
"code": "REF.LOCAL_RESOLUTION",
"stage": "semantic",
"severity": "error",
"pointer": "/eventTime/sourceRefs/0",
"message": "Undeclared local reference: source:missing"
}
]The JSON Pointer identifies the first entry in eventTime.sourceRefs. Restore source:station-log to make the record pass again.
This is a semantic error. By contrast, an invalid field type or an unexpected field fails the structural check and leaves dependent semantic checks not_checked. A JSON Schema validator can check structure; reference resolution, time ordering, selections, unit consistency and processing lineage require the parser or an equivalent semantic implementation.
How the record fits together
Use the parts that your material needs. Required inventory arrays can be empty; an empty list does not establish that nothing was observed or that a research profile is satisfied.
| Part | What it holds |
|---|---|
| Identity and lifecycle | The record ID, draft/publication state and document timestamps. |
| Event time and position | Supported values, approximate values, explicit gaps or redactions. |
| Sources | An inventory of documents, testimony, instrument data and other source material. |
| Products | Raw or derived data products, with source or processing links. |
| Methods and frames | Declared methods, their versions and coordinate reference frames. |
| Assertions | Particular values extracted from sources, with provenance and available locators. |
| Measurements | Quantities, values, units, uncertainty and supporting references. |
| Processing | Declared activities connecting inputs, outputs, methods, actors and times. |
For exact alternatives and constraints, use the observation field reference. The schema is also exported through @disclosureos/records/experimental/v2/observation/schema; its identifier is urn:disclosureos:experimental:observation:0.1.0.
Preserve time, position and uncertainty
A known or approximate time or position carries supporting references. Approximate values also declare precision. Unknown and redacted values carry a reason. Use these states instead of inventing midnight, a zero duration or coordinates at zero latitude and longitude.
A measured quantity has a signed value, a unit and an uncertainty object. Uncertainty can be unknown, standard, expanded or bound. Expanded uncertainty requires a positive coverage factor; it does not infer a coverage probability. Quantity and uncertainty units must match exactly. The parser does not convert units or certify their physical meaning.
Positions retain their coordinate frames. Geographic angles use degrees. Keep metric position uncertainty separate from angular uncertainty, and declare a matching vertical reference for geodetic altitude. An unknown frame definition stays unknown.
Keep alternatives and selections visible
The small example links its time directly to a source. Use assertions when you need to preserve individual extracted values, their provenance or competing accounts. An assertion can retain its source locator and original-author and extractor identities. It does not have to become the record's current value.
When a current value cites a local assertion, include an explicit selection: who selected it, when, the method and version, the inputs considered, and the reason. The selected value must be copied exactly. You can retain several assertions while leaving the current value unknown; the parser does not average them or choose an interpretation.
Keep attributed assessments of those values in a claim history. A source's reported wording, a selected value and an assessment have different roles.
Trace product lineage
Use a raw product to describe retained data linked to its sources. A derived product identifies the processing activity that produced it. Each activity declares its inputs, outputs, method and version, actor and time.
Those links must resolve consistently in both directions. Local processing cycles fail validation. A declared processing step does not prove that the output was reproduced. The complete measurement example follows this pattern through a raw product, a reduction and a measured value.
Normative objects reject unexpected fields. Namespaced extensions can retain additional JSON, but the core does not validate its meaning. Access labels and redacted fields do not remove sensitive information from other fields or files. Review the full publication separately.
Add the next part
Choose the guide that matches your source material. These additions connect to the observation; they do not all need to be included in one record.
| Your next task | Guide |
|---|---|
| Connect a reading to the equipment and capture that produced it | Instruments |
| Describe reported objects, places, platforms, conditions or historical time | Event and setting |
| Retain witnesses, distinct accounts, recording context and sourced qualifications | Witnesses and accounts |
| Track document editions, release events and digital custody | Documents and custody |
| Connect collected specimens, preparation and laboratory results | Materials and laboratory |
| Attach a review with a subject, supporting inputs, reviewer and method | Claims |
Witness and document entities attach detailed declarations to exact observation snapshots. Material and laboratory contracts are also included in Beta 4; their guide describes the separate specimen, preparation and result identities. Add those documents when your integration needs them.
See the same source in the showcase
Open the field recording. The full fictional case connects this session to recordings, accounts, documents and samples. This guide's smaller record deliberately keeps only the station-log source and session time so you can understand and reproduce the first connection.
For the public explanation of these concepts, visit the Records standard page. For exact implementation detail, return to the field reference.