com.airplaneian.contrail.temp.flight
Schema Diff
+53 -33
Compatibility Analysis
Breaking Changes Detected
2 breaking changes, 10 non-breaking changes.
Breaking Changes (2)
- RemovedVertex RemovedVertex { vertex_id: "com.airplaneian.contrail.temp.flight:body.operatingAirline" }
- RemovedEdge RemovedEdge { src: "com.airplaneian.contrail.temp.flight:body", tgt: "com.airplaneian.contrail.temp.flight:body.operatingAirline", kind: "prop", name: Some("operatingAirline") }
Non-Breaking Changes (10)
- AddedVertex AddedVertex { vertex_id: "com.airplaneian.contrail.temp.flight:body.callsign" }
- AddedVertex AddedVertex { vertex_id: "com.airplaneian.contrail.temp.flight:body.operator" }
- AddedVertex AddedVertex { vertex_id: "com.airplaneian.contrail.temp.flight:body.operatorName" }
- AddedVertex AddedVertex { vertex_id: "com.airplaneian.contrail.temp.flight:body.registeredOwner" }
- AddedVertex AddedVertex { vertex_id: "com.airplaneian.contrail.temp.flight:body.route" }
- AddedEdge AddedEdge { src: "com.airplaneian.contrail.temp.flight:body", tgt: "com.airplaneian.contrail.temp.flight:body.callsign", kind: "prop", name: Some("callsign") }
- AddedEdge AddedEdge { src: "com.airplaneian.contrail.temp.flight:body", tgt: "com.airplaneian.contrail.temp.flight:body.operator", kind: "prop", name: Some("operator") }
- AddedEdge AddedEdge { src: "com.airplaneian.contrail.temp.flight:body", tgt: "com.airplaneian.contrail.temp.flight:body.operatorName", kind: "prop", name: Some("operatorName") }
- AddedEdge AddedEdge { src: "com.airplaneian.contrail.temp.flight:body", tgt: "com.airplaneian.contrail.temp.flight:body.registeredOwner", kind: "prop", name: Some("registeredOwner") }
- AddedEdge AddedEdge { src: "com.airplaneian.contrail.temp.flight:body", tgt: "com.airplaneian.contrail.temp.flight:body.route", kind: "prop", name: Some("route") }
Migration Guidance
Removed Elements
RemovedVertex { vertex_id: "com.airplaneian.contrail.temp.flight:body.operatingAirline" }
Added Elements
AddedVertex { vertex_id: "com.airplaneian.contrail.temp.flight:body.callsign" }AddedVertex { vertex_id: "com.airplaneian.contrail.temp.flight:body.operator" }AddedVertex { vertex_id: "com.airplaneian.contrail.temp.flight:body.operatorName" }AddedVertex { vertex_id: "com.airplaneian.contrail.temp.flight:body.registeredOwner" }AddedVertex { vertex_id: "com.airplaneian.contrail.temp.flight:body.route" }
Additional Notes
- Breaking: RemovedEdge { src: "com.airplaneian.contrail.temp.flight:body", tgt: "com.airplaneian.contrail.temp.flight:body.operatingAirline", kind: "prop", name: Some("operatingAirline") }
- Non-breaking: AddedEdge { src: "com.airplaneian.contrail.temp.flight:body", tgt: "com.airplaneian.contrail.temp.flight:body.callsign", kind: "prop", name: Some("callsign") }
- Non-breaking: AddedEdge { src: "com.airplaneian.contrail.temp.flight:body", tgt: "com.airplaneian.contrail.temp.flight:body.operator", kind: "prop", name: Some("operator") }
- Non-breaking: AddedEdge { src: "com.airplaneian.contrail.temp.flight:body", tgt: "com.airplaneian.contrail.temp.flight:body.operatorName", kind: "prop", name: Some("operatorName") }
- Non-breaking: AddedEdge { src: "com.airplaneian.contrail.temp.flight:body", tgt: "com.airplaneian.contrail.temp.flight:body.registeredOwner", kind: "prop", name: Some("registeredOwner") }
- Non-breaking: AddedEdge { src: "com.airplaneian.contrail.temp.flight:body", tgt: "com.airplaneian.contrail.temp.flight:body.route", kind: "prop", name: Some("route") }
1
1
{
2
2
"id": "com.airplaneian.contrail.temp.flight",
3
3
"defs": {
4
4
"main": {
5
5
"key": "tid",
6
6
"type": "record",
7
7
"record": {
8
8
"type": "object",
9
9
"required": [
10
10
"createdAt"
11
11
],
12
12
"properties": {
13
13
"date": {
14
14
"type": "string",
15
15
"maxLength": 10,
16
-
"description": "Calendar date of departure at the origin, as 'YYYY-MM-DD'. Present as its own field rather than derived from the timestamps because it is one third of the commercial identity key -- date plus 'operatingAirline' plus 'flightNumber' -- and because deriving it from an instant requires knowing the origin's local offset, which a reader may not have. Where both this and a departure timestamp are written they must agree. Write it consistently, since cross-repository matching depends on it."
16
+
"description": "Calendar date of departure at the origin, as 'YYYY-MM-DD'. Part of the identity key with 'operator' and 'flightNumber'. Must agree with any departure timestamp."
17
17
},
18
18
"seat": {
19
19
"type": "string",
20
20
"maxLength": 16,
21
-
"description": "Seat occupied, as a string, for example '14C' -- row and position together, since the letter is not optional and the whole thing is not a number. Only meaningful when 'relationship' indicates the author was aboard."
21
+
"description": "Seat occupied, as a string, for example '14C'."
22
22
},
23
23
"cabin": {
24
24
"type": "string",
25
25
"maxLength": 64,
26
-
"description": "Cabin or class of service. An open string rather than an enumeration because carriers invent and rename cabins continually and any closed set would be obsolete within a year. Write lower camel case, matching the known values below, so that records from different tools compare equal; readers must tolerate values outside the list.",
26
+
"description": "Cabin or class of service. An open string in lower camel case; the known values are not exhaustive.",
27
27
"knownValues": [
28
28
"economy",
29
29
"premiumEconomy",
30
30
"business",
31
31
"first"
32
32
]
33
33
},
34
34
"notes": {
35
35
"type": "string",
36
36
"maxLength": 10000,
37
-
"description": "Free-text note about the flight. Everything written here is public and permanent once the record is published, and unlike the structured fields its contents cannot be reviewed by a tool for anything the author did not mean to disclose. Tools writing records on a user's behalf should show note contents prominently before publishing. Do not use this field to carry structured data that belongs in a dedicated field, and do not use it for booking references or other credentials.",
37
+
"description": "Free-text note. Public as soon as the record is written, and copies may persist after the record is deleted. Do not put booking references or other credentials here.",
38
38
"maxGraphemes": 1000
39
39
},
40
+
"route": {
41
+
"type": "string",
42
+
"maxLength": 1000,
43
+
"description": "The route as filed, written as the flight plan expressed it, for example 'SSTIK2 SSTIK Q90 AVOSE'. Free text, not normalised and not reliable for matching. This is the planned route, not the flown track: a track belongs in a surveillance archive, which 'icao24' and a departure time are enough to query."
44
+
},
40
45
"icao24": {
41
46
"type": "string",
42
47
"maxLength": 8,
43
-
"description": "The airframe's 24-bit ICAO address as six lowercase hexadecimal characters, for example 'a1b2c3'. Stable per airframe and the primary identity field for general aviation, where there is no flight number to match on. Together with an actual departure time it forms the general aviation identity key; write both consistently, since cross-repository matching depends on them."
48
+
"description": "The airframe's 24-bit ICAO address, six lowercase hexadecimal characters. With an actual departure time this is the identity key for flights with no flight number."
44
49
},
45
50
"origin": {
46
51
"ref": "com.airplaneian.contrail.temp.defs#place",
47
52
"type": "ref",
48
-
"description": "Where the flight departed. May equal 'destination': local flights that return to their departure point, such as circuits, sightseeing, or training sorties, are ordinary and must not be treated as an error."
53
+
"description": "Where the flight departed. May equal 'destination'; local flights are ordinary."
49
54
},
50
55
"source": {
51
56
"type": "string",
52
57
"maxLength": 64,
53
-
"description": "Short identifier for the tool or dataset that produced this record, for example 'flighty', 'manual', or 'adsb'. Together with 'sourceId' this lets a tool find the records it wrote previously and update them in place instead of creating duplicates on a re-import. It also records provenance: the same record shape carries a first-hand passenger entry and a machine-harvested observation, and 'source' is what distinguishes them."
58
+
"description": "Short identifier for the tool or dataset that wrote this record, for example 'flighty', 'manual', or 'adsb'."
54
59
},
55
60
"status": {
56
61
"type": "string",
57
62
"maxLength": 32,
58
-
"description": "How the flight concluded. Absent means unknown rather than normal, so write 'normal' explicitly when it is known that the flight operated as planned. An open string for consistency with the other classification fields here; readers must tolerate values outside the list.",
63
+
"description": "How the flight concluded. Absent means unknown, so write 'normal' explicitly when the flight operated as planned.",
59
64
"knownValues": [
60
65
"normal",
61
66
"cancelled",
62
67
"diverted"
63
68
]
64
69
},
70
+
"callsign": {
71
+
"type": "string",
72
+
"maxLength": 16,
73
+
"description": "The flight identification the aircraft broadcast, uppercase and exactly as transmitted. Holds the whole callsign, never a fragment of one. May be an operator designator followed by a flight number, a registration, or a string with no internal structure."
74
+
},
75
+
"operator": {
76
+
"type": "string",
77
+
"maxLength": 8,
78
+
"description": "ICAO designator of the agency that operated the flight, three letters, uppercase. Not airlines only: 'UAL', 'FDX', 'RCH'. Use 'operatorName' where no designator exists."
79
+
},
65
80
"sourceId": {
66
81
"type": "string",
67
82
"maxLength": 512,
68
-
"description": "The identifier the tool named in 'source' uses for this flight, in that tool's own namespace -- typically an opaque key from an export. Deliberately stored in the record body rather than encoded into the record key, so that a record can be corrected without changing its identity: deriving keys from content would turn a fixed flight number into a new record instead of an update. Meaningful only in combination with 'source', and carries no meaning to readers who do not know that tool."
83
+
"description": "That tool's own identifier for this flight. Kept in the record body rather than the record key, so a record can be corrected without becoming a new one. Meaningful only with 'source'."
69
84
},
70
85
"createdAt": {
71
86
"type": "string",
72
87
"format": "datetime",
73
-
"description": "When this record was written, as distinct from when the flight happened. The only required field. Write it with an explicit UTC offset and no fractional seconds, for example '2026-07-24T18:22:05-07:00' or '2026-07-25T01:22:05Z'. Fractional seconds are omitted throughout this schema because trailing zeroes in a fractional part round-trip ambiguously and lose precision inconsistently between implementations; a fixed convention avoids both problems."
88
+
"description": "When this record was written, not when the flight happened. Explicit UTC offset, no fractional seconds."
74
89
},
75
90
"destination": {
76
91
"ref": "com.airplaneian.contrail.temp.defs#place",
77
92
"type": "ref",
78
-
"description": "Where the flight arrived, or where it was intended to arrive if it was cancelled. If the flight diverted, this remains the intended destination and the actual landing place goes in 'diversionAirport'."
93
+
"description": "Where the flight arrived, or was intended to arrive if it was cancelled. If it diverted, this stays the intended destination and 'diversionAirport' holds where it landed."
79
94
},
80
95
"aircraftType": {
81
96
"type": "string",
82
97
"maxLength": 128,
83
-
"description": "Free-text description of the aircraft type as the source expressed it, for example 'Boeing 737-800' or 'Piper PA-18 Super Cub'. Present because most sources supply a name rather than a designator, and discarding it in favour of an empty 'icaoTypeDesignator' would lose real information. Not normalised and not reliable for matching -- use 'icaoTypeDesignator' for that. Do not derive one field from the other: a guessed designator is worse than an absent one, since several distinct designators share a single marketing name."
98
+
"description": "Free-text aircraft type as the source expressed it, for example 'Boeing 737-800'. Not normalised and not reliable for matching. Several distinct ICAO designators can share one marketing name."
84
99
},
85
100
"flightNumber": {
86
101
"type": "string",
87
102
"maxLength": 16,
88
-
"description": "The operating carrier's flight number, as a string rather than an integer. Alphabetic suffixes are in real use, some sources emit malformed values, and a numeric type could never be loosened later without breaking every existing record. Write the digits alone without the airline designator prefix. Part of the commercial identity key; write it consistently, since cross-repository matching depends on it."
103
+
"description": "The operating agency's flight number, as a string. Digits only, without the operator prefix."
104
+
},
105
+
"operatorName": {
106
+
"type": "string",
107
+
"maxLength": 128,
108
+
"description": "Free-text name of the operating agency, for operators with no ICAO designator. Not reliable for matching. This is who flew the aircraft, which is often not who owns it."
89
109
},
90
110
"registration": {
91
111
"type": "string",
92
112
"maxLength": 16,
93
-
"description": "Civil registration of the airframe, for example 'N12345' or 'GVBOW'. Write it uppercase with no hyphens, spaces, or other separators, so that 'G-VBOW' and 'GVBOW' do not become two different aircraft to a reader. This normalisation matters because registration is one of the few fields by which general aviation records can be matched across repositories. Note that registrations are reassigned to different airframes over time, so 'icao24' is the more durable airframe identifier where it is known."
113
+
"description": "Registration or tail number, uppercase with no hyphens or spaces, so that 'G-VBOW' and 'GVBOW' are one aircraft. Military and state identifiers go here too."
94
114
},
95
115
"relationship": {
96
116
"type": "string",
97
117
"maxLength": 64,
98
-
"description": "The author's connection to this flight. Unlike every other field in this record, absent here does not mean unknown: it means no claim of any relationship is being made. A record written from ADS-B data about someone else's flight simply omits it. An open string rather than a closed set, so that relationships nobody anticipated can be expressed without a schema change; readers must tolerate values outside the known list. Note that omitting this field does not make a record private -- the presence of flight records in a repository discloses the author's connection to those flights regardless of what the records claim.",
118
+
"description": "The author's connection to this flight. Absent means no claim is being made, unlike every other field where absent means unknown. An open string: the known values are not exhaustive.",
99
119
"knownValues": [
100
120
"passenger",
101
121
"pic",
102
122
"sic",
103
123
"student",
104
124
"instructor",
105
125
"crew",
106
126
"observer"
107
127
]
108
128
},
109
129
"actualLanding": {
110
130
"type": "string",
111
131
"format": "datetime",
112
-
"description": "Actual wheels-on time -- the 'on' time. Explicit UTC offset, no fractional seconds. The interval between this and 'actualTakeoff' is flight time; do not store that interval, as it is derivable."
132
+
"description": "Actual 'on' time, wheels on. Explicit UTC offset, no fractional seconds."
113
133
},
114
134
"actualTakeoff": {
115
135
"type": "string",
116
136
"format": "datetime",
117
-
"description": "Actual wheels-off time -- the 'off' time. Explicit UTC offset, no fractional seconds. Together with 'icao24' this forms the general aviation identity key, and it is usually the most reliably known time for a flight with no gate operations."
137
+
"description": "Actual 'off' time, wheels off. Explicit UTC offset, no fractional seconds."
138
+
},
139
+
"registeredOwner": {
140
+
"type": "string",
141
+
"maxLength": 128,
142
+
"description": "Free-text name of the party the airframe is registered to. Often a trust or holding company, and frequently not the operator."
118
143
},
119
144
"diversionAirport": {
120
145
"ref": "com.airplaneian.contrail.temp.defs#place",
121
146
"type": "ref",
122
-
"description": "Where the flight actually landed, when it did not land at 'destination'. Present only when 'status' is 'diverted'. 'destination' continues to hold the intended arrival point."
147
+
"description": "Where the flight actually landed, when that was not 'destination'. Present only when 'status' is 'diverted'."
123
148
},
124
149
"marketingAirline": {
125
150
"type": "string",
126
151
"maxLength": 8,
127
-
"description": "ICAO designator of the airline that sold the flight, when it differs from 'operatingAirline' -- that is, for codeshares. Absent means either that there was no codeshare or that it is unknown. Do not put the marketing carrier in 'operatingAirline'; the distinction is what lets two records describing one physical flight be recognised as such."
128
-
},
129
-
"operatingAirline": {
130
-
"type": "string",
131
-
"maxLength": 8,
132
-
"description": "ICAO designator of the airline that actually operated the flight, three letters, uppercase -- 'UAL', not 'UA'. ICAO rather than IATA because IATA airline codes are recycled between carriers, so a historical record tagged with one is ambiguous. Unset for most general aviation. Part of the commercial identity key alongside 'date' and 'flightNumber'; write it consistently, since cross-repository matching depends on it."
152
+
"description": "ICAO designator of the airline that sold the flight, when it differs from 'operator'. Codeshares only."
133
153
},
134
154
"scheduledLanding": {
135
155
"type": "string",
136
156
"format": "datetime",
137
-
"description": "Scheduled wheels-on time -- the 'on' time. Explicit UTC offset, no fractional seconds."
157
+
"description": "Scheduled 'on' time, wheels on. Explicit UTC offset, no fractional seconds."
138
158
},
139
159
"scheduledTakeoff": {
140
160
"type": "string",
141
161
"format": "datetime",
142
-
"description": "Scheduled wheels-off time -- the 'off' time. Explicit UTC offset, no fractional seconds."
162
+
"description": "Scheduled 'off' time, wheels off. Explicit UTC offset, no fractional seconds."
143
163
},
144
164
"actualGateArrival": {
145
165
"type": "string",
146
166
"format": "datetime",
147
-
"description": "Actual time the aircraft reached the gate or parking position -- the 'in' time. Explicit UTC offset, no fractional seconds."
167
+
"description": "Actual 'in' time, reaching the gate or parking position. Explicit UTC offset, no fractional seconds."
148
168
},
149
169
"icaoTypeDesignator": {
150
170
"type": "string",
151
171
"maxLength": 8,
152
-
"description": "ICAO aircraft type designator, for example 'B77W' or 'C172'. Write it only when the source actually supplies a designator, not when it has been inferred from a marketing name."
172
+
"description": "ICAO aircraft type designator, for example 'B77W'."
153
173
},
154
174
"actualGateDeparture": {
155
175
"type": "string",
156
176
"format": "datetime",
157
-
"description": "Actual time the aircraft left the gate or parking position -- the 'out' time. Explicit UTC offset, no fractional seconds. The interval between this and 'actualGateArrival' is block time; do not store that interval, as it is derivable."
177
+
"description": "Actual 'out' time, leaving the gate or parking position. Explicit UTC offset, no fractional seconds."
158
178
},
159
179
"scheduledGateArrival": {
160
180
"type": "string",
161
181
"format": "datetime",
162
-
"description": "Scheduled time the aircraft reached the gate or parking position -- the 'in' time. Explicit UTC offset, no fractional seconds."
182
+
"description": "Scheduled 'in' time, reaching the gate or parking position. Explicit UTC offset, no fractional seconds."
163
183
},
164
184
"marketingFlightNumber": {
165
185
"type": "string",
166
186
"maxLength": 16,
167
-
"description": "Flight number under which the flight was sold, when it differs from 'flightNumber'. A string, for the same reasons."
187
+
"description": "Flight number under which the flight was sold, when it differs from 'flightNumber'."
168
188
},
169
189
"scheduledGateDeparture": {
170
190
"type": "string",
171
191
"format": "datetime",
172
-
"description": "Scheduled time the aircraft left the gate or parking position -- the 'out' time. Write it with an explicit UTC offset and no fractional seconds. The eight time fields form the standard out/off/on/in set; all are optional, so a record knowing only a takeoff time is perfectly valid, and general aviation records will usually omit the gate times entirely."
192
+
"description": "Scheduled 'out' time, leaving the gate or parking position. Explicit UTC offset, no fractional seconds."
173
193
}
174
194
}
175
195
},
176
-
"description": "An assertion that a particular flight existed. This is not a first-person log entry: the record describes the flight itself, and the author's connection to it -- passenger, pilot, observer -- is an optional annotation via 'relationship' rather than the point of the record. A record written from ADS-B data about a stranger's flight and a record written from the author's own boarding pass are the same kind of assertion with different provenance, distinguished by 'source' and by whether 'relationship' is present. Because the record is about the flight rather than about the author, several people will write records describing the same flight, and none of them is canonical. That duplication is expected and by design. It does mean readers need to recognise two repositories describing one flight, so the identity fields matter more here than they would in a personal-log model: for commercial flights write 'date', 'operatingAirline', and 'flightNumber' consistently; for general aviation write 'icao24' and an actual departure time. There is deliberately no global flight identifier, because no authority exists to issue one. The record accommodates commercial airline travel and general aviation equally -- a widebody on a transpacific sector and a light aircraft flying circuits at an unlicensed strip are both valid, and origin may equal destination. Only 'createdAt' is required. Every other field being optional is the single most important property of this schema: absent means unknown or not applicable, and there are no sentinel values for unknowns. A tool that wants complete data should reject incomplete input itself rather than expect the schema to enforce it. Values derivable from other fields are excluded on purpose -- duration, distance, and great-circle miles are all computable from times and places, and storing them guarantees that records written by different tools disagree. Reference data about the world, such as airport names, coordinates looked up from a code, or aircraft specifications, likewise does not belong in a user's repository. Note that a collection of these records is a movement history: it discloses home airport, travel cadence, and periods away from home. That disclosure follows from the records being present in a repository at all, and is not affected by whether 'relationship' claims the author was aboard."
196
+
"description": "An assertion that a particular flight existed, rather than a personal log entry about the author. Only 'createdAt' is required. Every other field is optional, and absent means unknown or not applicable rather than empty or zero. The exception is 'relationship', where absent means no claim is being made. Records of the same flight written by different people are expected, so write the identifying fields consistently. Any kind of flying is in scope, and origin may equal destination."
177
197
}
178
198
},
179
199
"$type": "com.atproto.lexicon.schema",
180
200
"lexicon": 1
181
201
}