com.airplaneian.contrail.temp.flight
Schema Diff
+25 -10
Compatibility Analysis
Breaking Changes Detected
2 breaking changes, 8 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 (8)
- 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" }
- 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") }
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" }
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") }
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'. Present as its own field rather than derived from the timestamps because it is one third of the commercial identity key -- date plus 'operator' 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."
17
17
},
18
18
"seat": {
19
19
"type": "string",
20
20
"maxLength": 16,
21
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."
22
22
},
23
23
"cabin": {
24
24
"type": "string",
25
25
"maxLength": 64,
26
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.",
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
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.",
38
38
"maxGraphemes": 1000
39
39
},
40
40
"icao24": {
41
41
"type": "string",
42
42
"maxLength": 8,
43
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."
44
44
},
45
45
"origin": {
46
46
"ref": "com.airplaneian.contrail.temp.defs#place",
47
47
"type": "ref",
48
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."
49
49
},
50
50
"source": {
51
51
"type": "string",
52
52
"maxLength": 64,
53
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."
54
54
},
55
55
"status": {
56
56
"type": "string",
57
57
"maxLength": 32,
58
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.",
59
59
"knownValues": [
60
60
"normal",
61
61
"cancelled",
62
62
"diverted"
63
63
]
64
64
},
65
+
"callsign": {
66
+
"type": "string",
67
+
"maxLength": 16,
68
+
"description": "The flight identification the aircraft transmitted, written exactly as received, uppercase with no padding or spaces. This is the primary flight identifier available from ADS-B and other surveillance sources, and it must not be decomposed on the way in: 'UAL38' splits cleanly into an operator and a flight number, but a general aviation aircraft transmits its registration, and state or military aircraft commonly transmit something with no civil structure at all, such as 'LEGACY' or 'KLH71'. Write this field verbatim and populate 'operator' and 'flightNumber' as well only when the split is unambiguous. Absent for sources that never see a callsign, such as a passenger's own booking history."
69
+
},
70
+
"operator": {
71
+
"type": "string",
72
+
"maxLength": 8,
73
+
"description": "ICAO designator of the agency that actually operated the flight, three letters, uppercase. Not restricted to airlines: 'UAL' for an airline, 'FDX' for a cargo carrier, 'RCH' for a military air mobility flight. ICAO rather than IATA because IATA codes are recycled between carriers, so a historical record tagged with one is ambiguous. Absent for most general aviation, where no designator exists; use 'operatorName' in that case. Part of the commercial identity key alongside 'date' and 'flightNumber', so write it consistently where it is known, since cross-repository matching depends on it."
74
+
},
65
75
"sourceId": {
66
76
"type": "string",
67
77
"maxLength": 512,
68
78
"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."
69
79
},
70
80
"createdAt": {
71
81
"type": "string",
72
82
"format": "datetime",
73
83
"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."
74
84
},
75
85
"destination": {
76
86
"ref": "com.airplaneian.contrail.temp.defs#place",
77
87
"type": "ref",
78
88
"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'."
79
89
},
80
90
"aircraftType": {
81
91
"type": "string",
82
92
"maxLength": 128,
83
93
"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."
84
94
},
85
95
"flightNumber": {
86
96
"type": "string",
87
97
"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."
98
+
"description": "The operating agency'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 operator designator prefix. Part of the commercial identity key, so write it consistently, since cross-repository matching depends on it. Absent for flights that have no flight number, which is most of general aviation and much state and military flying."
89
99
},
100
+
"operatorName": {
101
+
"type": "string",
102
+
"maxLength": 128,
103
+
"description": "Free-text name of the agency that operated the flight, for operators that have no ICAO designator: flight schools, charter and air taxi businesses, law enforcement and government units, private owners flying their own aircraft. Not normalised and not reliable for matching, in the same way that 'aircraftType' complements 'icaoTypeDesignator'. Do not restate here the name of an operator whose designator is already in 'operator'. Note that this is who flew the aircraft, which is frequently not who owns it."
104
+
},
90
105
"registration": {
91
106
"type": "string",
92
107
"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."
108
+
"description": "Registration or tail number 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. Military and state aircraft carry identifiers in this field too, in whatever form their operator uses, such as 'MM62209' or 'FAC1215'. Note that registrations are reassigned to different airframes over time, so 'icao24' is the more durable airframe identifier where it is known."
94
109
},
95
110
"relationship": {
96
111
"type": "string",
97
112
"maxLength": 64,
98
113
"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.",
99
114
"knownValues": [
100
115
"passenger",
101
116
"pic",
102
117
"sic",
103
118
"student",
104
119
"instructor",
105
120
"crew",
106
121
"observer"
107
122
]
108
123
},
109
124
"actualLanding": {
110
125
"type": "string",
111
126
"format": "datetime",
112
127
"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."
113
128
},
114
129
"actualTakeoff": {
115
130
"type": "string",
116
131
"format": "datetime",
117
132
"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."
118
133
},
134
+
"registeredOwner": {
135
+
"type": "string",
136
+
"maxLength": 128,
137
+
"description": "Free-text name of the party the airframe is registered to, as the civil registry records it. This is deliberately separate from 'operator' and 'operatorName', because the registrant is frequently not the operator: a large share of the fleet is registered to trusts, banks, or single-purpose holding companies, such as 'WILMINGTON TRUST CO TRUSTEE' or a limited company named after the tail number. Surveillance datasets usually expose a single combined owner-or-operator field, and its contents are the registrant, so it belongs here rather than in 'operator'. Absent for aircraft with no public registry entry, which includes most military aircraft."
138
+
},
119
139
"diversionAirport": {
120
140
"ref": "com.airplaneian.contrail.temp.defs#place",
121
141
"type": "ref",
122
142
"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."
123
143
},
124
144
"marketingAirline": {
125
145
"type": "string",
126
146
"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."
147
+
"description": "ICAO designator of the airline that sold the flight, when it differs from 'operator'. This one is deliberately named for airlines, because codeshare marketing is an airline arrangement and has no counterpart in other kinds of operation. Absent means either that there was no codeshare or that it is unknown. Do not put the marketing carrier in 'operator'; the distinction is what lets two records describing one physical flight be recognised as such."
133
148
},
134
149
"scheduledLanding": {
135
150
"type": "string",
136
151
"format": "datetime",
137
152
"description": "Scheduled wheels-on time -- the 'on' time. Explicit UTC offset, no fractional seconds."
138
153
},
139
154
"scheduledTakeoff": {
140
155
"type": "string",
141
156
"format": "datetime",
142
157
"description": "Scheduled wheels-off time -- the 'off' time. Explicit UTC offset, no fractional seconds."
143
158
},
144
159
"actualGateArrival": {
145
160
"type": "string",
146
161
"format": "datetime",
147
162
"description": "Actual time the aircraft reached the gate or parking position -- the 'in' time. Explicit UTC offset, no fractional seconds."
148
163
},
149
164
"icaoTypeDesignator": {
150
165
"type": "string",
151
166
"maxLength": 8,
152
167
"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."
153
168
},
154
169
"actualGateDeparture": {
155
170
"type": "string",
156
171
"format": "datetime",
157
172
"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."
158
173
},
159
174
"scheduledGateArrival": {
160
175
"type": "string",
161
176
"format": "datetime",
162
177
"description": "Scheduled time the aircraft reached the gate or parking position -- the 'in' time. Explicit UTC offset, no fractional seconds."
163
178
},
164
179
"marketingFlightNumber": {
165
180
"type": "string",
166
181
"maxLength": 16,
167
182
"description": "Flight number under which the flight was sold, when it differs from 'flightNumber'. A string, for the same reasons."
168
183
},
169
184
"scheduledGateDeparture": {
170
185
"type": "string",
171
186
"format": "datetime",
172
187
"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."
173
188
}
174
189
}
175
190
},
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."
191
+
"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 scheduled flights write 'date', 'operator', and 'flightNumber' consistently; for general aviation, state and military flying write 'icao24' and an actual departure time, and write 'callsign' verbatim wherever a source supplies one. There is deliberately no global flight identifier, because no authority exists to issue one. The record is intended to describe any kind of flying, and accommodates scheduled airline service, cargo, charter, business aviation, air ambulance, law enforcement, government, military and flight training operations alongside general aviation -- 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."
177
192
}
178
193
},
179
194
"$type": "com.atproto.lexicon.schema",
180
195
"lexicon": 1
181
196
}