@disclosureos/records 2.0.0-beta.0 → 2.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +9 -0
- package/dist/experimental/v2/index.d.ts +68487 -1
- package/dist/experimental/v2/index.js +2291 -16
- package/dist/experimental/v2/index.js.map +1 -1
- package/package.json +7 -2
- package/schema/experimental/claim-history-0.2.0.schema.json +1929 -0
- package/schema/experimental/claim-history-0.3.0.schema.json +2274 -0
- package/schema/experimental/observation-context-0.1.0.schema.json +14056 -0
- package/schema/experimental/research-entities-0.1.0.schema.json +7436 -0
|
@@ -126,9 +126,9 @@ function parsePrimitiveRecord(input) {
|
|
|
126
126
|
unchecked.add(ref2);
|
|
127
127
|
continue;
|
|
128
128
|
}
|
|
129
|
-
const
|
|
130
|
-
if (!
|
|
131
|
-
else if (
|
|
129
|
+
const target3 = assertions.get(ref2.slice("assertion:".length));
|
|
130
|
+
if (!target3) issues.push({ code: "REF.LOCAL_RESOLUTION", stage: "semantic", pointer: `/${field}/sourceRefs/${index}`, message: "Local assertion does not exist." });
|
|
131
|
+
else if (target3.field !== field) issues.push({ code: "REF.FIELD_MISMATCH", stage: "semantic", pointer: `/${field}/sourceRefs/${index}`, message: "Assertion concerns a different field." });
|
|
132
132
|
}
|
|
133
133
|
const selection = value.selection;
|
|
134
134
|
if (!selection) continue;
|
|
@@ -141,9 +141,9 @@ function parsePrimitiveRecord(input) {
|
|
|
141
141
|
for (const [index, ref2] of selection.consideredAssertionRefs.entries()) {
|
|
142
142
|
if (refs.has(ref2)) issues.push({ code: "REF.UNIQUE_ID", stage: "semantic", pointer: `${path}/consideredAssertionRefs/${index}`, message: "Considered assertion is repeated." });
|
|
143
143
|
refs.add(ref2);
|
|
144
|
-
const
|
|
145
|
-
if (!
|
|
146
|
-
else if (
|
|
144
|
+
const target3 = assertions.get(ref2.slice("assertion:".length));
|
|
145
|
+
if (!target3) issues.push({ code: "REF.LOCAL_RESOLUTION", stage: "semantic", pointer: `${path}/consideredAssertionRefs/${index}`, message: "Considered assertion does not exist." });
|
|
146
|
+
else if (target3.field !== field) issues.push({ code: "REF.FIELD_MISMATCH", stage: "semantic", pointer: `${path}/consideredAssertionRefs/${index}`, message: "Considered assertion concerns a different field." });
|
|
147
147
|
}
|
|
148
148
|
const selected = assertions.get(selection.assertionRef.slice("assertion:".length));
|
|
149
149
|
if (!selected) issues.push({ code: "REF.LOCAL_RESOLUTION", stage: "semantic", pointer: `${path}/assertionRef`, message: "Selected assertion does not exist." });
|
|
@@ -383,9 +383,9 @@ function parseExperimentalObservation(input) {
|
|
|
383
383
|
resolve(value.assertionRef, `${selectionPath}/assertionRef`, owner);
|
|
384
384
|
if (!value.consideredAssertionRefs.includes(value.assertionRef)) problem("SELECTION.INPUTS", `${selectionPath}/assertionRef`, "Selected assertion must be among considered inputs.");
|
|
385
385
|
if (!refs.includes(value.assertionRef)) problem("SELECTION.SOURCE_REF", `${path}/sourceRefs`, "Field must cite the selected assertion.");
|
|
386
|
-
const
|
|
387
|
-
if (
|
|
388
|
-
else if (
|
|
386
|
+
const target3 = assertions.get(key(value.assertionRef));
|
|
387
|
+
if (target3 && !matchesField(value.assertionRef, field, measurementId)) problem("REF.FIELD_MISMATCH", `${selectionPath}/assertionRef`, "Selected assertion concerns a different field or measurement.");
|
|
388
|
+
else if (target3 && JSON.stringify(target3.value) !== JSON.stringify(selectedValue)) problem("SELECTION.VALUE_MISMATCH", `${path}/value`, "Selection must copy the cited assertion value exactly; processing is declared separately.");
|
|
389
389
|
}
|
|
390
390
|
instant(data.createdAt, "/createdAt");
|
|
391
391
|
instant(data.updatedAt, "/updatedAt");
|
|
@@ -457,10 +457,10 @@ function parseExperimentalObservation(input) {
|
|
|
457
457
|
}
|
|
458
458
|
if (queue.length !== graph.size) problem("PROCESS.CYCLE", "/processing", "Local processing/provenance dependencies contain a cycle.");
|
|
459
459
|
const checks = { structural: "passed", semantic: issues.length ? "failed" : "passed", profile: "not_checked", external: "not_checked" };
|
|
460
|
-
const uncheckedRefs = [...sources.keys()].map((
|
|
461
|
-
[...products.keys()].map((
|
|
462
|
-
[...methods.keys()].map((
|
|
463
|
-
[...frames.keys()].map((
|
|
460
|
+
const uncheckedRefs = [...sources.keys()].map((id7) => `source:${id7}`).concat(
|
|
461
|
+
[...products.keys()].map((id7) => `product:${id7}`),
|
|
462
|
+
[...methods.keys()].map((id7) => `method:${id7}`),
|
|
463
|
+
[...frames.keys()].map((id7) => `frame:${id7}`)
|
|
464
464
|
);
|
|
465
465
|
return issues.length ? { success: false, issues, checks, uncheckedRefs } : { success: true, data, issues, checks, uncheckedRefs };
|
|
466
466
|
}
|
|
@@ -561,9 +561,9 @@ function parseExperimentalClaimHistory(input) {
|
|
|
561
561
|
if (!available.has(ref2)) problem("REF.LOCAL_RESOLUTION", path, `Undeclared local reference: ${ref2}`);
|
|
562
562
|
else if (owner && claims.has(ref2)) graph.get(owner)?.add(ref2);
|
|
563
563
|
}
|
|
564
|
-
function refs(
|
|
564
|
+
function refs(values3, path, owner) {
|
|
565
565
|
const seen = /* @__PURE__ */ new Set();
|
|
566
|
-
for (const [i, ref2] of
|
|
566
|
+
for (const [i, ref2] of values3.entries()) {
|
|
567
567
|
if (seen.has(ref2)) problem("REF.UNIQUE_ID", `${path}/${i}`, "Reference is repeated.");
|
|
568
568
|
seen.add(ref2);
|
|
569
569
|
resolve(ref2, `${path}/${i}`, owner);
|
|
@@ -639,7 +639,2282 @@ function compareUtcInstants(left, right) {
|
|
|
639
639
|
const result = comparePoints({ kind: "instant", value: left}, { kind: "instant", value: right});
|
|
640
640
|
return result === -1 || result === 0 || result === 1 ? result : void 0;
|
|
641
641
|
}
|
|
642
|
+
var SourceTypeSchema = z.enum([
|
|
643
|
+
"foia",
|
|
644
|
+
"official_report",
|
|
645
|
+
"official_statement",
|
|
646
|
+
"congressional_testimony",
|
|
647
|
+
"congressional_report",
|
|
648
|
+
"military_document",
|
|
649
|
+
"intelligence_document",
|
|
650
|
+
"whistleblower",
|
|
651
|
+
"firsthand_witness",
|
|
652
|
+
"secondhand_account",
|
|
653
|
+
"news_article",
|
|
654
|
+
"documentary",
|
|
655
|
+
"interview",
|
|
656
|
+
"book",
|
|
657
|
+
"academic_paper",
|
|
658
|
+
"investigation_report",
|
|
659
|
+
"database_entry",
|
|
660
|
+
"social_media",
|
|
661
|
+
"website",
|
|
662
|
+
"other"
|
|
663
|
+
]).describe("Kind of source backing an observation (document, testimony, media, etc.).");
|
|
664
|
+
var SourceCredibilitySchema = z.enum(["official", "verified", "credible", "unverified", "questionable", "disputed", "unknown"]).describe("Trust tier of a source \u2014 an orthogonal axis to confidence and temporal certainty.");
|
|
642
665
|
|
|
643
|
-
|
|
666
|
+
// src/source/reference.ts
|
|
667
|
+
var SourceReferenceSchema = z.object({
|
|
668
|
+
sourceId: z.string().describe("Stable unique identifier for this source."),
|
|
669
|
+
type: SourceTypeSchema,
|
|
670
|
+
title: z.string().describe("Title of the source document, article, or material."),
|
|
671
|
+
author: z.string().optional().describe("Author of the source material."),
|
|
672
|
+
organization: z.string().optional().describe("Organization that produced or published the source."),
|
|
673
|
+
date: z.string().optional().describe("Publication or creation date of the source (ISO date)."),
|
|
674
|
+
url: z.string().optional().describe("Link to the source material."),
|
|
675
|
+
archiveUrl: z.string().optional().describe("Archived copy of the source (e.g. Wayback Machine), in case the original disappears."),
|
|
676
|
+
reference: z.string().optional().describe("Citation locator within the source (e.g. page number, document section)."),
|
|
677
|
+
credibility: SourceCredibilitySchema,
|
|
678
|
+
isPrimarySource: z.boolean().optional().describe("Whether this is a primary source (original document/recording) rather than secondary reporting."),
|
|
679
|
+
classificationLevel: z.string().optional().describe("Government classification of the source, if it was ever classified."),
|
|
680
|
+
notes: z.string().optional().describe("Free-text context about the source.")
|
|
681
|
+
}).meta({ id: "SourceReference" }).describe("A citation/source backing an observation, with its credibility tier.");
|
|
682
|
+
var ConfidenceLevelSchema = z.enum(["very_high", "high", "moderate", "low", "very_low", "unassessed"]).describe("Qualitative confidence magnitude.");
|
|
683
|
+
ConfidenceLevelSchema.options;
|
|
684
|
+
|
|
685
|
+
// src/observation/domains.ts
|
|
686
|
+
var ObjectShapeSchema = z.enum([
|
|
687
|
+
"sphere",
|
|
688
|
+
"orb",
|
|
689
|
+
"disc",
|
|
690
|
+
"saucer",
|
|
691
|
+
"oval",
|
|
692
|
+
"egg",
|
|
693
|
+
"cylinder",
|
|
694
|
+
"cigar",
|
|
695
|
+
"tic_tac",
|
|
696
|
+
"triangle",
|
|
697
|
+
"delta",
|
|
698
|
+
"boomerang",
|
|
699
|
+
"chevron",
|
|
700
|
+
"diamond",
|
|
701
|
+
"rectangle",
|
|
702
|
+
"square",
|
|
703
|
+
"cube",
|
|
704
|
+
"cross",
|
|
705
|
+
"star",
|
|
706
|
+
"amorphous",
|
|
707
|
+
"changing",
|
|
708
|
+
"light_only",
|
|
709
|
+
"other",
|
|
710
|
+
"unknown"
|
|
711
|
+
]).describe("Reported shape of the observed object.");
|
|
712
|
+
z.object({
|
|
713
|
+
shape: ObjectShapeSchema.optional(),
|
|
714
|
+
size: z.string().optional().describe('Apparent size as reported (e.g. "size of a commercial airliner").'),
|
|
715
|
+
sizeMeters: z.number().optional().describe("Estimated size of the object, in meters."),
|
|
716
|
+
color: z.string().optional().describe("Primary color of the object as reported."),
|
|
717
|
+
secondaryColors: z.array(z.string()).optional().describe("Additional colors observed on the object."),
|
|
718
|
+
luminosity: z.string().optional().describe('Light emission as reported (e.g. "glowing white", "self-luminous", "no lights").'),
|
|
719
|
+
sound: z.string().optional().describe('Whether and what sound the object produced (e.g. "silent", "humming").'),
|
|
720
|
+
soundDescription: z.string().optional().describe("Fuller free-text description of any sound."),
|
|
721
|
+
surfaceDetails: z.string().optional().describe('Visible surface features (e.g. "metallic, seamless, no rivets or seams").'),
|
|
722
|
+
numberObserved: z.number().optional().describe("How many objects were observed."),
|
|
723
|
+
formation: z.string().optional().describe('Geometric arrangement when multiple objects were observed (e.g. "triangular formation").'),
|
|
724
|
+
structuralFeatures: z.array(z.string()).optional().describe('Distinct structural elements reported (e.g. "dome", "portholes", "appendages").')
|
|
725
|
+
}).meta({ id: "ObjectCharacteristics" }).describe("Physical description of the observed object(s).");
|
|
726
|
+
var ManeuverTypeSchema = z.enum([
|
|
727
|
+
"hover",
|
|
728
|
+
"instant_acceleration",
|
|
729
|
+
"instant_stop",
|
|
730
|
+
"right_angle_turn",
|
|
731
|
+
"zigzag",
|
|
732
|
+
"pendulum",
|
|
733
|
+
"split",
|
|
734
|
+
"merge",
|
|
735
|
+
"disappear",
|
|
736
|
+
"appear",
|
|
737
|
+
"transmedium_entry",
|
|
738
|
+
"transmedium_exit",
|
|
739
|
+
"vertical_ascent",
|
|
740
|
+
"vertical_descent",
|
|
741
|
+
"rotation",
|
|
742
|
+
"wobble",
|
|
743
|
+
"other"
|
|
744
|
+
]).describe("A distinctive movement/maneuver exhibited by the object.");
|
|
745
|
+
z.object({
|
|
746
|
+
speed: z.string().optional().describe('Speed as reported (e.g. "faster than any known aircraft").'),
|
|
747
|
+
speedKmh: z.number().optional().describe("Estimated speed, in kilometers per hour."),
|
|
748
|
+
altitude: z.string().optional().describe('Altitude as reported (e.g. "treetop level", "very high").'),
|
|
749
|
+
altitudeMeters: z.number().optional().describe("Estimated altitude of the object, in meters."),
|
|
750
|
+
heading: z.number().optional().describe("Direction of travel, in compass degrees (0\u2013360)."),
|
|
751
|
+
flightPath: z.string().optional().describe('Narrative of the object\u2019s path through the encounter (e.g. "descended from 80,000 ft to sea level").'),
|
|
752
|
+
maneuvers: z.array(ManeuverTypeSchema).optional().describe("Distinctive maneuvers exhibited, from the typed vocabulary."),
|
|
753
|
+
maneuverDescriptions: z.array(z.string()).optional().describe("Free-text descriptions elaborating on the typed maneuvers."),
|
|
754
|
+
radarData: z.boolean().optional().describe("Whether the movement was tracked on radar."),
|
|
755
|
+
infraredSignature: z.boolean().optional().describe("Whether the object showed an infrared signature."),
|
|
756
|
+
trajectory: z.string().optional().describe('Overall trajectory summary (e.g. "erratic", "straight and level").')
|
|
757
|
+
}).meta({ id: "Movement" }).describe("How the object moved \u2014 kinematics and notable maneuvers.");
|
|
758
|
+
z.object({
|
|
759
|
+
investigatingBody: z.string().optional().describe('Primary organization that investigated (e.g. "AARO", "Project Blue Book").'),
|
|
760
|
+
investigatingBodies: z.array(z.string()).optional().describe("All organizations that investigated, when more than one."),
|
|
761
|
+
caseNumber: z.string().optional().describe("Case or file number assigned by the investigating body."),
|
|
762
|
+
investigationDate: z.string().optional().describe("When the investigation was conducted (ISO date)."),
|
|
763
|
+
conclusion: z.string().optional().describe('Official conclusion reached (e.g. "unidentified", "weather balloon").'),
|
|
764
|
+
confidence: ConfidenceLevelSchema.optional(),
|
|
765
|
+
methodologies: z.array(z.string()).optional().describe('Methods used (e.g. "witness interviews", "radar data analysis").'),
|
|
766
|
+
findings: z.string().optional().describe("Summary of what the investigation found."),
|
|
767
|
+
recommendations: z.string().optional().describe("Recommendations issued by the investigation.")
|
|
768
|
+
}).meta({ id: "Investigation" }).describe("Official/independent investigation of the observation.");
|
|
769
|
+
z.object({
|
|
770
|
+
count: z.number().optional().describe("Total number of witnesses."),
|
|
771
|
+
categories: z.array(z.string()).optional().describe('Kinds of witnesses present (e.g. "military pilots", "radar operators", "civilians").'),
|
|
772
|
+
militaryWitnesses: z.boolean().optional().describe("Whether any witnesses were military personnel."),
|
|
773
|
+
aviationWitnesses: z.boolean().optional().describe("Whether any witnesses were pilots or aviation professionals."),
|
|
774
|
+
multipleIndependent: z.boolean().optional().describe("Whether independent witnesses observed from separate vantage points."),
|
|
775
|
+
professionalObservers: z.boolean().optional().describe("Whether any witnesses were trained observers (pilots, astronomers, military)."),
|
|
776
|
+
descriptions: z.array(z.string()).optional().describe("Brief summaries of individual witness accounts.")
|
|
777
|
+
}).meta({ id: "Witnesses" }).describe("Aggregate summary of who witnessed the observation.");
|
|
778
|
+
z.object({
|
|
779
|
+
officialResponse: z.string().optional().describe("How officials responded (statements, denials, acknowledgments)."),
|
|
780
|
+
mediaAttention: z.boolean().optional().describe("Whether the observation received media coverage."),
|
|
781
|
+
publicImpact: z.string().optional().describe("Effect on public awareness or discourse."),
|
|
782
|
+
policyImpact: z.string().optional().describe("Policy consequences (e.g. hearings, legislation, reporting-process changes)."),
|
|
783
|
+
militaryResponse: z.string().optional().describe("Military actions taken (e.g. intercept scrambled, alert status changed)."),
|
|
784
|
+
coverUpAlleged: z.boolean().optional().describe("Whether suppression or concealment of the event has been alleged.")
|
|
785
|
+
}).meta({ id: "ResponseImpact" }).describe("Official, media, and public response to the observation.");
|
|
786
|
+
z.object({
|
|
787
|
+
weather: z.string().optional().describe('General weather conditions (e.g. "clear", "overcast").'),
|
|
788
|
+
visibility: z.string().optional().describe('Visibility conditions (e.g. "unlimited", "10 miles", "hazy").'),
|
|
789
|
+
cloudCover: z.string().optional().describe('Cloud cover description (e.g. "scattered at 5,000 ft").'),
|
|
790
|
+
windSpeed: z.string().optional().describe("Wind conditions as reported."),
|
|
791
|
+
temperature: z.number().optional().describe("Air temperature, in degrees Celsius."),
|
|
792
|
+
humidity: z.number().optional().describe("Relative humidity, as a percentage (0\u2013100)."),
|
|
793
|
+
celestialConditions: z.string().optional().describe("Sky conditions relevant to identification (e.g. visible planets, meteor showers, satellites)."),
|
|
794
|
+
moonPhase: z.string().optional().describe("Moon phase description at the time of observation."),
|
|
795
|
+
precipitation: z.string().optional().describe("Precipitation at the time of observation, if any.")
|
|
796
|
+
}).meta({ id: "Environment" }).describe("Environmental and weather conditions at the time of observation.");
|
|
797
|
+
var RelationKindSchema = z.enum([
|
|
798
|
+
"corroborates",
|
|
799
|
+
"contradicts",
|
|
800
|
+
"duplicate_of",
|
|
801
|
+
"same_object",
|
|
802
|
+
"supersedes",
|
|
803
|
+
"superseded_by",
|
|
804
|
+
"re_analysis_of",
|
|
805
|
+
"part_of"
|
|
806
|
+
]).describe("How one observation relates to another (typed edge vocabulary).");
|
|
807
|
+
var RelationEdgeSchema = z.object({
|
|
808
|
+
kind: RelationKindSchema,
|
|
809
|
+
targetId: z.string().min(1).describe("The `Observation.id` this edge points at."),
|
|
810
|
+
note: z.string().optional().describe("Free-text context for why the link exists.")
|
|
811
|
+
}).meta({ id: "RelationEdge" }).describe("A typed link from this observation to another.");
|
|
812
|
+
z.object({
|
|
813
|
+
/** Typed edges to other observations — the standardized way to link records. */
|
|
814
|
+
edges: z.array(RelationEdgeSchema).optional().describe("Typed edges to other observations \u2014 the standardized way to link records."),
|
|
815
|
+
/** Named grouping into a flap (a localized cluster of sightings). */
|
|
816
|
+
flap: z.string().optional().describe("Named grouping into a flap (a localized cluster of sightings)."),
|
|
817
|
+
/** Named grouping into a wave (a broad temporal surge of sightings). */
|
|
818
|
+
wave: z.string().optional().describe("Named grouping into a wave (a broad temporal surge of sightings)."),
|
|
819
|
+
/** Named grouping into an ad-hoc cluster. */
|
|
820
|
+
cluster: z.string().optional().describe("Named grouping into an ad-hoc cluster."),
|
|
821
|
+
/** @deprecated Use typed `edges` with `kind: 'corroborates' | 'same_object' | …`. */
|
|
822
|
+
relatedObservationIds: z.array(z.string()).optional().describe('Deprecated \u2014 use typed `edges` with `kind: "corroborates" | "same_object" | \u2026`.'),
|
|
823
|
+
/** @deprecated Use typed `edges` with `kind: 'supersedes' | 're_analysis_of' | …`. */
|
|
824
|
+
precedingEvents: z.array(z.string()).optional().describe('Deprecated \u2014 use typed `edges` with `kind: "supersedes" | "re_analysis_of" | \u2026`.'),
|
|
825
|
+
/** @deprecated Use typed `edges`. */
|
|
826
|
+
followingEvents: z.array(z.string()).optional().describe("Deprecated \u2014 use typed `edges`.")
|
|
827
|
+
}).meta({ id: "Relations" }).describe("Typed links to related observations, plus flap/wave/cluster groupings.");
|
|
828
|
+
z.object({
|
|
829
|
+
aircraftType: z.string().optional().describe('Type of aircraft involved (e.g. "F/A-18F Super Hornet").'),
|
|
830
|
+
aircraftDesignation: z.string().optional().describe("Military designation or tail number of the aircraft."),
|
|
831
|
+
squadron: z.string().optional().describe("Squadron or unit the aircraft belonged to."),
|
|
832
|
+
flightMission: z.string().optional().describe('Mission being flown at the time (e.g. "training exercise", "combat air patrol").'),
|
|
833
|
+
altitude: z.number().optional().describe("Aircraft altitude during the encounter, in meters."),
|
|
834
|
+
speed: z.number().optional().describe("Aircraft speed during the encounter, in kilometers per hour."),
|
|
835
|
+
heading: z.number().optional().describe("Aircraft heading during the encounter, in compass degrees (0\u2013360)."),
|
|
836
|
+
radarContact: z.boolean().optional().describe("Whether the aircraft\u2019s radar held contact with the object."),
|
|
837
|
+
weaponsSystemEngaged: z.boolean().optional().describe("Whether a weapons system locked onto or tracked the object."),
|
|
838
|
+
interceptAttempted: z.boolean().optional().describe("Whether an intercept of the object was attempted.")
|
|
839
|
+
}).meta({ id: "Aviation" }).describe("Aviation context when the observation involved aircraft.");
|
|
840
|
+
z.object({
|
|
841
|
+
primarySource: SourceReferenceSchema.optional(),
|
|
842
|
+
sources: z.array(SourceReferenceSchema).optional(),
|
|
843
|
+
originalClassification: z.string().optional().describe('Original government classification of the source material (e.g. "SECRET").'),
|
|
844
|
+
declassificationDate: z.string().optional().describe("When the source material was declassified (ISO date)."),
|
|
845
|
+
foiaRequestId: z.string().optional().describe("FOIA request number that produced the source material."),
|
|
846
|
+
archiveLocation: z.string().optional().describe("Physical or digital archive where the source material resides.")
|
|
847
|
+
}).meta({ id: "SourceData" }).describe(
|
|
848
|
+
"Where the observation data came from. Forensic custody/authenticity now lives in the optional `Observation.provenance` slot (@disclosureos/records/extensions/provenance)."
|
|
849
|
+
);
|
|
850
|
+
var CoordinatePrecisionSchema = z.enum(["exact", "address", "locality", "region", "approximate", "unknown"]).describe("How precisely a coordinate is known.");
|
|
851
|
+
var SiteTypeSchema = z.enum([
|
|
852
|
+
"military_air_base",
|
|
853
|
+
"military_naval_base",
|
|
854
|
+
"military_army_base",
|
|
855
|
+
"military_missile_site",
|
|
856
|
+
"military_radar_station",
|
|
857
|
+
"military_research_facility",
|
|
858
|
+
"military_training_area",
|
|
859
|
+
"military_other",
|
|
860
|
+
"nuclear_power_plant",
|
|
861
|
+
"nuclear_weapons_storage",
|
|
862
|
+
"nuclear_research_facility",
|
|
863
|
+
"nuclear_waste_storage",
|
|
864
|
+
"nuclear_other",
|
|
865
|
+
"civilian_airport",
|
|
866
|
+
"private_airfield",
|
|
867
|
+
"heliport",
|
|
868
|
+
"seaport",
|
|
869
|
+
"offshore_platform",
|
|
870
|
+
"naval_vessel",
|
|
871
|
+
"government_facility",
|
|
872
|
+
"embassy",
|
|
873
|
+
"intelligence_facility",
|
|
874
|
+
"power_plant",
|
|
875
|
+
"dam",
|
|
876
|
+
"telecommunications",
|
|
877
|
+
"water_treatment",
|
|
878
|
+
"research_facility",
|
|
879
|
+
"test_range",
|
|
880
|
+
"space_station",
|
|
881
|
+
"archaeological_site",
|
|
882
|
+
"volcano",
|
|
883
|
+
"command_center",
|
|
884
|
+
"residential",
|
|
885
|
+
"commercial",
|
|
886
|
+
"industrial",
|
|
887
|
+
"agricultural",
|
|
888
|
+
"wilderness",
|
|
889
|
+
"ocean",
|
|
890
|
+
"lake",
|
|
891
|
+
"mountain",
|
|
892
|
+
"desert",
|
|
893
|
+
"forest",
|
|
894
|
+
"urban",
|
|
895
|
+
"suburban",
|
|
896
|
+
"rural",
|
|
897
|
+
"other",
|
|
898
|
+
"unknown"
|
|
899
|
+
]).describe("Category of site at or near the observation location (military, nuclear, civilian, natural, etc.).");
|
|
900
|
+
var TerrainTypeSchema = z.enum([
|
|
901
|
+
"ocean",
|
|
902
|
+
"coastal",
|
|
903
|
+
"lake",
|
|
904
|
+
"river",
|
|
905
|
+
"wetland",
|
|
906
|
+
"plains",
|
|
907
|
+
"hills",
|
|
908
|
+
"mountains",
|
|
909
|
+
"desert",
|
|
910
|
+
"forest",
|
|
911
|
+
"jungle",
|
|
912
|
+
"tundra",
|
|
913
|
+
"arctic",
|
|
914
|
+
"urban",
|
|
915
|
+
"suburban",
|
|
916
|
+
"rural",
|
|
917
|
+
"underground",
|
|
918
|
+
"underwater",
|
|
919
|
+
"airborne",
|
|
920
|
+
"space",
|
|
921
|
+
"unknown"
|
|
922
|
+
]).describe("Physical terrain at the observation location.");
|
|
923
|
+
var AirspaceClassSchema = z.enum([
|
|
924
|
+
"A",
|
|
925
|
+
"B",
|
|
926
|
+
"C",
|
|
927
|
+
"D",
|
|
928
|
+
"E",
|
|
929
|
+
"G",
|
|
930
|
+
"restricted",
|
|
931
|
+
"prohibited",
|
|
932
|
+
"warning",
|
|
933
|
+
"moa",
|
|
934
|
+
"alert",
|
|
935
|
+
"cfa",
|
|
936
|
+
"national_security",
|
|
937
|
+
"tfr",
|
|
938
|
+
"international",
|
|
939
|
+
"unknown"
|
|
940
|
+
]).describe("Airspace classification over the location (ICAO classes plus special-use airspace).");
|
|
941
|
+
var LocationSensitivitySchema = z.enum(["critical", "high", "moderate", "standard", "none"]).describe("How sensitive the location is (e.g. proximity to critical infrastructure).");
|
|
942
|
+
var ProximitySiteSchema = z.object({
|
|
943
|
+
siteType: SiteTypeSchema,
|
|
944
|
+
siteName: z.string().optional().describe('Name of the nearby site (e.g. "Naval Air Station Oceana").'),
|
|
945
|
+
distanceKm: z.number().describe("Distance from the observation location, in kilometers."),
|
|
946
|
+
bearing: z.number().optional().describe("Compass bearing from the observation location to the site, in degrees (0\u2013360).")
|
|
947
|
+
}).meta({ id: "ProximitySite" }).describe("A site of interest near the observation and its distance/bearing.");
|
|
948
|
+
z.object({
|
|
949
|
+
id: z.string().min(1).describe("Stable unique identifier for this location."),
|
|
950
|
+
name: z.string().min(1).describe('Human-readable place name (e.g. "Off the coast of San Diego").'),
|
|
951
|
+
country: z.string().min(1).describe("Country where the observation occurred."),
|
|
952
|
+
countryCode: z.string().optional().describe('ISO 3166-1 alpha-2 country code (e.g. "US").'),
|
|
953
|
+
region: z.string().optional().describe("State, province, or administrative region."),
|
|
954
|
+
city: z.string().optional().describe("Nearest city or town."),
|
|
955
|
+
address: z.string().optional().describe("Street address, when the location is that precise."),
|
|
956
|
+
longitude: z.number().min(-180).max(180).describe("Longitude in decimal degrees (WGS 84)."),
|
|
957
|
+
latitude: z.number().min(-90).max(90).describe("Latitude in decimal degrees (WGS 84)."),
|
|
958
|
+
coordinatePrecision: CoordinatePrecisionSchema.optional(),
|
|
959
|
+
coordinatePrecisionMeters: z.number().optional().describe("Numeric uncertainty radius of the coordinates, in meters."),
|
|
960
|
+
coordinatesApproximate: z.boolean().optional().describe("Whether the coordinates are an approximation rather than a measured fix."),
|
|
961
|
+
elevationMeters: z.number().optional().describe("Ground elevation at the location, in meters above sea level."),
|
|
962
|
+
elevationSource: z.enum(["gps", "map", "estimated", "unknown"]).optional().describe("How the elevation value was obtained."),
|
|
963
|
+
siteType: SiteTypeSchema,
|
|
964
|
+
secondarySiteTypes: z.array(SiteTypeSchema).optional().describe("Additional site categories that also apply to the location."),
|
|
965
|
+
terrain: TerrainTypeSchema.optional(),
|
|
966
|
+
airspaceClass: AirspaceClassSchema.optional(),
|
|
967
|
+
locationSensitivity: LocationSensitivitySchema.optional(),
|
|
968
|
+
proximitySites: z.array(ProximitySiteSchema).optional().describe("Named sites of interest near the observation, with distance and bearing."),
|
|
969
|
+
nearestMilitaryKm: z.number().optional().describe("Distance to the nearest military installation, in kilometers."),
|
|
970
|
+
nearestNuclearKm: z.number().optional().describe("Distance to the nearest nuclear facility, in kilometers."),
|
|
971
|
+
nearestAirportKm: z.number().optional().describe("Distance to the nearest airport, in kilometers."),
|
|
972
|
+
waterDepthMeters: z.number().optional().describe("Water depth at the location for maritime observations, in meters."),
|
|
973
|
+
vesselName: z.string().optional().describe("Name of the vessel the observer was aboard, if any."),
|
|
974
|
+
vesselType: z.string().optional().describe('Type of vessel (e.g. "aircraft carrier", "fishing trawler").'),
|
|
975
|
+
aircraftType: z.string().optional().describe("Type of aircraft the observer was aboard, if any."),
|
|
976
|
+
aircraftCallsign: z.string().optional().describe("Callsign of the observer\u2019s aircraft."),
|
|
977
|
+
flightNumber: z.string().optional().describe("Commercial flight number, for airline observations."),
|
|
978
|
+
observerAltitudeMeters: z.number().optional().describe("Altitude of an airborne observer at the time of observation, in meters.")
|
|
979
|
+
}).meta({ id: "LocationData" }).describe("Where an observation occurred \u2014 identity, coordinates, site classification, and proximity context.");
|
|
980
|
+
var DetectionMethodSchema = z.enum([
|
|
981
|
+
"radar_primary",
|
|
982
|
+
"radar_secondary",
|
|
983
|
+
"radar_doppler",
|
|
984
|
+
"radar_phased_array",
|
|
985
|
+
"infrared_flir",
|
|
986
|
+
"infrared_other",
|
|
987
|
+
"electro_optical",
|
|
988
|
+
"visual_camera",
|
|
989
|
+
"satellite_imagery",
|
|
990
|
+
"sonar_active",
|
|
991
|
+
"sonar_passive",
|
|
992
|
+
"electromagnetic",
|
|
993
|
+
"radiation_detector",
|
|
994
|
+
"magnetometer",
|
|
995
|
+
"gravimeter",
|
|
996
|
+
"acoustic",
|
|
997
|
+
"seismic",
|
|
998
|
+
"lidar",
|
|
999
|
+
"spectroscopic",
|
|
1000
|
+
"radio_frequency",
|
|
1001
|
+
"particle",
|
|
1002
|
+
"gnss",
|
|
1003
|
+
"time_reference",
|
|
1004
|
+
"chemical",
|
|
1005
|
+
"inertial",
|
|
1006
|
+
"physiological",
|
|
1007
|
+
"pressure",
|
|
1008
|
+
"multiple",
|
|
1009
|
+
"other",
|
|
1010
|
+
"unknown"
|
|
1011
|
+
]).describe("How a sensor detected the object.");
|
|
1012
|
+
var SensorTypeSchema = z.enum([
|
|
1013
|
+
"military_radar",
|
|
1014
|
+
"civilian_radar",
|
|
1015
|
+
"airborne_radar",
|
|
1016
|
+
"shipborne_radar",
|
|
1017
|
+
"ground_radar",
|
|
1018
|
+
"flir",
|
|
1019
|
+
"eo_sensor",
|
|
1020
|
+
"satellite",
|
|
1021
|
+
"sonar",
|
|
1022
|
+
"electromagnetic_sensor",
|
|
1023
|
+
"radiation_sensor",
|
|
1024
|
+
"civilian_camera",
|
|
1025
|
+
"security_camera",
|
|
1026
|
+
"dashcam",
|
|
1027
|
+
"phone_camera",
|
|
1028
|
+
"infrasonic_sensor",
|
|
1029
|
+
"ultrasonic_sensor",
|
|
1030
|
+
"adsb_receiver",
|
|
1031
|
+
"rf_spectrum_analyzer",
|
|
1032
|
+
"passive_radar",
|
|
1033
|
+
"particle_detector",
|
|
1034
|
+
"atomic_clock",
|
|
1035
|
+
"gnss_receiver",
|
|
1036
|
+
"fluxgate_magnetometer",
|
|
1037
|
+
"air_quality_sensor",
|
|
1038
|
+
"barometer",
|
|
1039
|
+
"lightning_detector",
|
|
1040
|
+
"imu",
|
|
1041
|
+
"eeg",
|
|
1042
|
+
"gsr",
|
|
1043
|
+
"pulse_oximeter",
|
|
1044
|
+
"pupillometer",
|
|
1045
|
+
"hardware_rng",
|
|
1046
|
+
"other"
|
|
1047
|
+
]).describe("Class of sensor that produced a reading.");
|
|
1048
|
+
var SensorReadingSchema = z.object({
|
|
1049
|
+
id: z.string().min(1).describe('Stable id, addressable by a claim `evidenceRef` ("sensor:<id>").'),
|
|
1050
|
+
sensorType: SensorTypeSchema,
|
|
1051
|
+
detectionMethod: DetectionMethodSchema,
|
|
1052
|
+
sensorRef: z.string().optional().describe(
|
|
1053
|
+
'Reference to a published sensor-manifest entry ("<org-slug>:<sensor-id>", e.g. "eldaeon:dionysus-passive-radar") carrying the instrument\u2019s full spec, timing, and calibration provenance.'
|
|
1054
|
+
),
|
|
1055
|
+
platform: z.string().optional().describe('Platform carrying the sensor (e.g. "USS Princeton", "F/A-18F").'),
|
|
1056
|
+
operator: z.string().optional().describe("Person or unit operating the sensor."),
|
|
1057
|
+
timestamp: z.string().optional().describe("When the reading was recorded (ISO timestamp)."),
|
|
1058
|
+
duration: z.number().optional().describe("How long the sensor held contact, in seconds."),
|
|
1059
|
+
rawDataAvailable: z.boolean().optional().describe("Whether the raw sensor data still exists and is obtainable."),
|
|
1060
|
+
calibrated: z.boolean().optional().describe("Whether the sensor was calibrated at the time of the reading."),
|
|
1061
|
+
readings: z.record(z.string(), z.unknown()).optional().describe("Sensor-specific measured values, keyed by measurement name."),
|
|
1062
|
+
notes: z.string().optional().describe("Free-text context about the reading.")
|
|
1063
|
+
}).meta({ id: "SensorReading" }).describe("A single sensor reading and its provenance.");
|
|
1064
|
+
var SensorEvidenceDataSchema = z.object({
|
|
1065
|
+
sensors: z.array(SensorReadingSchema),
|
|
1066
|
+
multiSensorCorrelation: z.boolean().optional().describe("Whether independent sensors corroborated the same object."),
|
|
1067
|
+
dataRetentionStatus: z.enum(["available", "archived", "destroyed", "classified", "unknown"]).optional().describe("Current status of the underlying sensor data."),
|
|
1068
|
+
anomalies: z.array(z.string()).optional().describe('Anomalies in the sensor data itself (e.g. "jamming indications", "signal dropout").')
|
|
1069
|
+
}).meta({ id: "SensorEvidenceData" }).describe("Instrument-recorded evidence for an observation (radar, FLIR, EO, etc.).");
|
|
1070
|
+
var TimeOfDaySchema = z.enum([
|
|
1071
|
+
"astronomical_dawn",
|
|
1072
|
+
"nautical_dawn",
|
|
1073
|
+
"civil_dawn",
|
|
1074
|
+
"sunrise",
|
|
1075
|
+
"morning",
|
|
1076
|
+
"noon",
|
|
1077
|
+
"afternoon",
|
|
1078
|
+
"sunset",
|
|
1079
|
+
"civil_dusk",
|
|
1080
|
+
"nautical_dusk",
|
|
1081
|
+
"astronomical_dusk",
|
|
1082
|
+
"night",
|
|
1083
|
+
"unknown"
|
|
1084
|
+
]).describe("Twilight-aware time-of-day bucket for an observation.");
|
|
1085
|
+
|
|
1086
|
+
// src/experimental/v2/context-schema.ts
|
|
1087
|
+
var text4 = z.string().min(1).regex(/\S/);
|
|
1088
|
+
var id3 = z.string().regex(/^[A-Za-z0-9][A-Za-z0-9._-]*(?![\s\S])/);
|
|
1089
|
+
var sourceRef2 = z.string().regex(/^(source|product):[A-Za-z0-9][A-Za-z0-9._-]*(?![\s\S])/);
|
|
1090
|
+
var OBSERVATION_CONTEXT_SCHEMA_ID = "urn:disclosureos:experimental:observation-context:0.1.0";
|
|
1091
|
+
var DocumentSnapshotRefSchema = z.strictObject({
|
|
1092
|
+
documentId: id3.describe("ID inside the supplied document; not a URL."),
|
|
1093
|
+
schemaId: text4.describe("Exact document contract identity."),
|
|
1094
|
+
sha256: z.string().regex(/^[a-f0-9]{64}(?![\s\S])/).describe("SHA-256 of exact supplied document bytes.")
|
|
1095
|
+
});
|
|
1096
|
+
var ObservationSnapshotRefSchema = DocumentSnapshotRefSchema.extend({
|
|
1097
|
+
schemaId: z.literal(EXPERIMENTAL_OBSERVATION_SCHEMA_ID)
|
|
1098
|
+
});
|
|
1099
|
+
var provenance2 = SourceProvenanceSchema.extend({ sourceRef: sourceRef2 });
|
|
1100
|
+
function values(schema) {
|
|
1101
|
+
return z.array(
|
|
1102
|
+
z.strictObject({
|
|
1103
|
+
id: id3.describe(
|
|
1104
|
+
"Assertion identity within this entity, independent of array order."
|
|
1105
|
+
),
|
|
1106
|
+
content: z.union([
|
|
1107
|
+
z.strictObject({
|
|
1108
|
+
state: z.literal("known"),
|
|
1109
|
+
value: schema,
|
|
1110
|
+
provenance: provenance2,
|
|
1111
|
+
originalWording: text4.optional()
|
|
1112
|
+
}),
|
|
1113
|
+
z.strictObject({
|
|
1114
|
+
state: z.literal("approximate"),
|
|
1115
|
+
value: schema,
|
|
1116
|
+
precision: text4,
|
|
1117
|
+
provenance: provenance2,
|
|
1118
|
+
originalWording: text4.optional()
|
|
1119
|
+
}),
|
|
1120
|
+
z.strictObject({
|
|
1121
|
+
state: z.literal("unknown"),
|
|
1122
|
+
reason: z.enum(["not_recorded", "not_collected", "unavailable"])
|
|
1123
|
+
}),
|
|
1124
|
+
z.strictObject({ state: z.literal("redacted"), reason: text4 }),
|
|
1125
|
+
z.strictObject({
|
|
1126
|
+
state: z.literal("unmapped"),
|
|
1127
|
+
originalWording: text4,
|
|
1128
|
+
provenance: provenance2
|
|
1129
|
+
})
|
|
1130
|
+
])
|
|
1131
|
+
})
|
|
1132
|
+
).min(1).optional();
|
|
1133
|
+
}
|
|
1134
|
+
var strings = z.array(text4).min(1);
|
|
1135
|
+
var localTime = z.strictObject({
|
|
1136
|
+
clock: z.string().regex(/^([01][0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?$/),
|
|
1137
|
+
timezone: text4.optional(),
|
|
1138
|
+
utcOffset: z.string().regex(/^[+-](0[0-9]|1[0-4]):[0-5][0-9]$/).optional(),
|
|
1139
|
+
daylightSaving: z.boolean().optional()
|
|
1140
|
+
});
|
|
1141
|
+
var period = z.union([
|
|
1142
|
+
z.strictObject({
|
|
1143
|
+
kind: z.literal("quarter"),
|
|
1144
|
+
year: z.number().int().min(1).max(9999),
|
|
1145
|
+
quarter: z.number().int().min(1).max(4)
|
|
1146
|
+
}),
|
|
1147
|
+
z.strictObject({
|
|
1148
|
+
kind: z.enum(["decade", "century"]),
|
|
1149
|
+
startYear: z.number().int().min(1).max(9999),
|
|
1150
|
+
endYear: z.number().int().min(1).max(9999)
|
|
1151
|
+
})
|
|
1152
|
+
]);
|
|
1153
|
+
var calendarEndpoint = z.strictObject({
|
|
1154
|
+
value: z.union([EventTimePointSchema, period]),
|
|
1155
|
+
certainty: z.enum(["exact", "approximate", "estimated", "unknown"]),
|
|
1156
|
+
display: text4.optional(),
|
|
1157
|
+
notes: text4.optional()
|
|
1158
|
+
});
|
|
1159
|
+
var calendarRange = z.strictObject({
|
|
1160
|
+
start: calendarEndpoint,
|
|
1161
|
+
end: calendarEndpoint,
|
|
1162
|
+
type: z.enum([
|
|
1163
|
+
"span",
|
|
1164
|
+
"uncertainty",
|
|
1165
|
+
"active_period",
|
|
1166
|
+
"investigation_period",
|
|
1167
|
+
"observation_window"
|
|
1168
|
+
]),
|
|
1169
|
+
inclusiveEnd: z.boolean(),
|
|
1170
|
+
display: text4.optional()
|
|
1171
|
+
});
|
|
1172
|
+
var relative = z.strictObject({
|
|
1173
|
+
anchorTemporalId: id3,
|
|
1174
|
+
relation: z.enum(["before", "after", "during", "around"]),
|
|
1175
|
+
offset: z.strictObject({
|
|
1176
|
+
value: z.number().min(0),
|
|
1177
|
+
unit: z.enum([
|
|
1178
|
+
"seconds",
|
|
1179
|
+
"minutes",
|
|
1180
|
+
"hours",
|
|
1181
|
+
"days",
|
|
1182
|
+
"weeks",
|
|
1183
|
+
"months",
|
|
1184
|
+
"years"
|
|
1185
|
+
]),
|
|
1186
|
+
approximate: z.boolean()
|
|
1187
|
+
}).optional(),
|
|
1188
|
+
wording: text4
|
|
1189
|
+
});
|
|
1190
|
+
var ContextEventFields = {
|
|
1191
|
+
eventType: values(
|
|
1192
|
+
text4.describe("Sourced event descriptor; not an origin hypothesis.")
|
|
1193
|
+
),
|
|
1194
|
+
description: values(text4),
|
|
1195
|
+
temporalId: values(id3),
|
|
1196
|
+
placeIds: values(z.array(id3).min(1))
|
|
1197
|
+
};
|
|
1198
|
+
var ContextObjectFields = {
|
|
1199
|
+
shape: values(ObjectShapeSchema),
|
|
1200
|
+
sizeDescription: values(text4),
|
|
1201
|
+
color: values(text4),
|
|
1202
|
+
secondaryColors: values(strings),
|
|
1203
|
+
luminosity: values(text4),
|
|
1204
|
+
sound: values(text4),
|
|
1205
|
+
soundDescription: values(text4),
|
|
1206
|
+
surfaceDetails: values(text4),
|
|
1207
|
+
formation: values(text4),
|
|
1208
|
+
structuralFeatures: values(strings),
|
|
1209
|
+
countDescription: values(text4),
|
|
1210
|
+
speedDescription: values(text4),
|
|
1211
|
+
altitudeDescription: values(text4),
|
|
1212
|
+
flightPath: values(text4),
|
|
1213
|
+
maneuvers: values(z.array(ManeuverTypeSchema).min(1)),
|
|
1214
|
+
maneuverDescriptions: values(strings),
|
|
1215
|
+
trajectoryDescription: values(text4),
|
|
1216
|
+
radarContactReported: values(z.boolean()),
|
|
1217
|
+
infraredSignatureReported: values(z.boolean())
|
|
1218
|
+
};
|
|
1219
|
+
var ContextPlaceFields = {
|
|
1220
|
+
name: values(text4),
|
|
1221
|
+
country: values(text4),
|
|
1222
|
+
countryCode: values(text4),
|
|
1223
|
+
region: values(text4),
|
|
1224
|
+
city: values(text4),
|
|
1225
|
+
address: values(text4),
|
|
1226
|
+
position: values(FramedPositionSchema),
|
|
1227
|
+
coordinatePrecision: values(CoordinatePrecisionSchema),
|
|
1228
|
+
coordinatesApproximate: values(z.boolean()),
|
|
1229
|
+
elevationSource: values(text4),
|
|
1230
|
+
siteType: values(SiteTypeSchema),
|
|
1231
|
+
secondarySiteTypes: values(z.array(SiteTypeSchema).min(1)),
|
|
1232
|
+
terrain: values(z.array(TerrainTypeSchema).min(1)),
|
|
1233
|
+
airspaceClass: values(AirspaceClassSchema),
|
|
1234
|
+
proximity: values(
|
|
1235
|
+
z.strictObject({
|
|
1236
|
+
targetPlaceId: id3,
|
|
1237
|
+
relation: z.enum([
|
|
1238
|
+
"nearby",
|
|
1239
|
+
"nearest_military",
|
|
1240
|
+
"nearest_nuclear",
|
|
1241
|
+
"nearest_airport"
|
|
1242
|
+
]),
|
|
1243
|
+
distanceMeasurementId: id3.optional(),
|
|
1244
|
+
bearingMeasurementId: id3.optional(),
|
|
1245
|
+
note: text4.optional()
|
|
1246
|
+
})
|
|
1247
|
+
),
|
|
1248
|
+
infrastructureSensitivity: values(LocationSensitivitySchema),
|
|
1249
|
+
sensitivity: values(
|
|
1250
|
+
z.enum(["public", "approximate_only", "withheld"]).describe(
|
|
1251
|
+
"Publication instruction only; does not enforce access control."
|
|
1252
|
+
)
|
|
1253
|
+
)
|
|
1254
|
+
};
|
|
1255
|
+
var ContextPlatformFields = {
|
|
1256
|
+
role: values(z.enum(["observer", "station", "aircraft", "vessel"])),
|
|
1257
|
+
placeId: values(id3),
|
|
1258
|
+
name: values(text4),
|
|
1259
|
+
type: values(text4),
|
|
1260
|
+
designation: values(text4),
|
|
1261
|
+
callsign: values(text4),
|
|
1262
|
+
flightNumber: values(text4),
|
|
1263
|
+
squadron: values(text4),
|
|
1264
|
+
mission: values(text4),
|
|
1265
|
+
operator: values(text4),
|
|
1266
|
+
radarContact: values(z.boolean()),
|
|
1267
|
+
weaponsSystemEngaged: values(z.boolean()),
|
|
1268
|
+
interceptAttempted: values(z.boolean())
|
|
1269
|
+
};
|
|
1270
|
+
var ContextEnvironmentFields = {
|
|
1271
|
+
placeId: values(id3),
|
|
1272
|
+
platformId: values(id3),
|
|
1273
|
+
temporalId: values(id3),
|
|
1274
|
+
observedAt: values(EventTimeValueSchema),
|
|
1275
|
+
weather: values(text4),
|
|
1276
|
+
visibility: values(text4),
|
|
1277
|
+
cloudCover: values(text4),
|
|
1278
|
+
windDescription: values(text4),
|
|
1279
|
+
celestialConditions: values(text4),
|
|
1280
|
+
moonPhase: values(text4),
|
|
1281
|
+
precipitation: values(text4)
|
|
1282
|
+
};
|
|
1283
|
+
var ContextTemporalFields = {
|
|
1284
|
+
eventTime: values(EventTimeValueSchema),
|
|
1285
|
+
calendarPeriod: values(period),
|
|
1286
|
+
relativeDate: values(relative),
|
|
1287
|
+
calendarRange: values(calendarRange),
|
|
1288
|
+
localTime: values(localTime),
|
|
1289
|
+
dateCertainty: values(
|
|
1290
|
+
z.enum(["exact", "approximate", "estimated", "unknown"])
|
|
1291
|
+
),
|
|
1292
|
+
timeCertainty: values(
|
|
1293
|
+
z.enum(["exact", "approximate", "estimated", "unknown"])
|
|
1294
|
+
),
|
|
1295
|
+
timeOfDay: values(TimeOfDaySchema),
|
|
1296
|
+
durationDescription: values(text4),
|
|
1297
|
+
display: values(text4),
|
|
1298
|
+
notes: values(text4),
|
|
1299
|
+
rangeInclusivity: values(
|
|
1300
|
+
z.enum(["both", "start", "end", "neither", "unknown"])
|
|
1301
|
+
)
|
|
1302
|
+
};
|
|
1303
|
+
var ContextCollectionFields = {
|
|
1304
|
+
sensorType: values(SensorTypeSchema),
|
|
1305
|
+
detectionMethod: values(DetectionMethodSchema),
|
|
1306
|
+
productRefs: values(z.array(sourceRef2).min(1)),
|
|
1307
|
+
acquisitionIds: values(z.array(id3).min(1)),
|
|
1308
|
+
retentionStatus: values(
|
|
1309
|
+
SensorEvidenceDataSchema.shape.dataRetentionStatus.unwrap()
|
|
1310
|
+
),
|
|
1311
|
+
rawDataAvailable: values(z.boolean()),
|
|
1312
|
+
anomalies: values(strings),
|
|
1313
|
+
correlationDescription: values(text4),
|
|
1314
|
+
alignmentDescription: values(text4),
|
|
1315
|
+
notes: values(text4)
|
|
1316
|
+
};
|
|
1317
|
+
for (const fields of [
|
|
1318
|
+
ContextEventFields,
|
|
1319
|
+
ContextObjectFields,
|
|
1320
|
+
ContextPlaceFields,
|
|
1321
|
+
ContextPlatformFields,
|
|
1322
|
+
ContextEnvironmentFields,
|
|
1323
|
+
ContextTemporalFields,
|
|
1324
|
+
ContextCollectionFields
|
|
1325
|
+
]) {
|
|
1326
|
+
for (const [key2, schema] of Object.entries(fields)) {
|
|
1327
|
+
const label = key2.replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase();
|
|
1328
|
+
fields[key2] = schema.describe(
|
|
1329
|
+
`Sourced ${label} assertions. Keep alternatives and missingness explicit; no assertion is selected by default.`
|
|
1330
|
+
);
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
var role = z.enum([
|
|
1334
|
+
"size",
|
|
1335
|
+
"count",
|
|
1336
|
+
"speed",
|
|
1337
|
+
"altitude",
|
|
1338
|
+
"heading",
|
|
1339
|
+
"ambient_temperature",
|
|
1340
|
+
"relative_humidity",
|
|
1341
|
+
"wind_speed",
|
|
1342
|
+
"moon_illumination",
|
|
1343
|
+
"duration",
|
|
1344
|
+
"distance",
|
|
1345
|
+
"bearing",
|
|
1346
|
+
"water_depth",
|
|
1347
|
+
"coordinate_precision",
|
|
1348
|
+
"time_alignment"
|
|
1349
|
+
]);
|
|
1350
|
+
var ContextMeasurementLinkSchema = z.strictObject({
|
|
1351
|
+
id: id3,
|
|
1352
|
+
role,
|
|
1353
|
+
measurementId: id3,
|
|
1354
|
+
relatedPlaceId: id3.optional()
|
|
1355
|
+
}).describe(
|
|
1356
|
+
"Association to an Observation measurement. No copied numeric value."
|
|
1357
|
+
);
|
|
1358
|
+
function entity(kind, fields) {
|
|
1359
|
+
const keys = Object.keys(fields);
|
|
1360
|
+
return z.strictObject({
|
|
1361
|
+
kind: z.literal(kind),
|
|
1362
|
+
id: id3,
|
|
1363
|
+
fields: z.strictObject(fields),
|
|
1364
|
+
measurements: z.array(ContextMeasurementLinkSchema).optional(),
|
|
1365
|
+
selections: z.array(
|
|
1366
|
+
z.strictObject({
|
|
1367
|
+
field: z.enum(keys),
|
|
1368
|
+
assertionId: id3,
|
|
1369
|
+
consideredAssertionIds: z.array(id3).min(1),
|
|
1370
|
+
evaluatedBy: text4,
|
|
1371
|
+
evaluatedAt: instantString,
|
|
1372
|
+
methodRef: z.string().regex(/^method:[A-Za-z0-9][A-Za-z0-9._-]*(?![\s\S])/),
|
|
1373
|
+
methodVersion: text4,
|
|
1374
|
+
rationale: text4
|
|
1375
|
+
})
|
|
1376
|
+
).optional()
|
|
1377
|
+
});
|
|
1378
|
+
}
|
|
1379
|
+
var ContextEntitySchema = z.discriminatedUnion("kind", [
|
|
1380
|
+
entity("event", ContextEventFields),
|
|
1381
|
+
entity("reported_object", ContextObjectFields),
|
|
1382
|
+
entity("place", ContextPlaceFields),
|
|
1383
|
+
entity("platform", ContextPlatformFields),
|
|
1384
|
+
entity("environment", ContextEnvironmentFields),
|
|
1385
|
+
entity("temporal", ContextTemporalFields),
|
|
1386
|
+
entity("collection", ContextCollectionFields)
|
|
1387
|
+
]);
|
|
1388
|
+
var ObservationContextSchema = z.strictObject({
|
|
1389
|
+
kind: z.literal("observation_context"),
|
|
1390
|
+
schemaVersion: z.literal("0.1.0"),
|
|
1391
|
+
id: id3,
|
|
1392
|
+
observationRef: ObservationSnapshotRefSchema,
|
|
1393
|
+
acquisitionRef: DocumentSnapshotRefSchema.extend({
|
|
1394
|
+
schemaId: z.literal(
|
|
1395
|
+
"urn:disclosureos:experimental:acquisition-context:0.1.0"
|
|
1396
|
+
)
|
|
1397
|
+
}).optional(),
|
|
1398
|
+
recordedAt: instantString,
|
|
1399
|
+
recordedBy: text4,
|
|
1400
|
+
entities: z.array(ContextEntitySchema).min(1)
|
|
1401
|
+
}).describe(
|
|
1402
|
+
"Typed descriptions of an observation. Supplied values remain sourced declarations, not verified facts."
|
|
1403
|
+
);
|
|
1404
|
+
function target(kind, fields) {
|
|
1405
|
+
const keys = Object.keys(fields);
|
|
1406
|
+
return z.strictObject({
|
|
1407
|
+
kind: z.literal(kind),
|
|
1408
|
+
id: id3,
|
|
1409
|
+
field: z.enum(keys).optional()
|
|
1410
|
+
});
|
|
1411
|
+
}
|
|
1412
|
+
var ContextTargetSchema = z.discriminatedUnion("kind", [
|
|
1413
|
+
target("event", ContextEventFields),
|
|
1414
|
+
target("reported_object", ContextObjectFields),
|
|
1415
|
+
target("place", ContextPlaceFields),
|
|
1416
|
+
target("platform", ContextPlatformFields),
|
|
1417
|
+
target("environment", ContextEnvironmentFields),
|
|
1418
|
+
target("temporal", ContextTemporalFields),
|
|
1419
|
+
target("collection", ContextCollectionFields)
|
|
1420
|
+
]);
|
|
1421
|
+
var ContextReferenceSchema = z.strictObject({
|
|
1422
|
+
document: DocumentSnapshotRefSchema.extend({
|
|
1423
|
+
schemaId: z.literal(OBSERVATION_CONTEXT_SCHEMA_ID)
|
|
1424
|
+
}),
|
|
1425
|
+
target: ContextTargetSchema
|
|
1426
|
+
});
|
|
1427
|
+
var ContextAssertionReferenceSchema = ContextReferenceSchema.extend({
|
|
1428
|
+
assertionId: id3
|
|
1429
|
+
});
|
|
1430
|
+
function observationContextJsonSchema() {
|
|
1431
|
+
return {
|
|
1432
|
+
...z.toJSONSchema(ObservationContextSchema, {
|
|
1433
|
+
target: "draft-2020-12",
|
|
1434
|
+
reused: "ref"
|
|
1435
|
+
}),
|
|
1436
|
+
$id: OBSERVATION_CONTEXT_SCHEMA_ID
|
|
1437
|
+
};
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
// src/experimental/v2/context.ts
|
|
1441
|
+
function contextAssertions(entity3) {
|
|
1442
|
+
return Object.entries(entity3.fields).flatMap(
|
|
1443
|
+
([field, assertions]) => (assertions ?? []).map((assertion) => ({
|
|
1444
|
+
field,
|
|
1445
|
+
assertion
|
|
1446
|
+
}))
|
|
1447
|
+
);
|
|
1448
|
+
}
|
|
1449
|
+
function parseObservationContext(input) {
|
|
1450
|
+
const parsed = ObservationContextSchema.safeParse(input);
|
|
1451
|
+
const contract = {
|
|
1452
|
+
schemaId: OBSERVATION_CONTEXT_SCHEMA_ID,
|
|
1453
|
+
rulesetVersion: "0.1.0"
|
|
1454
|
+
};
|
|
1455
|
+
const issues = [];
|
|
1456
|
+
const error = (code, pointer6, message) => issues.push({ code, stage: "semantic", pointer: pointer6, message });
|
|
1457
|
+
if (!parsed.success)
|
|
1458
|
+
return {
|
|
1459
|
+
success: false,
|
|
1460
|
+
contract,
|
|
1461
|
+
checks: {
|
|
1462
|
+
structural: "failed",
|
|
1463
|
+
semantic: "not_checked",
|
|
1464
|
+
profile: "not_checked",
|
|
1465
|
+
external: "not_checked"
|
|
1466
|
+
},
|
|
1467
|
+
issues: parsed.error.issues.map((i) => ({
|
|
1468
|
+
code: "STRUCT.VALUE",
|
|
1469
|
+
stage: "structural",
|
|
1470
|
+
pointer: "/" + i.path.join("/"),
|
|
1471
|
+
message: i.message
|
|
1472
|
+
})),
|
|
1473
|
+
uncheckedRefs: []
|
|
1474
|
+
};
|
|
1475
|
+
const data = parsed.data;
|
|
1476
|
+
const entities = /* @__PURE__ */ new Map();
|
|
1477
|
+
const relativeGraph = /* @__PURE__ */ new Map();
|
|
1478
|
+
for (const [i, entity3] of data.entities.entries()) {
|
|
1479
|
+
const key2 = `${entity3.kind}:${entity3.id}`;
|
|
1480
|
+
if (entities.has(key2))
|
|
1481
|
+
error("REF.UNIQUE_ID", `/entities/${i}/id`, "Duplicate entity identity.");
|
|
1482
|
+
entities.set(key2, entity3);
|
|
1483
|
+
if (entity3.kind === "temporal") relativeGraph.set(entity3.id, /* @__PURE__ */ new Set());
|
|
1484
|
+
}
|
|
1485
|
+
function time(value, path) {
|
|
1486
|
+
const found = [];
|
|
1487
|
+
checkTime(value, path, found);
|
|
1488
|
+
found.forEach((i) => error(i.code, i.pointer, i.message));
|
|
1489
|
+
}
|
|
1490
|
+
time(
|
|
1491
|
+
{ kind: "instant", value: data.recordedAt},
|
|
1492
|
+
"/recordedAt"
|
|
1493
|
+
);
|
|
1494
|
+
const unchecked = /* @__PURE__ */ new Set([data.observationRef.sha256]);
|
|
1495
|
+
if (data.acquisitionRef) unchecked.add(data.acquisitionRef.sha256);
|
|
1496
|
+
for (const [i, entity3] of data.entities.entries()) {
|
|
1497
|
+
const path = `/entities/${i}`;
|
|
1498
|
+
const assertions = contextAssertions(entity3);
|
|
1499
|
+
const ids = /* @__PURE__ */ new Set();
|
|
1500
|
+
for (const { field, assertion } of assertions) {
|
|
1501
|
+
const p = `${path}/fields/${field}`;
|
|
1502
|
+
if (ids.has(assertion.id))
|
|
1503
|
+
error(
|
|
1504
|
+
"REF.UNIQUE_ID",
|
|
1505
|
+
p,
|
|
1506
|
+
"Assertion IDs must be unique across fields within an entity."
|
|
1507
|
+
);
|
|
1508
|
+
ids.add(assertion.id);
|
|
1509
|
+
const { content } = assertion;
|
|
1510
|
+
const prov = content.provenance;
|
|
1511
|
+
if (prov) {
|
|
1512
|
+
unchecked.add(prov.sourceRef);
|
|
1513
|
+
if (prov.locator?.kind === "time_range" && prov.locator.endSeconds < prov.locator.startSeconds)
|
|
1514
|
+
error("TIME.INTERVAL", p, "Source locator end precedes start.");
|
|
1515
|
+
}
|
|
1516
|
+
if (!("value" in content)) continue;
|
|
1517
|
+
if (field === "eventTime" || field === "observedAt")
|
|
1518
|
+
time(content.value, p);
|
|
1519
|
+
const linkKind = {
|
|
1520
|
+
placeId: "place",
|
|
1521
|
+
platformId: "platform",
|
|
1522
|
+
temporalId: "temporal"
|
|
1523
|
+
}[field];
|
|
1524
|
+
if (linkKind && !entities.has(`${linkKind}:${content.value}`))
|
|
1525
|
+
error(
|
|
1526
|
+
"REF.LOCAL_RESOLUTION",
|
|
1527
|
+
p,
|
|
1528
|
+
"Context entity reference does not resolve."
|
|
1529
|
+
);
|
|
1530
|
+
if (field === "placeIds") {
|
|
1531
|
+
for (const id7 of content.value)
|
|
1532
|
+
if (!entities.has(`place:${id7}`))
|
|
1533
|
+
error(
|
|
1534
|
+
"REF.LOCAL_RESOLUTION",
|
|
1535
|
+
p,
|
|
1536
|
+
"Place reference does not resolve."
|
|
1537
|
+
);
|
|
1538
|
+
}
|
|
1539
|
+
if (field === "proximity" && !entities.has(
|
|
1540
|
+
`place:${content.value.targetPlaceId}`
|
|
1541
|
+
))
|
|
1542
|
+
error(
|
|
1543
|
+
"REF.LOCAL_RESOLUTION",
|
|
1544
|
+
p,
|
|
1545
|
+
"Proximity target place does not resolve."
|
|
1546
|
+
);
|
|
1547
|
+
if (field === "relativeDate") {
|
|
1548
|
+
const relative2 = content.value;
|
|
1549
|
+
if (!entities.has(`temporal:${relative2.anchorTemporalId}`))
|
|
1550
|
+
error(
|
|
1551
|
+
"REF.LOCAL_RESOLUTION",
|
|
1552
|
+
p,
|
|
1553
|
+
"Relative date anchor does not resolve."
|
|
1554
|
+
);
|
|
1555
|
+
relativeGraph.get(entity3.id)?.add(relative2.anchorTemporalId);
|
|
1556
|
+
if (relative2.relation === "during" && relative2.offset)
|
|
1557
|
+
error(
|
|
1558
|
+
"TIME.RELATIVE_OFFSET",
|
|
1559
|
+
p,
|
|
1560
|
+
"A during relation cannot carry an offset."
|
|
1561
|
+
);
|
|
1562
|
+
}
|
|
1563
|
+
if (field === "calendarPeriod") {
|
|
1564
|
+
const period2 = content.value;
|
|
1565
|
+
if (period2.kind !== "quarter" && period2.endYear - period2.startYear !== (period2.kind === "decade" ? 9 : 99))
|
|
1566
|
+
error(
|
|
1567
|
+
"TIME.CALENDAR_PERIOD",
|
|
1568
|
+
p,
|
|
1569
|
+
"Declared period must cover exactly ten or one hundred years."
|
|
1570
|
+
);
|
|
1571
|
+
}
|
|
1572
|
+
if (field === "calendarRange") {
|
|
1573
|
+
const range = content.value;
|
|
1574
|
+
for (const endpoint of [range.start.value, range.end.value]) {
|
|
1575
|
+
if (["year", "month", "date", "instant"].includes(endpoint.kind))
|
|
1576
|
+
time(endpoint, p);
|
|
1577
|
+
if (["decade", "century"].includes(endpoint.kind) && endpoint.endYear - endpoint.startYear !== (endpoint.kind === "decade" ? 9 : 99))
|
|
1578
|
+
error(
|
|
1579
|
+
"TIME.CALENDAR_PERIOD",
|
|
1580
|
+
p,
|
|
1581
|
+
"Endpoint period has invalid width."
|
|
1582
|
+
);
|
|
1583
|
+
}
|
|
1584
|
+
const a = range.start.value, b = range.end.value;
|
|
1585
|
+
if (a.kind === b.kind) {
|
|
1586
|
+
const reversed = ["year", "month", "date", "instant"].includes(a.kind) ? comparePoints(
|
|
1587
|
+
a,
|
|
1588
|
+
b
|
|
1589
|
+
) > 0 : a.kind === "quarter" ? a.year * 4 + a.quarter > b.year * 4 + b.quarter : a.startYear > b.startYear;
|
|
1590
|
+
if (reversed)
|
|
1591
|
+
error("TIME.INTERVAL", p, "Calendar range end precedes start.");
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
if (field === "localTime") {
|
|
1595
|
+
const clock = content.value;
|
|
1596
|
+
if (clock.timezone)
|
|
1597
|
+
try {
|
|
1598
|
+
new Intl.DateTimeFormat("en", { timeZone: clock.timezone });
|
|
1599
|
+
} catch {
|
|
1600
|
+
error(
|
|
1601
|
+
"TIME.TIMEZONE",
|
|
1602
|
+
p,
|
|
1603
|
+
"Unknown timezone; no offset has been inferred."
|
|
1604
|
+
);
|
|
1605
|
+
}
|
|
1606
|
+
if (clock.utcOffset?.slice(1, 3) === "14" && !clock.utcOffset.endsWith(":00"))
|
|
1607
|
+
error("TIME.OFFSET", p, "UTC offset must not exceed fourteen hours.");
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
const selectedFields = /* @__PURE__ */ new Set();
|
|
1611
|
+
for (const selection of entity3.selections ?? []) {
|
|
1612
|
+
const p = `${path}/selections`;
|
|
1613
|
+
if (selectedFields.has(selection.field))
|
|
1614
|
+
error(
|
|
1615
|
+
"SELECTION.DUPLICATE_FIELD",
|
|
1616
|
+
p,
|
|
1617
|
+
"One selection is allowed per field."
|
|
1618
|
+
);
|
|
1619
|
+
selectedFields.add(selection.field);
|
|
1620
|
+
if (!selection.consideredAssertionIds.includes(selection.assertionId))
|
|
1621
|
+
error(
|
|
1622
|
+
"SELECTION.INPUTS",
|
|
1623
|
+
p,
|
|
1624
|
+
"Selected assertion must be a considered input."
|
|
1625
|
+
);
|
|
1626
|
+
if (new Set(selection.consideredAssertionIds).size !== selection.consideredAssertionIds.length)
|
|
1627
|
+
error("REF.UNIQUE_ID", p, "Considered assertions are repeated.");
|
|
1628
|
+
for (const id7 of selection.consideredAssertionIds)
|
|
1629
|
+
if (!assertions.some(
|
|
1630
|
+
(a) => a.field === selection.field && a.assertion.id === id7
|
|
1631
|
+
))
|
|
1632
|
+
error(
|
|
1633
|
+
"REF.FIELD_MISMATCH",
|
|
1634
|
+
p,
|
|
1635
|
+
"Considered assertion must exist on the selected field."
|
|
1636
|
+
);
|
|
1637
|
+
const chosen = assertions.find(
|
|
1638
|
+
(a) => a.field === selection.field && a.assertion.id === selection.assertionId
|
|
1639
|
+
);
|
|
1640
|
+
if (!chosen || !["known", "approximate", "unmapped"].includes(
|
|
1641
|
+
chosen.assertion.content.state
|
|
1642
|
+
))
|
|
1643
|
+
error(
|
|
1644
|
+
"SELECTION.VALUE",
|
|
1645
|
+
p,
|
|
1646
|
+
"Select a sourced assertion, not an unknown or redacted value."
|
|
1647
|
+
);
|
|
1648
|
+
time(
|
|
1649
|
+
{ kind: "instant", value: selection.evaluatedAt},
|
|
1650
|
+
p
|
|
1651
|
+
);
|
|
1652
|
+
if (comparePoints(
|
|
1653
|
+
{ kind: "instant", value: selection.evaluatedAt},
|
|
1654
|
+
{ kind: "instant", value: data.recordedAt}
|
|
1655
|
+
) > 0)
|
|
1656
|
+
error(
|
|
1657
|
+
"SELECTION.ORDER",
|
|
1658
|
+
p,
|
|
1659
|
+
"Selection evaluation cannot follow its recording."
|
|
1660
|
+
);
|
|
1661
|
+
unchecked.add(selection.methodRef);
|
|
1662
|
+
}
|
|
1663
|
+
const measurements = /* @__PURE__ */ new Set();
|
|
1664
|
+
for (const link of entity3.measurements ?? []) {
|
|
1665
|
+
if (measurements.has(link.id))
|
|
1666
|
+
error(
|
|
1667
|
+
"REF.UNIQUE_ID",
|
|
1668
|
+
`${path}/measurements`,
|
|
1669
|
+
"Measurement link IDs repeat."
|
|
1670
|
+
);
|
|
1671
|
+
measurements.add(link.id);
|
|
1672
|
+
unchecked.add(`measurement:${link.measurementId}`);
|
|
1673
|
+
if (link.relatedPlaceId && !entities.has(`place:${link.relatedPlaceId}`))
|
|
1674
|
+
error(
|
|
1675
|
+
"REF.LOCAL_RESOLUTION",
|
|
1676
|
+
`${path}/measurements`,
|
|
1677
|
+
"Related place does not resolve."
|
|
1678
|
+
);
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
const degree = new Map([...relativeGraph.keys()].map((k) => [k, 0]));
|
|
1682
|
+
for (const edges of relativeGraph.values())
|
|
1683
|
+
for (const to of edges)
|
|
1684
|
+
if (degree.has(to)) degree.set(to, degree.get(to) + 1);
|
|
1685
|
+
const queue = [...degree].filter(([, n]) => n === 0).map(([key2]) => key2);
|
|
1686
|
+
for (let i = 0; i < queue.length; i++)
|
|
1687
|
+
for (const to of relativeGraph.get(queue[i]) ?? [])
|
|
1688
|
+
if (degree.has(to)) {
|
|
1689
|
+
degree.set(to, degree.get(to) - 1);
|
|
1690
|
+
if (degree.get(to) === 0) queue.push(to);
|
|
1691
|
+
}
|
|
1692
|
+
if (queue.length !== degree.size)
|
|
1693
|
+
error(
|
|
1694
|
+
"TIME.RELATIVE_CYCLE",
|
|
1695
|
+
"/entities",
|
|
1696
|
+
"Relative dates must be acyclic."
|
|
1697
|
+
);
|
|
1698
|
+
const validation = {
|
|
1699
|
+
contract,
|
|
1700
|
+
issues,
|
|
1701
|
+
uncheckedRefs: [...unchecked],
|
|
1702
|
+
checks: {
|
|
1703
|
+
structural: "passed",
|
|
1704
|
+
semantic: issues.length ? "failed" : "passed",
|
|
1705
|
+
profile: "not_checked",
|
|
1706
|
+
external: "not_checked"
|
|
1707
|
+
}
|
|
1708
|
+
};
|
|
1709
|
+
return issues.length ? { ...validation, success: false } : { ...validation, success: true, data };
|
|
1710
|
+
}
|
|
1711
|
+
var text5 = z.string().min(1).regex(/\S/, "must contain non-whitespace text");
|
|
1712
|
+
var id4 = z.string().regex(/^[A-Za-z0-9][A-Za-z0-9._-]*(?![\s\S])/);
|
|
1713
|
+
var claimRef2 = z.string().regex(/^claim:[A-Za-z0-9][A-Za-z0-9._-]*(?![\s\S])/);
|
|
1714
|
+
var inputRef2 = z.string().regex(
|
|
1715
|
+
/^(?:claim|source|product|assertion|measurement):[A-Za-z0-9][A-Za-z0-9._-]*(?![\s\S])/
|
|
1716
|
+
);
|
|
1717
|
+
var ContextClaimSubjectSchema = z.discriminatedUnion("kind", [
|
|
1718
|
+
z.strictObject({ kind: z.literal("observation") }),
|
|
1719
|
+
z.strictObject({
|
|
1720
|
+
kind: z.literal("context"),
|
|
1721
|
+
reference: ContextReferenceSchema
|
|
1722
|
+
}),
|
|
1723
|
+
z.strictObject({ kind: z.literal("measurement"), measurementId: id4 })
|
|
1724
|
+
]);
|
|
1725
|
+
var common2 = {
|
|
1726
|
+
id: id4,
|
|
1727
|
+
recordedAt: instantString,
|
|
1728
|
+
topic: text5,
|
|
1729
|
+
subject: ContextClaimSubjectSchema,
|
|
1730
|
+
supersedes: z.array(claimRef2).min(1).optional()
|
|
1731
|
+
};
|
|
1732
|
+
var ContextSourceStatementSchema = z.strictObject({
|
|
1733
|
+
...common2,
|
|
1734
|
+
kind: z.literal("source_assertion"),
|
|
1735
|
+
text: text5,
|
|
1736
|
+
reportedLevel: text5.optional(),
|
|
1737
|
+
provenance: ObservationAssertionSchema.options[0].shape.provenance
|
|
1738
|
+
});
|
|
1739
|
+
var assessment2 = {
|
|
1740
|
+
...common2,
|
|
1741
|
+
kind: z.literal("assessment"),
|
|
1742
|
+
inputRefs: z.array(inputRef2),
|
|
1743
|
+
contextInputRefs: z.array(ContextAssertionReferenceSchema).optional(),
|
|
1744
|
+
rationale: text5
|
|
1745
|
+
};
|
|
1746
|
+
var ContextUnassessedClaimSchema = z.strictObject({
|
|
1747
|
+
...assessment2,
|
|
1748
|
+
status: z.literal("unassessed")
|
|
1749
|
+
});
|
|
1750
|
+
var ContextAssessedClaimSchema = z.strictObject({
|
|
1751
|
+
...assessment2,
|
|
1752
|
+
status: z.literal("assessed"),
|
|
1753
|
+
outcome: z.enum(["reported", "confirmed", "absent", "inconclusive"]),
|
|
1754
|
+
evaluatedBy: text5,
|
|
1755
|
+
evaluatedAt: instantString,
|
|
1756
|
+
methodRef: z.string().regex(/^method:[A-Za-z0-9][A-Za-z0-9._-]*(?![\s\S])/),
|
|
1757
|
+
methodVersion: text5,
|
|
1758
|
+
confidence: z.number().min(0).max(1).optional()
|
|
1759
|
+
});
|
|
1760
|
+
var ContextHistoricalClaimSchema = z.union([
|
|
1761
|
+
ContextSourceStatementSchema,
|
|
1762
|
+
ContextUnassessedClaimSchema,
|
|
1763
|
+
ContextAssessedClaimSchema
|
|
1764
|
+
]);
|
|
1765
|
+
var CONTEXT_CLAIM_HISTORY_SCHEMA_ID = "urn:disclosureos:experimental:claim-history:0.2.0";
|
|
1766
|
+
var CONTEXT_CLAIM_HISTORY_RULESET_VERSION = "0.2.0";
|
|
1767
|
+
var ContextClaimHistorySchema = z.strictObject({
|
|
1768
|
+
kind: z.literal("claim_history"),
|
|
1769
|
+
schemaVersion: z.literal("0.2.0"),
|
|
1770
|
+
id: id4,
|
|
1771
|
+
contextRefs: z.array(
|
|
1772
|
+
DocumentSnapshotRefSchema.extend({
|
|
1773
|
+
schemaId: z.literal(OBSERVATION_CONTEXT_SCHEMA_ID)
|
|
1774
|
+
})
|
|
1775
|
+
),
|
|
1776
|
+
observation: ExperimentalObservationSchema,
|
|
1777
|
+
claims: z.array(ContextHistoricalClaimSchema),
|
|
1778
|
+
extensions: ExperimentalObservationSchema.shape.extensions
|
|
1779
|
+
});
|
|
1780
|
+
function contextClaimHistoryJsonSchema() {
|
|
1781
|
+
return {
|
|
1782
|
+
...z.toJSONSchema(ContextClaimHistorySchema, {
|
|
1783
|
+
target: "draft-2020-12",
|
|
1784
|
+
reused: "ref"
|
|
1785
|
+
}),
|
|
1786
|
+
$id: CONTEXT_CLAIM_HISTORY_SCHEMA_ID
|
|
1787
|
+
};
|
|
1788
|
+
}
|
|
1789
|
+
|
|
1790
|
+
// src/experimental/v2/context-claim-history.ts
|
|
1791
|
+
var point2 = (value) => ({
|
|
1792
|
+
kind: "instant",
|
|
1793
|
+
value,
|
|
1794
|
+
timeScale: "UTC"
|
|
1795
|
+
});
|
|
1796
|
+
var pointer4 = (path) => path.map((p) => `/${String(p).replace(/~/g, "~0").replace(/\//g, "~1")}`).join("");
|
|
1797
|
+
function parseContextClaimHistory(input) {
|
|
1798
|
+
const contract = {
|
|
1799
|
+
kind: "claim_history",
|
|
1800
|
+
schemaId: CONTEXT_CLAIM_HISTORY_SCHEMA_ID,
|
|
1801
|
+
rulesetVersion: CONTEXT_CLAIM_HISTORY_RULESET_VERSION
|
|
1802
|
+
};
|
|
1803
|
+
const parsed = ContextClaimHistorySchema.safeParse(input);
|
|
1804
|
+
if (!parsed.success)
|
|
1805
|
+
return {
|
|
1806
|
+
success: false,
|
|
1807
|
+
contract,
|
|
1808
|
+
checks: {
|
|
1809
|
+
structural: "failed",
|
|
1810
|
+
semantic: "not_checked",
|
|
1811
|
+
profile: "not_checked",
|
|
1812
|
+
external: "not_checked"
|
|
1813
|
+
},
|
|
1814
|
+
uncheckedRefs: [],
|
|
1815
|
+
issues: parsed.error.issues.map((issue) => ({
|
|
1816
|
+
code: "STRUCT.VALUE",
|
|
1817
|
+
stage: "structural",
|
|
1818
|
+
severity: "error",
|
|
1819
|
+
pointer: pointer4(issue.path),
|
|
1820
|
+
message: issue.message
|
|
1821
|
+
}))
|
|
1822
|
+
};
|
|
1823
|
+
const data = parsed.data;
|
|
1824
|
+
const observationResult = parseExperimentalObservation(data.observation);
|
|
1825
|
+
const issues = observationResult.issues.map(
|
|
1826
|
+
(issue) => ({ ...issue, pointer: `/observation${issue.pointer}` })
|
|
1827
|
+
);
|
|
1828
|
+
const problem = (code, path, message) => issues.push({
|
|
1829
|
+
code,
|
|
1830
|
+
stage: "semantic",
|
|
1831
|
+
severity: "error",
|
|
1832
|
+
pointer: path,
|
|
1833
|
+
message
|
|
1834
|
+
});
|
|
1835
|
+
const claims = /* @__PURE__ */ new Map();
|
|
1836
|
+
const graph = /* @__PURE__ */ new Map();
|
|
1837
|
+
const superseded = /* @__PURE__ */ new Set();
|
|
1838
|
+
const sources = new Map(
|
|
1839
|
+
data.observation.sources.map((item) => [`source:${item.id}`, item])
|
|
1840
|
+
);
|
|
1841
|
+
const products = new Map(
|
|
1842
|
+
data.observation.products.map((item) => [`product:${item.id}`, item])
|
|
1843
|
+
);
|
|
1844
|
+
const methods = new Map(
|
|
1845
|
+
data.observation.methods.map((item) => [`method:${item.id}`, item])
|
|
1846
|
+
);
|
|
1847
|
+
const measurements = new Set(
|
|
1848
|
+
data.observation.measurements.map((item) => `measurement:${item.id}`)
|
|
1849
|
+
);
|
|
1850
|
+
const available = /* @__PURE__ */ new Set([
|
|
1851
|
+
...sources.keys(),
|
|
1852
|
+
...products.keys(),
|
|
1853
|
+
...measurements,
|
|
1854
|
+
...data.observation.assertions.map((item) => `assertion:${item.id}`)
|
|
1855
|
+
]);
|
|
1856
|
+
for (const [i, claim] of data.claims.entries()) {
|
|
1857
|
+
const ref2 = `claim:${claim.id}`;
|
|
1858
|
+
if (claims.has(ref2))
|
|
1859
|
+
problem(
|
|
1860
|
+
"REF.UNIQUE_ID",
|
|
1861
|
+
`/claims/${i}/id`,
|
|
1862
|
+
"Duplicate claim ID; each revision must have its own ID."
|
|
1863
|
+
);
|
|
1864
|
+
else {
|
|
1865
|
+
claims.set(ref2, claim);
|
|
1866
|
+
graph.set(ref2, /* @__PURE__ */ new Set());
|
|
1867
|
+
available.add(ref2);
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1870
|
+
function instant(value, path) {
|
|
1871
|
+
const local = [];
|
|
1872
|
+
checkTime(point2(value), path, local);
|
|
1873
|
+
for (const issue of local)
|
|
1874
|
+
problem(issue.code, issue.pointer, issue.message);
|
|
1875
|
+
}
|
|
1876
|
+
function resolve(ref2, path, owner) {
|
|
1877
|
+
if (!available.has(ref2))
|
|
1878
|
+
problem(
|
|
1879
|
+
"REF.LOCAL_RESOLUTION",
|
|
1880
|
+
path,
|
|
1881
|
+
`Undeclared local reference: ${ref2}`
|
|
1882
|
+
);
|
|
1883
|
+
else if (owner && claims.has(ref2)) graph.get(owner)?.add(ref2);
|
|
1884
|
+
}
|
|
1885
|
+
function refs(values3, path, owner) {
|
|
1886
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1887
|
+
for (const [i, ref2] of values3.entries()) {
|
|
1888
|
+
if (seen.has(ref2))
|
|
1889
|
+
problem("REF.UNIQUE_ID", `${path}/${i}`, "Reference is repeated.");
|
|
1890
|
+
seen.add(ref2);
|
|
1891
|
+
resolve(ref2, `${path}/${i}`, owner);
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
const snapshots = new Set(data.contextRefs.map((r) => JSON.stringify(r)));
|
|
1895
|
+
if (snapshots.size !== data.contextRefs.length)
|
|
1896
|
+
problem(
|
|
1897
|
+
"REF.UNIQUE_ID",
|
|
1898
|
+
"/contextRefs",
|
|
1899
|
+
"Context snapshot references repeat."
|
|
1900
|
+
);
|
|
1901
|
+
for (const [i, claim] of data.claims.entries()) {
|
|
1902
|
+
const contextRefs = [
|
|
1903
|
+
...claim.subject.kind === "context" ? [claim.subject.reference] : [],
|
|
1904
|
+
...claim.kind === "assessment" ? claim.contextInputRefs ?? [] : []
|
|
1905
|
+
];
|
|
1906
|
+
for (const ref2 of contextRefs)
|
|
1907
|
+
if (!snapshots.has(JSON.stringify(ref2.document)))
|
|
1908
|
+
problem(
|
|
1909
|
+
"REF.LOCAL_RESOLUTION",
|
|
1910
|
+
`/claims/${i}`,
|
|
1911
|
+
"Context reference must select a declared snapshot."
|
|
1912
|
+
);
|
|
1913
|
+
if (claim.kind === "assessment" && new Set((claim.contextInputRefs ?? []).map((r) => JSON.stringify(r))).size !== (claim.contextInputRefs ?? []).length)
|
|
1914
|
+
problem(
|
|
1915
|
+
"REF.UNIQUE_ID",
|
|
1916
|
+
`/claims/${i}/contextInputRefs`,
|
|
1917
|
+
"Context inputs repeat."
|
|
1918
|
+
);
|
|
1919
|
+
}
|
|
1920
|
+
for (const [i, claim] of data.claims.entries()) {
|
|
1921
|
+
const path = `/claims/${i}`;
|
|
1922
|
+
const owner = `claim:${claim.id}`;
|
|
1923
|
+
instant(claim.recordedAt, `${path}/recordedAt`);
|
|
1924
|
+
if (claim.subject.kind === "measurement")
|
|
1925
|
+
resolve(
|
|
1926
|
+
`measurement:${claim.subject.measurementId}`,
|
|
1927
|
+
`${path}/subject/measurementId`
|
|
1928
|
+
);
|
|
1929
|
+
if (claim.supersedes) {
|
|
1930
|
+
refs(claim.supersedes, `${path}/supersedes`, owner);
|
|
1931
|
+
for (const [j, ref2] of claim.supersedes.entries()) {
|
|
1932
|
+
const previous = claims.get(ref2);
|
|
1933
|
+
if (!previous) continue;
|
|
1934
|
+
superseded.add(ref2);
|
|
1935
|
+
if (previous.kind !== claim.kind || previous.topic !== claim.topic || JSON.stringify(previous.subject) !== JSON.stringify(claim.subject)) {
|
|
1936
|
+
problem(
|
|
1937
|
+
"CLAIM.SUPERSESSION_SCOPE",
|
|
1938
|
+
`${path}/supersedes/${j}`,
|
|
1939
|
+
"A revision must retain the claim kind, topic, and subject. Record a different claim separately."
|
|
1940
|
+
);
|
|
1941
|
+
}
|
|
1942
|
+
if (previous.kind === "assessment" && previous.status === "assessed" && claim.kind === "assessment" && (claim.status !== "assessed" || previous.evaluatedBy !== claim.evaluatedBy)) {
|
|
1943
|
+
problem(
|
|
1944
|
+
"CLAIM.REVISION_ATTRIBUTION",
|
|
1945
|
+
`${path}/supersedes/${j}`,
|
|
1946
|
+
"An assessed revision must retain its evaluator; other evaluators record independent assessments."
|
|
1947
|
+
);
|
|
1948
|
+
}
|
|
1949
|
+
if (comparePoints(point2(previous.recordedAt), point2(claim.recordedAt)) > 0) {
|
|
1950
|
+
problem(
|
|
1951
|
+
"CLAIM.REVISION_ORDER",
|
|
1952
|
+
`${path}/recordedAt`,
|
|
1953
|
+
"A revision cannot be recorded before the statement it supersedes."
|
|
1954
|
+
);
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
}
|
|
1958
|
+
if (claim.kind === "source_assertion") {
|
|
1959
|
+
resolve(claim.provenance.sourceRef, `${path}/provenance/sourceRef`);
|
|
1960
|
+
const source = sources.get(claim.provenance.sourceRef) ?? products.get(claim.provenance.sourceRef);
|
|
1961
|
+
if (source?.digest && claim.provenance.sourceDigest && source.digest.value !== claim.provenance.sourceDigest.value) {
|
|
1962
|
+
problem(
|
|
1963
|
+
"SOURCE.DIGEST_MISMATCH",
|
|
1964
|
+
`${path}/provenance/sourceDigest`,
|
|
1965
|
+
"Digest differs from the inventory declaration; neither is verified against bytes."
|
|
1966
|
+
);
|
|
1967
|
+
}
|
|
1968
|
+
const locator = claim.provenance.locator;
|
|
1969
|
+
if (locator?.kind === "time_range" && locator.endSeconds < locator.startSeconds)
|
|
1970
|
+
problem(
|
|
1971
|
+
"TIME.INTERVAL",
|
|
1972
|
+
`${path}/provenance/locator/endSeconds`,
|
|
1973
|
+
"Locator end precedes its start."
|
|
1974
|
+
);
|
|
1975
|
+
} else {
|
|
1976
|
+
refs(claim.inputRefs, `${path}/inputRefs`, owner);
|
|
1977
|
+
if (claim.status === "assessed") {
|
|
1978
|
+
instant(claim.evaluatedAt, `${path}/evaluatedAt`);
|
|
1979
|
+
if (comparePoints(point2(claim.evaluatedAt), point2(claim.recordedAt)) > 0)
|
|
1980
|
+
problem(
|
|
1981
|
+
"CLAIM.EVALUATION_ORDER",
|
|
1982
|
+
`${path}/evaluatedAt`,
|
|
1983
|
+
"Evaluation cannot occur after the assessment was recorded."
|
|
1984
|
+
);
|
|
1985
|
+
const method = methods.get(claim.methodRef);
|
|
1986
|
+
if (!method)
|
|
1987
|
+
problem(
|
|
1988
|
+
"REF.LOCAL_RESOLUTION",
|
|
1989
|
+
`${path}/methodRef`,
|
|
1990
|
+
"Assessment method is not declared in the Observation inventory."
|
|
1991
|
+
);
|
|
1992
|
+
else if (method.version !== claim.methodVersion)
|
|
1993
|
+
problem(
|
|
1994
|
+
"METHOD.VERSION_MISMATCH",
|
|
1995
|
+
`${path}/methodVersion`,
|
|
1996
|
+
"Assessment method version differs from its inventory declaration."
|
|
1997
|
+
);
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
const indegrees = new Map([...graph.keys()].map((ref2) => [ref2, 0]));
|
|
2002
|
+
for (const edges of graph.values())
|
|
2003
|
+
for (const ref2 of edges) indegrees.set(ref2, indegrees.get(ref2) + 1);
|
|
2004
|
+
const queue = [...indegrees].filter(([, degree]) => degree === 0).map(([ref2]) => ref2);
|
|
2005
|
+
for (let i = 0; i < queue.length; i++)
|
|
2006
|
+
for (const ref2 of graph.get(queue[i]) ?? []) {
|
|
2007
|
+
const degree = indegrees.get(ref2) - 1;
|
|
2008
|
+
indegrees.set(ref2, degree);
|
|
2009
|
+
if (degree === 0) queue.push(ref2);
|
|
2010
|
+
}
|
|
2011
|
+
if (queue.length !== graph.size)
|
|
2012
|
+
problem(
|
|
2013
|
+
"CLAIM.DEPENDENCY_CYCLE",
|
|
2014
|
+
"/claims",
|
|
2015
|
+
"Claim inputs and supersession must form an acyclic history."
|
|
2016
|
+
);
|
|
2017
|
+
const validation = {
|
|
2018
|
+
contract,
|
|
2019
|
+
issues,
|
|
2020
|
+
uncheckedRefs: [
|
|
2021
|
+
...data.contextRefs.map((r) => r.sha256),
|
|
2022
|
+
...observationResult.uncheckedRefs,
|
|
2023
|
+
...data.claims.flatMap((c) => [
|
|
2024
|
+
...c.subject.kind === "context" ? [c.subject.reference.document.sha256] : [],
|
|
2025
|
+
...c.kind === "assessment" ? (c.contextInputRefs ?? []).map((r) => r.document.sha256) : []
|
|
2026
|
+
])
|
|
2027
|
+
],
|
|
2028
|
+
checks: {
|
|
2029
|
+
structural: "passed",
|
|
2030
|
+
semantic: issues.length ? "failed" : "passed",
|
|
2031
|
+
profile: "not_checked",
|
|
2032
|
+
external: "not_checked"
|
|
2033
|
+
}
|
|
2034
|
+
};
|
|
2035
|
+
return issues.length ? { ...validation, success: false } : {
|
|
2036
|
+
...validation,
|
|
2037
|
+
success: true,
|
|
2038
|
+
data,
|
|
2039
|
+
currentClaimRefs: [...claims.keys()].filter(
|
|
2040
|
+
(ref2) => !superseded.has(ref2)
|
|
2041
|
+
)
|
|
2042
|
+
};
|
|
2043
|
+
}
|
|
2044
|
+
var WitnessCategorySchema = z.enum([
|
|
2045
|
+
"military_pilot",
|
|
2046
|
+
"military_aircrew",
|
|
2047
|
+
"military_ground",
|
|
2048
|
+
"military_naval",
|
|
2049
|
+
"military_radar_operator",
|
|
2050
|
+
"military_other",
|
|
2051
|
+
"commercial_pilot",
|
|
2052
|
+
"commercial_aircrew",
|
|
2053
|
+
"private_pilot",
|
|
2054
|
+
"air_traffic_controller",
|
|
2055
|
+
"aviation_other",
|
|
2056
|
+
"government_official",
|
|
2057
|
+
"elected_official",
|
|
2058
|
+
"intelligence_officer",
|
|
2059
|
+
"law_enforcement",
|
|
2060
|
+
"scientist",
|
|
2061
|
+
"astronomer",
|
|
2062
|
+
"meteorologist",
|
|
2063
|
+
"engineer",
|
|
2064
|
+
"medical_professional",
|
|
2065
|
+
"maritime",
|
|
2066
|
+
"civilian",
|
|
2067
|
+
"civilian_group",
|
|
2068
|
+
"anonymous",
|
|
2069
|
+
"unknown"
|
|
2070
|
+
]).describe("Professional/role category of a witness.");
|
|
2071
|
+
var CredibilityFactorSchema = z.enum([
|
|
2072
|
+
"professional_training",
|
|
2073
|
+
"official_capacity",
|
|
2074
|
+
"sworn_statement",
|
|
2075
|
+
"contemporaneous_record",
|
|
2076
|
+
"corroborating_witnesses",
|
|
2077
|
+
"corroborating_evidence",
|
|
2078
|
+
"consistent_account",
|
|
2079
|
+
"no_apparent_motive",
|
|
2080
|
+
"reputation_risk",
|
|
2081
|
+
"security_clearance"
|
|
2082
|
+
]).describe("A factor strengthening witness credibility.");
|
|
2083
|
+
var CredibilityDetractorSchema = z.enum([
|
|
2084
|
+
"anonymous",
|
|
2085
|
+
"inconsistent_account",
|
|
2086
|
+
"delayed_report",
|
|
2087
|
+
"known_fabricator",
|
|
2088
|
+
"financial_motive",
|
|
2089
|
+
"single_witness",
|
|
2090
|
+
"impaired_state",
|
|
2091
|
+
"recovered_memory"
|
|
2092
|
+
]).describe("A factor weakening witness credibility.");
|
|
2093
|
+
var WitnessCredibilitySchema = z.object({
|
|
2094
|
+
// The former `CredibilityRating` was byte-identical to the qualitative
|
|
2095
|
+
// `ConfidenceLevel`; it is now the single shared scale (DRY #1).
|
|
2096
|
+
rating: ConfidenceLevelSchema.optional(),
|
|
2097
|
+
factors: z.array(CredibilityFactorSchema).optional(),
|
|
2098
|
+
detractors: z.array(CredibilityDetractorSchema).optional(),
|
|
2099
|
+
isProfessionalObserver: z.boolean().optional().describe("Whether the witness is a trained observer (pilot, astronomer, military)."),
|
|
2100
|
+
hasAviationExperience: z.boolean().optional().describe("Whether the witness has aviation experience."),
|
|
2101
|
+
hasMilitaryExperience: z.boolean().optional().describe("Whether the witness has military experience."),
|
|
2102
|
+
hasScientificBackground: z.boolean().optional().describe("Whether the witness has a scientific background."),
|
|
2103
|
+
hasPriorUAPKnowledge: z.boolean().optional().describe("Whether the witness had prior knowledge of or interest in UAP before the observation."),
|
|
2104
|
+
wasSkepticPrior: z.boolean().optional().describe("Whether the witness was a skeptic before the observation."),
|
|
2105
|
+
underOathTestimony: z.boolean().optional().describe("Whether the testimony was given under oath."),
|
|
2106
|
+
polygraphAdministered: z.boolean().optional().describe("Whether a polygraph was administered."),
|
|
2107
|
+
polygraphPassed: z.boolean().optional().describe("Whether the witness passed the polygraph."),
|
|
2108
|
+
consistentTestimony: z.boolean().optional().describe("Whether the account has remained consistent across retellings."),
|
|
2109
|
+
willingToBeIdentified: z.boolean().optional().describe("Whether the witness is willing to be publicly identified."),
|
|
2110
|
+
notes: z.string().optional().describe("Free-text context about the credibility assessment.")
|
|
2111
|
+
}).meta({ id: "WitnessCredibility" }).describe("Structured assessment of a witness's credibility (rating, factors, detractors).");
|
|
2112
|
+
|
|
2113
|
+
// src/extensions/testimony/witness.ts
|
|
2114
|
+
var SecurityClearanceSchema = z.enum(["none", "confidential", "secret", "top_secret", "sci", "unknown"]).describe("Security clearance level held by a witness.");
|
|
2115
|
+
var WitnessSchema = z.object({
|
|
2116
|
+
witnessId: z.string().describe("Stable unique identifier for this witness."),
|
|
2117
|
+
category: WitnessCategorySchema,
|
|
2118
|
+
anonymous: z.boolean().describe("Whether the witness\u2019s identity is withheld."),
|
|
2119
|
+
publicName: z.string().optional().describe("Witness\u2019s name as publicly known, when not anonymous."),
|
|
2120
|
+
pseudonym: z.string().optional().describe("Pseudonym used when the witness is anonymous."),
|
|
2121
|
+
role: z.string().optional().describe('Witness\u2019s role at the time (e.g. "F/A-18F pilot", "radar operator").'),
|
|
2122
|
+
organization: z.string().optional().describe("Organization the witness belonged to at the time."),
|
|
2123
|
+
experienceYears: z.number().optional().describe("Years of relevant professional experience."),
|
|
2124
|
+
securityClearance: SecurityClearanceSchema.optional(),
|
|
2125
|
+
credibility: WitnessCredibilitySchema.optional(),
|
|
2126
|
+
statementSummary: z.string().optional().describe("Brief summary of what the witness reported."),
|
|
2127
|
+
interviewAvailable: z.boolean().optional().describe("Whether a recorded interview with the witness exists."),
|
|
2128
|
+
writtenReportAvailable: z.boolean().optional().describe("Whether a written report from the witness exists.")
|
|
2129
|
+
}).meta({ id: "Witness" }).describe("A person who reported or corroborated an observation.");
|
|
2130
|
+
var TemporalCertaintySchema = z.enum(["exact", "approximate", "estimated", "unknown"]).describe("Confidence in a date or time value \u2014 the single certainty scale for all temporal values.");
|
|
2131
|
+
var ChainOfCustodySchema = z.enum([
|
|
2132
|
+
"verified",
|
|
2133
|
+
"partial",
|
|
2134
|
+
"unverified",
|
|
2135
|
+
"government_held",
|
|
2136
|
+
"private_held",
|
|
2137
|
+
"lost",
|
|
2138
|
+
"destroyed",
|
|
2139
|
+
"classified",
|
|
2140
|
+
"unknown"
|
|
2141
|
+
]).describe("Custody status of an evidence item.");
|
|
2142
|
+
var CustodyActionSchema = z.enum([
|
|
2143
|
+
"creation",
|
|
2144
|
+
"collection",
|
|
2145
|
+
"transfer",
|
|
2146
|
+
"storage",
|
|
2147
|
+
"analysis",
|
|
2148
|
+
"release",
|
|
2149
|
+
"classification",
|
|
2150
|
+
"destruction",
|
|
2151
|
+
"loss",
|
|
2152
|
+
"recovery",
|
|
2153
|
+
"other"
|
|
2154
|
+
]).describe("An action recorded in a chain-of-custody entry.");
|
|
2155
|
+
var CustodyEntrySchema = z.object({
|
|
2156
|
+
entryId: z.string().describe("Stable unique identifier for this custody entry."),
|
|
2157
|
+
date: z.string().describe("When the custody event occurred (ISO date)."),
|
|
2158
|
+
action: CustodyActionSchema,
|
|
2159
|
+
from: z.string().optional().describe("Party that held the evidence before this event."),
|
|
2160
|
+
to: z.string().optional().describe("Party that held the evidence after this event."),
|
|
2161
|
+
location: z.string().optional().describe("Where the custody event took place."),
|
|
2162
|
+
reference: z.string().optional().describe("Document or record substantiating the event (e.g. transfer receipt, log entry)."),
|
|
2163
|
+
notes: z.string().optional().describe("Free-text context about the event.")
|
|
2164
|
+
}).meta({ id: "CustodyEntry" }).describe("A single custody event for an evidence item.");
|
|
2165
|
+
z.object({
|
|
2166
|
+
evidenceId: z.string().describe("Identifier of the evidence item this custody history belongs to."),
|
|
2167
|
+
status: ChainOfCustodySchema,
|
|
2168
|
+
entries: z.array(CustodyEntrySchema)
|
|
2169
|
+
}).meta({ id: "ChainOfCustodyRecord" }).describe("The full custody history for a piece of evidence.");
|
|
2170
|
+
|
|
2171
|
+
// src/extensions/testimony/statement.ts
|
|
2172
|
+
var TestimonyContextSchema = z.enum([
|
|
2173
|
+
"sworn_affidavit",
|
|
2174
|
+
"congressional_testimony",
|
|
2175
|
+
"deposition",
|
|
2176
|
+
"official_interview",
|
|
2177
|
+
"written_statement",
|
|
2178
|
+
"recorded_interview",
|
|
2179
|
+
"informal_account",
|
|
2180
|
+
"anonymous_tip",
|
|
2181
|
+
"whistleblower_disclosure"
|
|
2182
|
+
]).describe("The setting in which testimony was given.");
|
|
2183
|
+
var TestimonyDateSchema = z.object({
|
|
2184
|
+
date: z.string().describe("When the testimony was given (ISO date)."),
|
|
2185
|
+
certainty: TemporalCertaintySchema
|
|
2186
|
+
}).meta({ id: "TestimonyDate" }).describe("When testimony was given, with its certainty.");
|
|
2187
|
+
z.object({
|
|
2188
|
+
statementId: z.string().describe('Stable id, addressable by a claim `evidenceRef` ("testimony:<statementId>").'),
|
|
2189
|
+
witness: WitnessSchema,
|
|
2190
|
+
context: TestimonyContextSchema,
|
|
2191
|
+
date: TestimonyDateSchema,
|
|
2192
|
+
content: z.string().optional().describe("Full text of the statement, when available."),
|
|
2193
|
+
summary: z.string().optional().describe("Brief summary of what the statement asserts."),
|
|
2194
|
+
sourceDocument: SourceReferenceSchema.optional(),
|
|
2195
|
+
chainOfCustody: ChainOfCustodySchema.optional(),
|
|
2196
|
+
additionalEvidenceIds: z.array(z.string()).optional().describe("Ids of other evidence items the statement references or supports.")
|
|
2197
|
+
}).meta({ id: "TestimonyStatement" }).describe("A single witness statement, its context, and supporting documentation.");
|
|
2198
|
+
|
|
2199
|
+
// src/experimental/v2/research-entities-schema.ts
|
|
2200
|
+
var text6 = z.string().min(1).regex(/\S/);
|
|
2201
|
+
var id5 = z.string().regex(/^[A-Za-z0-9][A-Za-z0-9._-]*(?![\s\S])/);
|
|
2202
|
+
var sourceRef3 = z.string().regex(/^(source|product):[A-Za-z0-9][A-Za-z0-9._-]*(?![\s\S])/);
|
|
2203
|
+
var provenance3 = SourceProvenanceSchema.extend({ sourceRef: sourceRef3 });
|
|
2204
|
+
var RESEARCH_ENTITIES_SCHEMA_ID = "urn:disclosureos:experimental:research-entities:0.1.0";
|
|
2205
|
+
function values2(schema) {
|
|
2206
|
+
return z.array(
|
|
2207
|
+
z.strictObject({
|
|
2208
|
+
id: id5.describe(
|
|
2209
|
+
"Assertion identity within this entity, independent of array order."
|
|
2210
|
+
),
|
|
2211
|
+
content: z.union([
|
|
2212
|
+
z.strictObject({
|
|
2213
|
+
state: z.literal("known"),
|
|
2214
|
+
value: schema,
|
|
2215
|
+
provenance: provenance3,
|
|
2216
|
+
originalWording: text6.optional()
|
|
2217
|
+
}),
|
|
2218
|
+
z.strictObject({
|
|
2219
|
+
state: z.literal("approximate"),
|
|
2220
|
+
value: schema,
|
|
2221
|
+
precision: text6,
|
|
2222
|
+
provenance: provenance3,
|
|
2223
|
+
originalWording: text6.optional()
|
|
2224
|
+
}),
|
|
2225
|
+
z.strictObject({
|
|
2226
|
+
state: z.literal("unknown"),
|
|
2227
|
+
reason: z.enum(["not_recorded", "not_collected", "unavailable"])
|
|
2228
|
+
}),
|
|
2229
|
+
z.strictObject({ state: z.literal("redacted"), reason: text6 }),
|
|
2230
|
+
z.strictObject({
|
|
2231
|
+
state: z.literal("unmapped"),
|
|
2232
|
+
originalWording: text6,
|
|
2233
|
+
provenance: provenance3
|
|
2234
|
+
})
|
|
2235
|
+
])
|
|
2236
|
+
})
|
|
2237
|
+
).min(1).optional();
|
|
2238
|
+
}
|
|
2239
|
+
var timeContextReference = ContextReferenceSchema.extend({
|
|
2240
|
+
target: z.union([
|
|
2241
|
+
ContextTargetSchema.options[0],
|
|
2242
|
+
ContextTargetSchema.options[5]
|
|
2243
|
+
])
|
|
2244
|
+
}).describe(
|
|
2245
|
+
"Temporal or event context for a qualification, not an arbitrary object attribute."
|
|
2246
|
+
);
|
|
2247
|
+
var relevantTime = z.union([
|
|
2248
|
+
z.strictObject({ kind: z.literal("calendar"), value: EventTimeValueSchema }),
|
|
2249
|
+
z.strictObject({
|
|
2250
|
+
kind: z.literal("context"),
|
|
2251
|
+
reference: timeContextReference
|
|
2252
|
+
}),
|
|
2253
|
+
z.strictObject({ kind: z.literal("unknown"), reason: text6 })
|
|
2254
|
+
]);
|
|
2255
|
+
var qualification = (value) => z.strictObject({ value, relevantTime });
|
|
2256
|
+
var ResearchWitnessFields = {
|
|
2257
|
+
publicIdentity: values2(
|
|
2258
|
+
z.discriminatedUnion("kind", [
|
|
2259
|
+
z.strictObject({ kind: z.literal("public_name"), display: text6 }),
|
|
2260
|
+
z.strictObject({ kind: z.literal("pseudonym"), display: text6 }),
|
|
2261
|
+
z.strictObject({ kind: z.literal("withheld"), display: text6 })
|
|
2262
|
+
])
|
|
2263
|
+
),
|
|
2264
|
+
anonymous: values2(z.boolean()),
|
|
2265
|
+
willingToBeIdentified: values2(z.boolean()),
|
|
2266
|
+
category: values2(qualification(WitnessCategorySchema)),
|
|
2267
|
+
role: values2(qualification(text6)),
|
|
2268
|
+
organization: values2(qualification(text6)),
|
|
2269
|
+
experienceYears: values2(qualification(z.number().min(0))),
|
|
2270
|
+
securityClearance: values2(qualification(SecurityClearanceSchema)),
|
|
2271
|
+
isProfessionalObserver: values2(qualification(z.boolean())),
|
|
2272
|
+
hasAviationExperience: values2(qualification(z.boolean())),
|
|
2273
|
+
hasMilitaryExperience: values2(qualification(z.boolean())),
|
|
2274
|
+
hasScientificBackground: values2(qualification(z.boolean())),
|
|
2275
|
+
hasPriorUAPKnowledge: values2(qualification(z.boolean())),
|
|
2276
|
+
wasSkepticPrior: values2(qualification(z.boolean())),
|
|
2277
|
+
description: values2(text6)
|
|
2278
|
+
};
|
|
2279
|
+
var ResearchAccountFields = {
|
|
2280
|
+
speakerWitnessIds: values2(z.array(id5).min(1)),
|
|
2281
|
+
recorder: values2(text6),
|
|
2282
|
+
context: values2(TestimonyContextSchema),
|
|
2283
|
+
recordedTime: values2(EventTimeValueSchema),
|
|
2284
|
+
dateCertainty: values2(
|
|
2285
|
+
z.enum(["exact", "approximate", "estimated", "unknown"])
|
|
2286
|
+
),
|
|
2287
|
+
eventContext: values2(ContextReferenceSchema),
|
|
2288
|
+
content: values2(text6),
|
|
2289
|
+
summary: values2(z.strictObject({ text: text6, summarizedBy: text6 })),
|
|
2290
|
+
sourceDocument: values2(sourceRef3),
|
|
2291
|
+
interviewAvailable: values2(z.boolean()),
|
|
2292
|
+
writtenReportAvailable: values2(z.boolean()),
|
|
2293
|
+
underOath: values2(z.boolean()),
|
|
2294
|
+
custodyStatus: values2(ChainOfCustodySchema),
|
|
2295
|
+
supportRefs: values2(z.array(sourceRef3).min(1))
|
|
2296
|
+
};
|
|
2297
|
+
var ResearchProcedureFields = {
|
|
2298
|
+
procedureType: values2(z.literal("polygraph")),
|
|
2299
|
+
witnessId: values2(id5),
|
|
2300
|
+
accountId: values2(id5),
|
|
2301
|
+
administered: values2(z.boolean()),
|
|
2302
|
+
passed: values2(z.boolean()),
|
|
2303
|
+
performedAt: values2(EventTimeValueSchema),
|
|
2304
|
+
context: values2(text6),
|
|
2305
|
+
sourceDocument: values2(sourceRef3)
|
|
2306
|
+
};
|
|
2307
|
+
var ResearchWitnessGroupFields = {
|
|
2308
|
+
witnessIds: values2(z.array(id5).min(1)),
|
|
2309
|
+
reportedCount: values2(z.number().int().min(0)),
|
|
2310
|
+
categories: values2(z.array(WitnessCategorySchema).min(1)),
|
|
2311
|
+
militaryWitnesses: values2(z.boolean()),
|
|
2312
|
+
aviationWitnesses: values2(z.boolean()),
|
|
2313
|
+
professionalObservers: values2(z.boolean()),
|
|
2314
|
+
descriptions: values2(z.array(text6).min(1))
|
|
2315
|
+
};
|
|
2316
|
+
for (const fields of [
|
|
2317
|
+
ResearchWitnessFields,
|
|
2318
|
+
ResearchAccountFields,
|
|
2319
|
+
ResearchProcedureFields,
|
|
2320
|
+
ResearchWitnessGroupFields
|
|
2321
|
+
])
|
|
2322
|
+
for (const [key2, schema] of Object.entries(fields))
|
|
2323
|
+
fields[key2] = schema.describe(
|
|
2324
|
+
`Sourced ${key2.replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase()} assertions. Alternatives and unknowns are retained; supplied does not mean verified.`
|
|
2325
|
+
);
|
|
2326
|
+
function entity2(kind, fields) {
|
|
2327
|
+
return z.strictObject({
|
|
2328
|
+
kind: z.literal(kind),
|
|
2329
|
+
id: id5,
|
|
2330
|
+
fields: z.strictObject(fields)
|
|
2331
|
+
});
|
|
2332
|
+
}
|
|
2333
|
+
var ResearchEntitySchema = z.discriminatedUnion("kind", [
|
|
2334
|
+
entity2("witness", ResearchWitnessFields),
|
|
2335
|
+
entity2("account", ResearchAccountFields),
|
|
2336
|
+
entity2("procedure", ResearchProcedureFields),
|
|
2337
|
+
entity2("witness_group", ResearchWitnessGroupFields)
|
|
2338
|
+
]);
|
|
2339
|
+
var ResearchEntitiesSchema = z.strictObject({
|
|
2340
|
+
kind: z.literal("research_entities"),
|
|
2341
|
+
schemaVersion: z.literal("0.1.0"),
|
|
2342
|
+
id: id5,
|
|
2343
|
+
observationRef: ObservationSnapshotRefSchema,
|
|
2344
|
+
contextRefs: z.array(
|
|
2345
|
+
DocumentSnapshotRefSchema.extend({
|
|
2346
|
+
schemaId: z.literal(OBSERVATION_CONTEXT_SCHEMA_ID)
|
|
2347
|
+
})
|
|
2348
|
+
),
|
|
2349
|
+
recordedAt: instantString,
|
|
2350
|
+
recordedBy: text6,
|
|
2351
|
+
entities: z.array(ResearchEntitySchema).min(1)
|
|
2352
|
+
}).describe(
|
|
2353
|
+
"Public witness, account, procedure and aggregate declarations. Private identity mappings and contact fields belong outside this exchange document. No consent or credibility is inferred."
|
|
2354
|
+
);
|
|
2355
|
+
function target2(kind, fields) {
|
|
2356
|
+
return z.strictObject({
|
|
2357
|
+
kind: z.literal(kind),
|
|
2358
|
+
id: id5,
|
|
2359
|
+
field: z.enum(Object.keys(fields)).optional()
|
|
2360
|
+
});
|
|
2361
|
+
}
|
|
2362
|
+
var ResearchEntityTargetSchema = z.discriminatedUnion("kind", [
|
|
2363
|
+
target2("witness", ResearchWitnessFields),
|
|
2364
|
+
target2("account", ResearchAccountFields),
|
|
2365
|
+
target2("procedure", ResearchProcedureFields),
|
|
2366
|
+
target2("witness_group", ResearchWitnessGroupFields)
|
|
2367
|
+
]);
|
|
2368
|
+
var ResearchEntityReferenceSchema = z.strictObject({
|
|
2369
|
+
document: DocumentSnapshotRefSchema.extend({
|
|
2370
|
+
schemaId: z.literal(RESEARCH_ENTITIES_SCHEMA_ID)
|
|
2371
|
+
}),
|
|
2372
|
+
target: ResearchEntityTargetSchema
|
|
2373
|
+
});
|
|
2374
|
+
var ResearchEntityAssertionReferenceSchema = ResearchEntityReferenceSchema.extend({ assertionId: id5 });
|
|
2375
|
+
function researchEntitiesJsonSchema() {
|
|
2376
|
+
return {
|
|
2377
|
+
...z.toJSONSchema(ResearchEntitiesSchema, {
|
|
2378
|
+
target: "draft-2020-12",
|
|
2379
|
+
reused: "ref"
|
|
2380
|
+
}),
|
|
2381
|
+
$id: RESEARCH_ENTITIES_SCHEMA_ID
|
|
2382
|
+
};
|
|
2383
|
+
}
|
|
2384
|
+
|
|
2385
|
+
// src/experimental/v2/research-entities.ts
|
|
2386
|
+
function researchEntityAssertions(entity3) {
|
|
2387
|
+
return Object.entries(entity3.fields).flatMap(
|
|
2388
|
+
([field, list]) => (list ?? []).map((assertion) => ({
|
|
2389
|
+
field,
|
|
2390
|
+
assertion
|
|
2391
|
+
}))
|
|
2392
|
+
);
|
|
2393
|
+
}
|
|
2394
|
+
function researchEntityContextReferences(entity3) {
|
|
2395
|
+
return researchEntityAssertions(entity3).flatMap(({ field, assertion }) => {
|
|
2396
|
+
const value = assertion.content.value;
|
|
2397
|
+
if (field === "eventContext" && value)
|
|
2398
|
+
return [value];
|
|
2399
|
+
return value?.relevantTime?.kind === "context" ? [value.relevantTime.reference] : [];
|
|
2400
|
+
});
|
|
2401
|
+
}
|
|
2402
|
+
function parseResearchEntities(input) {
|
|
2403
|
+
const parsed = ResearchEntitiesSchema.safeParse(input);
|
|
2404
|
+
const contract = {
|
|
2405
|
+
schemaId: RESEARCH_ENTITIES_SCHEMA_ID,
|
|
2406
|
+
rulesetVersion: "0.1.0"
|
|
2407
|
+
};
|
|
2408
|
+
if (!parsed.success)
|
|
2409
|
+
return {
|
|
2410
|
+
success: false,
|
|
2411
|
+
contract,
|
|
2412
|
+
checks: {
|
|
2413
|
+
structural: "failed",
|
|
2414
|
+
semantic: "not_checked",
|
|
2415
|
+
profile: "not_checked",
|
|
2416
|
+
external: "not_checked"
|
|
2417
|
+
},
|
|
2418
|
+
uncheckedRefs: [],
|
|
2419
|
+
issues: parsed.error.issues.map((i) => ({
|
|
2420
|
+
code: "STRUCT.VALUE",
|
|
2421
|
+
stage: "structural",
|
|
2422
|
+
pointer: "/" + i.path.join("/"),
|
|
2423
|
+
message: i.message
|
|
2424
|
+
}))
|
|
2425
|
+
};
|
|
2426
|
+
const data = parsed.data, issues = [];
|
|
2427
|
+
const problem = (code, pointer6, message) => issues.push({ code, stage: "semantic", pointer: pointer6, message });
|
|
2428
|
+
const snapshots = new Set(data.contextRefs.map((r) => JSON.stringify(r)));
|
|
2429
|
+
if (snapshots.size !== data.contextRefs.length)
|
|
2430
|
+
problem(
|
|
2431
|
+
"REF.UNIQUE_ID",
|
|
2432
|
+
"/contextRefs",
|
|
2433
|
+
"Context snapshot references repeat."
|
|
2434
|
+
);
|
|
2435
|
+
const unchecked = /* @__PURE__ */ new Set([
|
|
2436
|
+
data.observationRef.sha256,
|
|
2437
|
+
...data.contextRefs.map((r) => r.sha256)
|
|
2438
|
+
]);
|
|
2439
|
+
const identities = /* @__PURE__ */ new Set();
|
|
2440
|
+
for (const [i, e] of data.entities.entries()) {
|
|
2441
|
+
const key2 = `${e.kind}:${e.id}`;
|
|
2442
|
+
if (identities.has(key2))
|
|
2443
|
+
problem(
|
|
2444
|
+
"REF.UNIQUE_ID",
|
|
2445
|
+
`/entities/${i}/id`,
|
|
2446
|
+
"Entity identity repeats within its kind."
|
|
2447
|
+
);
|
|
2448
|
+
identities.add(key2);
|
|
2449
|
+
}
|
|
2450
|
+
function time(v, p) {
|
|
2451
|
+
const found = [];
|
|
2452
|
+
checkTime(v, p, found);
|
|
2453
|
+
found.forEach((i) => problem(i.code, i.pointer, i.message));
|
|
2454
|
+
}
|
|
2455
|
+
time(
|
|
2456
|
+
{ kind: "instant", value: data.recordedAt},
|
|
2457
|
+
"/recordedAt"
|
|
2458
|
+
);
|
|
2459
|
+
for (const [i, e] of data.entities.entries()) {
|
|
2460
|
+
const ep = `/entities/${i}`, ids = /* @__PURE__ */ new Set();
|
|
2461
|
+
for (const { field, assertion: a } of researchEntityAssertions(e)) {
|
|
2462
|
+
const p = `${ep}/fields/${field}`;
|
|
2463
|
+
if (ids.has(a.id))
|
|
2464
|
+
problem("REF.UNIQUE_ID", p, "Assertion IDs repeat within this entity.");
|
|
2465
|
+
ids.add(a.id);
|
|
2466
|
+
const prov = a.content.provenance;
|
|
2467
|
+
if (prov) {
|
|
2468
|
+
unchecked.add(prov.sourceRef);
|
|
2469
|
+
if (prov.locator?.kind === "time_range" && prov.locator.endSeconds < prov.locator.startSeconds)
|
|
2470
|
+
problem("TIME.INTERVAL", p, "Source locator end precedes its start.");
|
|
2471
|
+
}
|
|
2472
|
+
const value = a.content.value;
|
|
2473
|
+
if (value === void 0) continue;
|
|
2474
|
+
if (field === "recordedTime" || field === "performedAt")
|
|
2475
|
+
time(value, p);
|
|
2476
|
+
const relevant = value.relevantTime;
|
|
2477
|
+
if (relevant?.kind === "calendar") time(relevant.value, p);
|
|
2478
|
+
const targetKind = field === "speakerWitnessIds" || field === "witnessIds" || field === "witnessId" ? "witness" : field === "accountId" ? "account" : void 0;
|
|
2479
|
+
if (targetKind) {
|
|
2480
|
+
const refs = Array.isArray(value) ? value : [value];
|
|
2481
|
+
if (new Set(refs).size !== refs.length)
|
|
2482
|
+
problem("REF.UNIQUE_ID", p, "Typed local links repeat.");
|
|
2483
|
+
for (const id7 of refs)
|
|
2484
|
+
if (!identities.has(`${targetKind}:${id7}`))
|
|
2485
|
+
problem("REF.ENTITY", p, "Typed local entity does not exist.");
|
|
2486
|
+
}
|
|
2487
|
+
if (field === "sourceDocument") unchecked.add(value);
|
|
2488
|
+
if (field === "supportRefs") {
|
|
2489
|
+
const refs = value;
|
|
2490
|
+
if (new Set(refs).size !== refs.length)
|
|
2491
|
+
problem("REF.UNIQUE_ID", p, "Support references repeat.");
|
|
2492
|
+
refs.forEach((r) => unchecked.add(r));
|
|
2493
|
+
}
|
|
2494
|
+
}
|
|
2495
|
+
for (const ref2 of researchEntityContextReferences(e))
|
|
2496
|
+
if (!snapshots.has(JSON.stringify(ref2.document)))
|
|
2497
|
+
problem(
|
|
2498
|
+
"REF.LOCAL_RESOLUTION",
|
|
2499
|
+
ep,
|
|
2500
|
+
"Context reference must select a declared snapshot."
|
|
2501
|
+
);
|
|
2502
|
+
}
|
|
2503
|
+
const validation = {
|
|
2504
|
+
contract,
|
|
2505
|
+
issues,
|
|
2506
|
+
uncheckedRefs: [...unchecked],
|
|
2507
|
+
checks: {
|
|
2508
|
+
structural: "passed",
|
|
2509
|
+
semantic: issues.length ? "failed" : "passed",
|
|
2510
|
+
profile: "not_checked",
|
|
2511
|
+
external: "not_checked"
|
|
2512
|
+
}
|
|
2513
|
+
};
|
|
2514
|
+
return issues.length ? { ...validation, success: false } : { ...validation, success: true, data };
|
|
2515
|
+
}
|
|
2516
|
+
var text7 = z.string().min(1).regex(/\S/, "must contain non-whitespace text");
|
|
2517
|
+
var id6 = z.string().regex(/^[A-Za-z0-9][A-Za-z0-9._-]*(?![\s\S])/);
|
|
2518
|
+
var claimRef3 = z.string().regex(/^claim:[A-Za-z0-9][A-Za-z0-9._-]*(?![\s\S])/);
|
|
2519
|
+
var inputRef3 = z.string().regex(
|
|
2520
|
+
/^(?:claim|source|product|assertion|measurement):[A-Za-z0-9][A-Za-z0-9._-]*(?![\s\S])/
|
|
2521
|
+
);
|
|
2522
|
+
var ResearchClaimSubjectSchema = z.discriminatedUnion("kind", [
|
|
2523
|
+
z.strictObject({ kind: z.literal("observation") }),
|
|
2524
|
+
z.strictObject({
|
|
2525
|
+
kind: z.literal("entity"),
|
|
2526
|
+
reference: ResearchEntityReferenceSchema
|
|
2527
|
+
}),
|
|
2528
|
+
z.strictObject({
|
|
2529
|
+
kind: z.literal("context"),
|
|
2530
|
+
reference: ContextReferenceSchema
|
|
2531
|
+
}),
|
|
2532
|
+
z.strictObject({ kind: z.literal("measurement"), measurementId: id6 })
|
|
2533
|
+
]);
|
|
2534
|
+
var WitnessReviewSchema = z.strictObject({
|
|
2535
|
+
rating: ConfidenceLevelSchema.optional(),
|
|
2536
|
+
factors: z.array(CredibilityFactorSchema).optional().describe(
|
|
2537
|
+
"Reviewer-selected factor labels; no built-in weighting or validation of their truth."
|
|
2538
|
+
),
|
|
2539
|
+
detractors: z.array(CredibilityDetractorSchema).optional().describe(
|
|
2540
|
+
"Retained vocabulary for attributable reviews. Anonymity never adds a penalty automatically."
|
|
2541
|
+
),
|
|
2542
|
+
consistentTestimony: z.enum(["consistent", "inconsistent", "unknown"]).optional(),
|
|
2543
|
+
multipleIndependent: z.enum(["independent", "not_independent", "unknown"]).optional(),
|
|
2544
|
+
notes: text7.optional()
|
|
2545
|
+
}).describe(
|
|
2546
|
+
"Attributable interpretation, separate from sourced qualifications; requires explicit inputs."
|
|
2547
|
+
);
|
|
2548
|
+
var common3 = {
|
|
2549
|
+
id: id6,
|
|
2550
|
+
recordedAt: instantString,
|
|
2551
|
+
topic: text7,
|
|
2552
|
+
subject: ResearchClaimSubjectSchema,
|
|
2553
|
+
supersedes: z.array(claimRef3).min(1).optional()
|
|
2554
|
+
};
|
|
2555
|
+
var ResearchSourceStatementSchema = z.strictObject({
|
|
2556
|
+
...common3,
|
|
2557
|
+
kind: z.literal("source_assertion"),
|
|
2558
|
+
text: text7,
|
|
2559
|
+
reportedLevel: text7.optional(),
|
|
2560
|
+
provenance: ObservationAssertionSchema.options[0].shape.provenance
|
|
2561
|
+
});
|
|
2562
|
+
var assessment3 = {
|
|
2563
|
+
...common3,
|
|
2564
|
+
kind: z.literal("assessment"),
|
|
2565
|
+
inputRefs: z.array(inputRef3),
|
|
2566
|
+
contextInputRefs: z.array(ContextAssertionReferenceSchema).optional(),
|
|
2567
|
+
entityInputRefs: z.array(ResearchEntityAssertionReferenceSchema).optional(),
|
|
2568
|
+
rationale: text7
|
|
2569
|
+
};
|
|
2570
|
+
var ResearchUnassessedClaimSchema = z.strictObject({
|
|
2571
|
+
...assessment3,
|
|
2572
|
+
status: z.literal("unassessed")
|
|
2573
|
+
});
|
|
2574
|
+
var ResearchAssessedClaimSchema = z.strictObject({
|
|
2575
|
+
...assessment3,
|
|
2576
|
+
status: z.literal("assessed"),
|
|
2577
|
+
outcome: z.enum(["reported", "confirmed", "absent", "inconclusive"]),
|
|
2578
|
+
evaluatedBy: text7,
|
|
2579
|
+
evaluatedAt: instantString,
|
|
2580
|
+
methodRef: z.string().regex(/^method:[A-Za-z0-9][A-Za-z0-9._-]*(?![\s\S])/),
|
|
2581
|
+
methodVersion: text7,
|
|
2582
|
+
confidence: z.number().min(0).max(1).optional(),
|
|
2583
|
+
witnessReview: WitnessReviewSchema.optional()
|
|
2584
|
+
});
|
|
2585
|
+
var ResearchHistoricalClaimSchema = z.union([
|
|
2586
|
+
ResearchSourceStatementSchema,
|
|
2587
|
+
ResearchUnassessedClaimSchema,
|
|
2588
|
+
ResearchAssessedClaimSchema
|
|
2589
|
+
]);
|
|
2590
|
+
var RESEARCH_CLAIM_HISTORY_SCHEMA_ID = "urn:disclosureos:experimental:claim-history:0.3.0";
|
|
2591
|
+
var RESEARCH_CLAIM_HISTORY_RULESET_VERSION = "0.3.0";
|
|
2592
|
+
var ResearchClaimHistorySchema = z.strictObject({
|
|
2593
|
+
kind: z.literal("claim_history"),
|
|
2594
|
+
schemaVersion: z.literal("0.3.0"),
|
|
2595
|
+
id: id6,
|
|
2596
|
+
contextRefs: z.array(
|
|
2597
|
+
DocumentSnapshotRefSchema.extend({
|
|
2598
|
+
schemaId: z.literal(OBSERVATION_CONTEXT_SCHEMA_ID)
|
|
2599
|
+
})
|
|
2600
|
+
),
|
|
2601
|
+
entityRefs: z.array(
|
|
2602
|
+
DocumentSnapshotRefSchema.extend({
|
|
2603
|
+
schemaId: z.literal(RESEARCH_ENTITIES_SCHEMA_ID)
|
|
2604
|
+
})
|
|
2605
|
+
),
|
|
2606
|
+
observation: ExperimentalObservationSchema,
|
|
2607
|
+
claims: z.array(ResearchHistoricalClaimSchema),
|
|
2608
|
+
extensions: ExperimentalObservationSchema.shape.extensions
|
|
2609
|
+
});
|
|
2610
|
+
function researchClaimHistoryJsonSchema() {
|
|
2611
|
+
return {
|
|
2612
|
+
...z.toJSONSchema(ResearchClaimHistorySchema, {
|
|
2613
|
+
target: "draft-2020-12",
|
|
2614
|
+
reused: "ref"
|
|
2615
|
+
}),
|
|
2616
|
+
$id: RESEARCH_CLAIM_HISTORY_SCHEMA_ID
|
|
2617
|
+
};
|
|
2618
|
+
}
|
|
2619
|
+
|
|
2620
|
+
// src/experimental/v2/research-claim-history.ts
|
|
2621
|
+
var point3 = (value) => ({
|
|
2622
|
+
kind: "instant",
|
|
2623
|
+
value,
|
|
2624
|
+
timeScale: "UTC"
|
|
2625
|
+
});
|
|
2626
|
+
var pointer5 = (path) => path.map((p) => `/${String(p).replace(/~/g, "~0").replace(/\//g, "~1")}`).join("");
|
|
2627
|
+
function parseResearchClaimHistory(input) {
|
|
2628
|
+
const contract = {
|
|
2629
|
+
kind: "claim_history",
|
|
2630
|
+
schemaId: RESEARCH_CLAIM_HISTORY_SCHEMA_ID,
|
|
2631
|
+
rulesetVersion: RESEARCH_CLAIM_HISTORY_RULESET_VERSION
|
|
2632
|
+
};
|
|
2633
|
+
const parsed = ResearchClaimHistorySchema.safeParse(input);
|
|
2634
|
+
if (!parsed.success)
|
|
2635
|
+
return {
|
|
2636
|
+
success: false,
|
|
2637
|
+
contract,
|
|
2638
|
+
checks: {
|
|
2639
|
+
structural: "failed",
|
|
2640
|
+
semantic: "not_checked",
|
|
2641
|
+
profile: "not_checked",
|
|
2642
|
+
external: "not_checked"
|
|
2643
|
+
},
|
|
2644
|
+
uncheckedRefs: [],
|
|
2645
|
+
issues: parsed.error.issues.map((issue) => ({
|
|
2646
|
+
code: "STRUCT.VALUE",
|
|
2647
|
+
stage: "structural",
|
|
2648
|
+
severity: "error",
|
|
2649
|
+
pointer: pointer5(issue.path),
|
|
2650
|
+
message: issue.message
|
|
2651
|
+
}))
|
|
2652
|
+
};
|
|
2653
|
+
const data = parsed.data;
|
|
2654
|
+
const observationResult = parseExperimentalObservation(data.observation);
|
|
2655
|
+
const issues = observationResult.issues.map(
|
|
2656
|
+
(issue) => ({ ...issue, pointer: `/observation${issue.pointer}` })
|
|
2657
|
+
);
|
|
2658
|
+
const problem = (code, path, message) => issues.push({
|
|
2659
|
+
code,
|
|
2660
|
+
stage: "semantic",
|
|
2661
|
+
severity: "error",
|
|
2662
|
+
pointer: path,
|
|
2663
|
+
message
|
|
2664
|
+
});
|
|
2665
|
+
const claims = /* @__PURE__ */ new Map();
|
|
2666
|
+
const graph = /* @__PURE__ */ new Map();
|
|
2667
|
+
const superseded = /* @__PURE__ */ new Set();
|
|
2668
|
+
const sources = new Map(
|
|
2669
|
+
data.observation.sources.map((item) => [`source:${item.id}`, item])
|
|
2670
|
+
);
|
|
2671
|
+
const products = new Map(
|
|
2672
|
+
data.observation.products.map((item) => [`product:${item.id}`, item])
|
|
2673
|
+
);
|
|
2674
|
+
const methods = new Map(
|
|
2675
|
+
data.observation.methods.map((item) => [`method:${item.id}`, item])
|
|
2676
|
+
);
|
|
2677
|
+
const measurements = new Set(
|
|
2678
|
+
data.observation.measurements.map((item) => `measurement:${item.id}`)
|
|
2679
|
+
);
|
|
2680
|
+
const available = /* @__PURE__ */ new Set([
|
|
2681
|
+
...sources.keys(),
|
|
2682
|
+
...products.keys(),
|
|
2683
|
+
...measurements,
|
|
2684
|
+
...data.observation.assertions.map((item) => `assertion:${item.id}`)
|
|
2685
|
+
]);
|
|
2686
|
+
for (const [i, claim] of data.claims.entries()) {
|
|
2687
|
+
const ref2 = `claim:${claim.id}`;
|
|
2688
|
+
if (claims.has(ref2))
|
|
2689
|
+
problem(
|
|
2690
|
+
"REF.UNIQUE_ID",
|
|
2691
|
+
`/claims/${i}/id`,
|
|
2692
|
+
"Duplicate claim ID; each revision must have its own ID."
|
|
2693
|
+
);
|
|
2694
|
+
else {
|
|
2695
|
+
claims.set(ref2, claim);
|
|
2696
|
+
graph.set(ref2, /* @__PURE__ */ new Set());
|
|
2697
|
+
available.add(ref2);
|
|
2698
|
+
}
|
|
2699
|
+
}
|
|
2700
|
+
function instant(value, path) {
|
|
2701
|
+
const local = [];
|
|
2702
|
+
checkTime(point3(value), path, local);
|
|
2703
|
+
for (const issue of local)
|
|
2704
|
+
problem(issue.code, issue.pointer, issue.message);
|
|
2705
|
+
}
|
|
2706
|
+
function resolve(ref2, path, owner) {
|
|
2707
|
+
if (!available.has(ref2))
|
|
2708
|
+
problem(
|
|
2709
|
+
"REF.LOCAL_RESOLUTION",
|
|
2710
|
+
path,
|
|
2711
|
+
`Undeclared local reference: ${ref2}`
|
|
2712
|
+
);
|
|
2713
|
+
else if (owner && claims.has(ref2)) graph.get(owner)?.add(ref2);
|
|
2714
|
+
}
|
|
2715
|
+
function refs(values3, path, owner) {
|
|
2716
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2717
|
+
for (const [i, ref2] of values3.entries()) {
|
|
2718
|
+
if (seen.has(ref2))
|
|
2719
|
+
problem("REF.UNIQUE_ID", `${path}/${i}`, "Reference is repeated.");
|
|
2720
|
+
seen.add(ref2);
|
|
2721
|
+
resolve(ref2, `${path}/${i}`, owner);
|
|
2722
|
+
}
|
|
2723
|
+
}
|
|
2724
|
+
const snapshots = new Set(data.contextRefs.map((r) => JSON.stringify(r)));
|
|
2725
|
+
if (snapshots.size !== data.contextRefs.length)
|
|
2726
|
+
problem(
|
|
2727
|
+
"REF.UNIQUE_ID",
|
|
2728
|
+
"/contextRefs",
|
|
2729
|
+
"Context snapshot references repeat."
|
|
2730
|
+
);
|
|
2731
|
+
for (const [i, claim] of data.claims.entries()) {
|
|
2732
|
+
const contextRefs = [
|
|
2733
|
+
...claim.subject.kind === "context" ? [claim.subject.reference] : [],
|
|
2734
|
+
...claim.kind === "assessment" ? claim.contextInputRefs ?? [] : []
|
|
2735
|
+
];
|
|
2736
|
+
for (const ref2 of contextRefs)
|
|
2737
|
+
if (!snapshots.has(JSON.stringify(ref2.document)))
|
|
2738
|
+
problem(
|
|
2739
|
+
"REF.LOCAL_RESOLUTION",
|
|
2740
|
+
`/claims/${i}`,
|
|
2741
|
+
"Context reference must select a declared snapshot."
|
|
2742
|
+
);
|
|
2743
|
+
if (claim.kind === "assessment" && new Set((claim.contextInputRefs ?? []).map((r) => JSON.stringify(r))).size !== (claim.contextInputRefs ?? []).length)
|
|
2744
|
+
problem(
|
|
2745
|
+
"REF.UNIQUE_ID",
|
|
2746
|
+
`/claims/${i}/contextInputRefs`,
|
|
2747
|
+
"Context inputs repeat."
|
|
2748
|
+
);
|
|
2749
|
+
}
|
|
2750
|
+
const entitySnapshots = new Set(
|
|
2751
|
+
data.entityRefs.map((r) => JSON.stringify(r))
|
|
2752
|
+
);
|
|
2753
|
+
if (entitySnapshots.size !== data.entityRefs.length)
|
|
2754
|
+
problem("REF.UNIQUE_ID", "/entityRefs", "Entity snapshots repeat.");
|
|
2755
|
+
for (const [i, claim] of data.claims.entries()) {
|
|
2756
|
+
const refs2 = [
|
|
2757
|
+
...claim.subject.kind === "entity" ? [claim.subject.reference] : [],
|
|
2758
|
+
...claim.kind === "assessment" ? claim.entityInputRefs ?? [] : []
|
|
2759
|
+
];
|
|
2760
|
+
for (const ref2 of refs2)
|
|
2761
|
+
if (!entitySnapshots.has(JSON.stringify(ref2.document)))
|
|
2762
|
+
problem(
|
|
2763
|
+
"REF.LOCAL_RESOLUTION",
|
|
2764
|
+
`/claims/${i}`,
|
|
2765
|
+
"Entity reference must select a declared snapshot."
|
|
2766
|
+
);
|
|
2767
|
+
if (claim.kind === "assessment") {
|
|
2768
|
+
if (new Set((claim.entityInputRefs ?? []).map((r) => JSON.stringify(r))).size !== (claim.entityInputRefs ?? []).length)
|
|
2769
|
+
problem(
|
|
2770
|
+
"REF.UNIQUE_ID",
|
|
2771
|
+
`/claims/${i}/entityInputRefs`,
|
|
2772
|
+
"Entity inputs repeat."
|
|
2773
|
+
);
|
|
2774
|
+
if (claim.status === "assessed" && claim.witnessReview) {
|
|
2775
|
+
if (claim.subject.kind !== "entity" || !["witness", "account", "witness_group", "procedure"].includes(
|
|
2776
|
+
claim.subject.reference.target.kind
|
|
2777
|
+
))
|
|
2778
|
+
problem(
|
|
2779
|
+
"CLAIM.SUPERSESSION_SCOPE",
|
|
2780
|
+
`/claims/${i}/witnessReview`,
|
|
2781
|
+
"Witness review requires a typed research-entity subject."
|
|
2782
|
+
);
|
|
2783
|
+
if (claim.inputRefs.length + (claim.entityInputRefs?.length ?? 0) + (claim.contextInputRefs?.length ?? 0) === 0)
|
|
2784
|
+
problem(
|
|
2785
|
+
"REF.LOCAL_RESOLUTION",
|
|
2786
|
+
`/claims/${i}/witnessReview`,
|
|
2787
|
+
"Witness review requires explicit inputs."
|
|
2788
|
+
);
|
|
2789
|
+
}
|
|
2790
|
+
}
|
|
2791
|
+
}
|
|
2792
|
+
for (const [i, claim] of data.claims.entries()) {
|
|
2793
|
+
const path = `/claims/${i}`;
|
|
2794
|
+
const owner = `claim:${claim.id}`;
|
|
2795
|
+
instant(claim.recordedAt, `${path}/recordedAt`);
|
|
2796
|
+
if (claim.subject.kind === "measurement")
|
|
2797
|
+
resolve(
|
|
2798
|
+
`measurement:${claim.subject.measurementId}`,
|
|
2799
|
+
`${path}/subject/measurementId`
|
|
2800
|
+
);
|
|
2801
|
+
if (claim.supersedes) {
|
|
2802
|
+
refs(claim.supersedes, `${path}/supersedes`, owner);
|
|
2803
|
+
for (const [j, ref2] of claim.supersedes.entries()) {
|
|
2804
|
+
const previous = claims.get(ref2);
|
|
2805
|
+
if (!previous) continue;
|
|
2806
|
+
superseded.add(ref2);
|
|
2807
|
+
if (previous.kind !== claim.kind || previous.topic !== claim.topic || JSON.stringify(previous.subject) !== JSON.stringify(claim.subject)) {
|
|
2808
|
+
problem(
|
|
2809
|
+
"CLAIM.SUPERSESSION_SCOPE",
|
|
2810
|
+
`${path}/supersedes/${j}`,
|
|
2811
|
+
"A revision must retain the claim kind, topic, and subject. Record a different claim separately."
|
|
2812
|
+
);
|
|
2813
|
+
}
|
|
2814
|
+
if (previous.kind === "assessment" && previous.status === "assessed" && claim.kind === "assessment" && (claim.status !== "assessed" || previous.evaluatedBy !== claim.evaluatedBy)) {
|
|
2815
|
+
problem(
|
|
2816
|
+
"CLAIM.REVISION_ATTRIBUTION",
|
|
2817
|
+
`${path}/supersedes/${j}`,
|
|
2818
|
+
"An assessed revision must retain its evaluator; other evaluators record independent assessments."
|
|
2819
|
+
);
|
|
2820
|
+
}
|
|
2821
|
+
if (comparePoints(point3(previous.recordedAt), point3(claim.recordedAt)) > 0) {
|
|
2822
|
+
problem(
|
|
2823
|
+
"CLAIM.REVISION_ORDER",
|
|
2824
|
+
`${path}/recordedAt`,
|
|
2825
|
+
"A revision cannot be recorded before the statement it supersedes."
|
|
2826
|
+
);
|
|
2827
|
+
}
|
|
2828
|
+
}
|
|
2829
|
+
}
|
|
2830
|
+
if (claim.kind === "source_assertion") {
|
|
2831
|
+
resolve(claim.provenance.sourceRef, `${path}/provenance/sourceRef`);
|
|
2832
|
+
const source = sources.get(claim.provenance.sourceRef) ?? products.get(claim.provenance.sourceRef);
|
|
2833
|
+
if (source?.digest && claim.provenance.sourceDigest && source.digest.value !== claim.provenance.sourceDigest.value) {
|
|
2834
|
+
problem(
|
|
2835
|
+
"SOURCE.DIGEST_MISMATCH",
|
|
2836
|
+
`${path}/provenance/sourceDigest`,
|
|
2837
|
+
"Digest differs from the inventory declaration; neither is verified against bytes."
|
|
2838
|
+
);
|
|
2839
|
+
}
|
|
2840
|
+
const locator = claim.provenance.locator;
|
|
2841
|
+
if (locator?.kind === "time_range" && locator.endSeconds < locator.startSeconds)
|
|
2842
|
+
problem(
|
|
2843
|
+
"TIME.INTERVAL",
|
|
2844
|
+
`${path}/provenance/locator/endSeconds`,
|
|
2845
|
+
"Locator end precedes its start."
|
|
2846
|
+
);
|
|
2847
|
+
} else {
|
|
2848
|
+
refs(claim.inputRefs, `${path}/inputRefs`, owner);
|
|
2849
|
+
if (claim.status === "assessed") {
|
|
2850
|
+
instant(claim.evaluatedAt, `${path}/evaluatedAt`);
|
|
2851
|
+
if (comparePoints(point3(claim.evaluatedAt), point3(claim.recordedAt)) > 0)
|
|
2852
|
+
problem(
|
|
2853
|
+
"CLAIM.EVALUATION_ORDER",
|
|
2854
|
+
`${path}/evaluatedAt`,
|
|
2855
|
+
"Evaluation cannot occur after the assessment was recorded."
|
|
2856
|
+
);
|
|
2857
|
+
const method = methods.get(claim.methodRef);
|
|
2858
|
+
if (!method)
|
|
2859
|
+
problem(
|
|
2860
|
+
"REF.LOCAL_RESOLUTION",
|
|
2861
|
+
`${path}/methodRef`,
|
|
2862
|
+
"Assessment method is not declared in the Observation inventory."
|
|
2863
|
+
);
|
|
2864
|
+
else if (method.version !== claim.methodVersion)
|
|
2865
|
+
problem(
|
|
2866
|
+
"METHOD.VERSION_MISMATCH",
|
|
2867
|
+
`${path}/methodVersion`,
|
|
2868
|
+
"Assessment method version differs from its inventory declaration."
|
|
2869
|
+
);
|
|
2870
|
+
}
|
|
2871
|
+
}
|
|
2872
|
+
}
|
|
2873
|
+
const indegrees = new Map([...graph.keys()].map((ref2) => [ref2, 0]));
|
|
2874
|
+
for (const edges of graph.values())
|
|
2875
|
+
for (const ref2 of edges) indegrees.set(ref2, indegrees.get(ref2) + 1);
|
|
2876
|
+
const queue = [...indegrees].filter(([, degree]) => degree === 0).map(([ref2]) => ref2);
|
|
2877
|
+
for (let i = 0; i < queue.length; i++)
|
|
2878
|
+
for (const ref2 of graph.get(queue[i]) ?? []) {
|
|
2879
|
+
const degree = indegrees.get(ref2) - 1;
|
|
2880
|
+
indegrees.set(ref2, degree);
|
|
2881
|
+
if (degree === 0) queue.push(ref2);
|
|
2882
|
+
}
|
|
2883
|
+
if (queue.length !== graph.size)
|
|
2884
|
+
problem(
|
|
2885
|
+
"CLAIM.DEPENDENCY_CYCLE",
|
|
2886
|
+
"/claims",
|
|
2887
|
+
"Claim inputs and supersession must form an acyclic history."
|
|
2888
|
+
);
|
|
2889
|
+
const validation = {
|
|
2890
|
+
contract,
|
|
2891
|
+
issues,
|
|
2892
|
+
uncheckedRefs: [
|
|
2893
|
+
...data.contextRefs.map((r) => r.sha256),
|
|
2894
|
+
...data.entityRefs.map((r) => r.sha256),
|
|
2895
|
+
...observationResult.uncheckedRefs,
|
|
2896
|
+
...data.claims.flatMap((c) => [
|
|
2897
|
+
...c.subject.kind === "context" ? [c.subject.reference.document.sha256] : [],
|
|
2898
|
+
...c.kind === "assessment" ? (c.contextInputRefs ?? []).map((r) => r.document.sha256) : []
|
|
2899
|
+
])
|
|
2900
|
+
],
|
|
2901
|
+
checks: {
|
|
2902
|
+
structural: "passed",
|
|
2903
|
+
semantic: issues.length ? "failed" : "passed",
|
|
2904
|
+
profile: "not_checked",
|
|
2905
|
+
external: "not_checked"
|
|
2906
|
+
}
|
|
2907
|
+
};
|
|
2908
|
+
return issues.length ? { ...validation, success: false } : {
|
|
2909
|
+
...validation,
|
|
2910
|
+
success: true,
|
|
2911
|
+
data,
|
|
2912
|
+
currentClaimRefs: [...claims.keys()].filter(
|
|
2913
|
+
(ref2) => !superseded.has(ref2)
|
|
2914
|
+
)
|
|
2915
|
+
};
|
|
2916
|
+
}
|
|
2917
|
+
|
|
2918
|
+
export { AssessedClaimSchema, CLAIM_HISTORY_RULESET_VERSION, CONTEXT_CLAIM_HISTORY_RULESET_VERSION, CONTEXT_CLAIM_HISTORY_SCHEMA_ID, ClaimSubjectSchema, ContextAssertionReferenceSchema, ContextAssessedClaimSchema, ContextClaimHistorySchema, ContextClaimSubjectSchema, ContextCollectionFields, ContextEntitySchema, ContextEnvironmentFields, ContextEventFields, ContextHistoricalClaimSchema, ContextMeasurementLinkSchema, ContextObjectFields, ContextPlaceFields, ContextPlatformFields, ContextReferenceSchema, ContextSourceStatementSchema, ContextTargetSchema, ContextTemporalFields, ContextUnassessedClaimSchema, DocumentSnapshotRefSchema, EXPERIMENTAL_CLAIM_HISTORY_SCHEMA_ID, EXPERIMENTAL_OBSERVATION_SCHEMA_ID, EventTimeIntervalSchema, EventTimePointSchema, EventTimeSchema, EventTimeValueSchema, ExperimentalClaimHistorySchema, ExperimentalObservationSchema, FramedPositionSchema, HistoricalClaimSchema, MeasuredQuantitySchema, OBSERVATION_CONTEXT_SCHEMA_ID, ObservationAssertionSchema, ObservationContextSchema, ObservationMeasurementSchema, ObservationMethodSchema, ObservationPositionSchema, ObservationProductSchema, ObservationSnapshotRefSchema, ObservationSourceSchema, ObservationTimeSchema, PRIMITIVES_SCHEMA_ID, PositionSchema, PositionValueSchema, PrimitiveRecordSchema, ProcessingActivitySchema, QuantitativeUncertaintySchema, RESEARCH_CLAIM_HISTORY_RULESET_VERSION, RESEARCH_CLAIM_HISTORY_SCHEMA_ID, RESEARCH_ENTITIES_SCHEMA_ID, ReferenceFrameSchema, ResearchAccountFields, ResearchAssessedClaimSchema, ResearchClaimHistorySchema, ResearchClaimSubjectSchema, ResearchEntitiesSchema, ResearchEntityAssertionReferenceSchema, ResearchEntityReferenceSchema, ResearchEntitySchema, ResearchEntityTargetSchema, ResearchHistoricalClaimSchema, ResearchProcedureFields, ResearchSourceStatementSchema, ResearchUnassessedClaimSchema, ResearchWitnessFields, ResearchWitnessGroupFields, SourceProvenanceSchema, SourceStatementSchema, UnassessedClaimSchema, ValueAssertionSchema, ValueSelectionSchema, WitnessReviewSchema, compareUtcInstants, contextAssertions, contextClaimHistoryJsonSchema, experimentalClaimHistoryJsonSchema, experimentalObservationJsonSchema, observationContextJsonSchema, parseContextClaimHistory, parseExperimentalClaimHistory, parseExperimentalObservation, parseObservationContext, parsePrimitiveRecord, parseResearchClaimHistory, parseResearchEntities, primitivesJsonSchema, researchClaimHistoryJsonSchema, researchEntitiesJsonSchema, researchEntityAssertions, researchEntityContextReferences };
|
|
644
2919
|
//# sourceMappingURL=index.js.map
|
|
645
2920
|
//# sourceMappingURL=index.js.map
|