Summary
from_geojson() cannot produce a CoT with an explicit <marti archive="false">. The property that
controls it, feature.properties.marti_archive, is read with truthy checks in three places instead of
!== undefined, so false is indistinguishable from "not set" and the attribute is silently omitted.
// lib/parser/from_geojson.ts:103-113
if (feature.properties.dest || feature.properties.marti_archive) {
cot.event.detail.marti = {};
if (feature.properties.marti_archive) {
cot.event.detail.marti._attributes = { archive: true };
}
if (feature.properties.dest) {
const dest = !Array.isArray(feature.properties.dest) ? [ feature.properties.dest ] : feature.properties.dest;
cot.event.detail.marti.dest = dest.map((dest) => {
return { _attributes: { ...dest } };
});
}
}
marti_archive: true works correctly. marti_archive: false produces byte-identical output to
marti_archive: undefined (no dest set): no <marti> element is emitted at all, so nothing about
archiving is asserted one way or the other on the wire.
Reproduction
import { from_geojson } from '@tak-ps/node-cot/lib/parser/from_geojson.js';
const cot = await from_geojson({
type: 'Feature',
properties: { marti_archive: false },
geometry: { type: 'Point', coordinates: [0, 0] },
});
console.log(cot.raw.event.detail.marti); // undefined - expected { _attributes: { archive: false } }
Why this matters
archive on <marti> is not cosmetic. On TAK Server, SubmissionService reads it per-message
(String archive = ((Element) marti).attributeValue("archive")) and sets a context flag that
RepositoryService checks before writing the message to the retention database. The message-level tag
takes precedence over the receiving input's own archive default — it's read by a listener added after
the input-level one, so it always overwrites. That means a client is fully able to say "don't retain this
specific CoT" independent of how the input is configured, provided it can actually put archive="false"
on the wire — which from_geojson() currently prevents.
Concretely: a consumer wants to mark certain generated CoTs as non-archival on an input whose default is
archive="true". There is no way to express that through this library. Every marti_archive value except
true produces the same (archived) result.
Fix
Two small changes, both backward compatible — true and undefined behave identically to today; only
false changes, from a no-op to doing what it already claims to do:
- if (feature.properties.dest || feature.properties.marti_archive) {
+ if (feature.properties.dest || feature.properties.marti_archive !== undefined) {
cot.event.detail.marti = {};
- if (feature.properties.marti_archive) {
- cot.event.detail.marti._attributes = { archive: true };
+ if (feature.properties.marti_archive !== undefined) {
+ cot.event.detail.marti._attributes = { archive: feature.properties.marti_archive };
}
The outer gate needs to widen too — otherwise marti_archive: false with no dest still fails to create
the <marti> element at all, since the || never becomes true.
I verified the underlying XML serialization has no issue with a false attribute value —
@tak-ps/xml-js produces <marti archive="false"/> correctly; the bug is purely in the truthy checks
above, not downstream.
Summary
from_geojson()cannot produce a CoT with an explicit<marti archive="false">. The property thatcontrols it,
feature.properties.marti_archive, is read with truthy checks in three places instead of!== undefined, sofalseis indistinguishable from "not set" and the attribute is silently omitted.marti_archive: trueworks correctly.marti_archive: falseproduces byte-identical output tomarti_archive: undefined(nodestset): no<marti>element is emitted at all, so nothing aboutarchiving is asserted one way or the other on the wire.
Reproduction
Why this matters
archiveon<marti>is not cosmetic. On TAK Server,SubmissionServicereads it per-message(
String archive = ((Element) marti).attributeValue("archive")) and sets a context flag thatRepositoryServicechecks before writing the message to the retention database. The message-level tagtakes precedence over the receiving input's own
archivedefault — it's read by a listener added afterthe input-level one, so it always overwrites. That means a client is fully able to say "don't retain this
specific CoT" independent of how the input is configured, provided it can actually put
archive="false"on the wire — which
from_geojson()currently prevents.Concretely: a consumer wants to mark certain generated CoTs as non-archival on an input whose default is
archive="true". There is no way to express that through this library. Everymarti_archivevalue excepttrueproduces the same (archived) result.Fix
Two small changes, both backward compatible —
trueandundefinedbehave identically to today; onlyfalsechanges, from a no-op to doing what it already claims to do:The outer gate needs to widen too — otherwise
marti_archive: falsewith nodeststill fails to createthe
<marti>element at all, since the||never becomes true.I verified the underlying XML serialization has no issue with a
falseattribute value —@tak-ps/xml-jsproduces<marti archive="false"/>correctly; the bug is purely in the truthy checksabove, not downstream.