diff --git a/build.sbt b/build.sbt index 0d083934..ddfa9783 100644 --- a/build.sbt +++ b/build.sbt @@ -4,10 +4,10 @@ val fs2Version = "3.9.3" val kittensVersion = "3.1.0" val munitVersion = "0.7.29" val munitCatsEffectVersion = "1.0.7" -val lucumaCoreVersion = "0.88.2" -val lucumaODBSchema = "0.7.0" +val lucumaCoreVersion = "0.91.0" +val lucumaODBSchema = "0.8.0" -ThisBuild / tlBaseVersion := "0.66" +ThisBuild / tlBaseVersion := "0.67" ThisBuild / tlCiReleaseBranches := Seq("main") ThisBuild / crossScalaVersions := Seq("3.3.1") ThisBuild / tlVersionIntroduced := Map("3" -> "0.29.0") diff --git a/lucuma-schemas/src/clue/resources/lucuma/schemas/ObservationDB.graphql b/lucuma-schemas/src/clue/resources/lucuma/schemas/ObservationDB.graphql index fc124540..42298958 100644 --- a/lucuma-schemas/src/clue/resources/lucuma/schemas/ObservationDB.graphql +++ b/lucuma-schemas/src/clue/resources/lucuma/schemas/ObservationDB.graphql @@ -144,6 +144,23 @@ type AddStepEventResult { event: StepEvent! } +""" +Input to the 'addTimeChargeCorrection' mutation. Identifies the visit +that will be corrected and describes the correction itself. +""" +input AddTimeChargeCorrectionInput { + observation: VisitId! + correction: TimeChargeCorrectionInput! +} + +""" +The result of the 'addTimeChargeCorrection' mutation. It contains the +visit's updated TimeChargeInvoice after applying the correction. +""" +type AddTimeChargeCorrectionResult { + timeChargeInvoice: TimeChargeInvoice! +} + """Air mass range creation and edit parameters""" input AirMassRangeInput { min: PosBigDecimal @@ -339,6 +356,34 @@ input CatalogInfoInput { objectType: NonEmptyString } +"""A time amount broken into charge class categories.""" +type CategorizedTime { + """Time charged to the program / PI.""" + program: TimeSpan! + + """Time charged to the partner.""" + partner: TimeSpan! + + """Execution time that is not charged.""" + nonCharged: TimeSpan! + + """Total of program, partner and uncharged times.""" + total: TimeSpan! +} + +""" +A minimum to maximum categorized time estimate. The actual execution time +should vary between the two extremes, depending upon which observations and +groups are ultimately completed. +""" +type CategorizedTimeRange { + """Minimum remaining time estimate.""" + minimum: CategorizedTime! + + """Maximum remaining time estimate.""" + maximum: CategorizedTime! +} + """Classical observing at Gemini""" input ClassicalInput { """ @@ -1427,6 +1472,9 @@ type GmosNorthVisit implements Visit { LIMIT: NonNegInt ): ExecutionEventSelectResult! + """Time accounting details for this visit.""" + timeChargeInvoice: TimeChargeInvoice! + """GmosNorth static instrument configuration""" static: GmosNorthStatic! } @@ -1832,6 +1880,9 @@ type GmosSouthVisit implements Visit { LIMIT: NonNegInt ): ExecutionEventSelectResult! + """Time accounting details for this visit.""" + timeChargeInvoice: TimeChargeInvoice! + """GmosSouth static instrument configuration""" static: GmosSouthStatic! } @@ -1981,6 +2032,15 @@ type Mutation { """ input: AddStepEventInput! ): AddStepEventResult! + + """ + Adds a new time accounting correction for a particular observation. Note + that time accounting corrections are additive and cannot be adjusted or + deleted except via a future correction. For example, to undo the impact + of an 'Add' operation, a new 'Subtract' operation of the same amount can + be introduced. + """ + addTimeChargeCorrection(input: AddTimeChargeCorrectionInput!): AddTimeChargeCorrectionResult! cloneObservation( """Parameters for cloning an existing observation""" input: CloneObservationInput! @@ -2111,10 +2171,6 @@ type Mutation { """Parameters for updating existing programs.""" input: UpdateProgramsInput! ): UpdateProgramsResult! - updateProposalAttachments( - """Parameters for updating existing proposal attachments.""" - input: UpdateProposalAttachmentsInput! - ): UpdateProposalAttachmentsResult! """Updates existing targets""" updateTargets( @@ -2417,7 +2473,7 @@ input ProposalInput { category: TacCategory """ - The toOActivation field is required when creating a new instance of proposal, but optional when editing + The toOActivation field is optional. If not specified when creating a proposal, it defaults to `NONE'. """ toOActivation: ToOActivation @@ -3192,42 +3248,6 @@ type UpdateProgramsResult { hasMore: Boolean! } -""" -Proposal Attachment selection and update description. Use `SET` to specify the changes, `WHERE` to select the proposal attachments to update, and `LIMIT` to control the size of the return value. -""" -input UpdateProposalAttachmentsInput { - """ - Program ID for the program whose proposal attachments are to be edited. - """ - programId: ProgramId! - - """Describes the proposal attachment values to modify.""" - SET: ProposalAttachmentPropertiesInput! - - """ - Filters the proposal attachments to be updated according to those that match the given constraints. - """ - WHERE: WhereProposalAttachment - - """ - Caps the number of results returned to the given value (if additional proposal attachments match the WHERE clause they will be updated but not returned). - """ - LIMIT: NonNegInt -} - -""" -The result of updating the selected proposal attachments, up to `LIMIT` or the maximum of (1000). If `hasMore` is true, additional obs attachments were modified and not included here. -""" -type UpdateProposalAttachmentsResult { - """ - The edited proposal attachments, up to the specified LIMIT or the default maximum of 1000. - """ - proposalAttachments: [ProposalAttachment!]! - - """`true` when there were additional edits that were not returned.""" - hasMore: Boolean! -} - """ Target selection and update description. Use `SET` to specify the changes, `WHERE` to select the targets to update, and `LIMIT` to control the size of the return value. """ @@ -4053,6 +4073,9 @@ type Execution { """ LIMIT: NonNegInt ): VisitSelectResult! + + """Time accounting calculation for this observation.""" + timeCharge: CategorizedTime! } """Execution configuration""" @@ -5676,7 +5699,21 @@ type Program { that are required and which are not fully defined, the planned time range cannot be calculated. """ - plannedTimeRange: PlannedTimeRange + plannedTimeRange: PlannedTimeRange @deprecated(reason: "Use timeEstimateRange instead.") + + """ + Remaining execution time estimate range, assuming it can be calculated. In + order for an observation to have an estimate, it must be fully defined such + that a sequence can be generated for it. If a program has observations that + are required and which are not fully defined, the remaining time estimate + cannot be calculated. + """ + timeEstimateRange: CategorizedTimeRange + + """ + Program-wide time charge, summing all corrected observation time charges. + """ + timeCharge: CategorizedTime! } """ProgramId id formatted as `p-[1-9a-f][0-9a-f]*`""" @@ -5719,23 +5756,11 @@ type ProperMotionRA { type ProposalAttachment { attachmentType: ProposalAttachmentType! fileName: NonEmptyString! - description: NonEmptyString - checked: Boolean! fileSize: Long! updatedAt: Timestamp! program: Program! } -input ProposalAttachmentPropertiesInput { - """ - The description field may be unset by assigning a null value, or ignored by skipping it altogether - """ - description: NonEmptyString - - """The checked status can be set, or ignored by skipping it altogether""" - checked: Boolean -} - """Metadata for `enum ProposalAttachmentType`""" type ProposalAttachmentTypeMeta { tag: ProposalAttachmentType! @@ -5754,7 +5779,7 @@ type Proposal { category: TacCategory """Target of Opportunity activation""" - toOActivation: ToOActivation + toOActivation: ToOActivation! """Abstract""" abstract: NonEmptyString @@ -6158,7 +6183,10 @@ type SequenceDigest { observeClass: ObserveClass! """PlannedTime for the whole sequence. """ - plannedTime: PlannedTime! + plannedTime: PlannedTime! @deprecated(reason: "Use timeEstimate instead.") + + """Time estimate for the whole sequence.""" + timeEstimate: CategorizedTime! """Unique offsets that occur in the sequence.""" offsets: [Offset!]! @@ -6942,6 +6970,126 @@ type TargetSelectResult { hasMore: Boolean! } +""" +A manual correction to time accounting calculations. Note that the +application of a correction is bounded by a zero time span and the +maximum time span. +""" +type TimeChargeCorrection { + """When the correction was made.""" + timestamp: Timestamp! + + """The charge class to be corrected.""" + chargeClass: ChargeClass! + + """The operation (add or subtract) to perform.""" + op: TimeChargeCorrectionOp! + + """ + The amount of time to add or subtract (respecting the min and max time span). + """ + amount: TimeSpan! + + """The user responsible for the change.""" + user: User! + + """Optional justification for the correction.""" + comment: String +} + +"""Describes a manual correction to time accounting calculations.""" +input TimeChargeCorrectionInput { + """The charge class to be corrected.""" + chargeClass: ChargeClass! + + """The operation (add or subtract) to perform.""" + op: TimeChargeCorrectionOp! + + """ + The amount of time to add or subtract (respecting the min and max time span). + """ + amount: TimeSpanInput! + + """Optional justification for the correction.""" + comment: String +} + +"""Time accounting correction operations.""" +enum TimeChargeCorrectionOp { + ADD + SUBTRACT +} + +""" +Describes a time charge discount, broken out by charge class (program vs. +partner). For each class, the associated time is subtracted and then added to +uncharged. +""" +interface TimeChargeDiscount { + """Time amount to discount from the program.""" + program: TimeSpan! + + """Time amount to discount from the partner.""" + partner: TimeSpan! + + """ + The atoms that are impacted (i.e., whose execution time is discounted) by this + discount. + """ + atoms: [AtomRecord!]! + + """Optional additional detail.""" + comment: String +} + +""" +A time charge discount that is applied when one or more datasets are marked +usable (as opposed to pas) or fail. +""" +type TimeChargeQaDiscount implements TimeChargeDiscount { + """Time amount to discount from the program.""" + program: TimeSpan! + + """Time amount to discount from the partner.""" + partner: TimeSpan! + + """ + The atoms that are impacted (i.e., whose execution time is discounted) by this + discount. + """ + atoms: [AtomRecord!]! + + """Optional additional detail.""" + comment: String + + """Datasets with non-passing QA states.""" + datasets: [Dataset!]! +} + +""" +Detailed time accounting information for a visit, showing the raw execution +time along with any automatically applied discounts (e.g., for bad weather) +and manual adjustments made by staff. +""" +type TimeChargeInvoice { + """Raw execution time.""" + executionTime: CategorizedTime! + + """ + Automatic discounts for weather loss, fault reports, and non-passing datasets. + """ + discounts: [TimeChargeDiscount!]! + + """Any manual corrections to the execution time.""" + corrections: [TimeChargeCorrection!]! + + """ + Final time charge once discounts and corrections have been applied to the + initial 'executionTime'. + """ + finalCharge: CategorizedTime! +} + """ToO Activation""" enum ToOActivation { """ToOActivation None""" @@ -7067,6 +7215,9 @@ interface Visit { """ LIMIT: NonNegInt ): ExecutionEventSelectResult! + + """Time accounting details for this visit.""" + timeChargeInvoice: TimeChargeInvoice! } """Matching visit results, limited to a maximum of 1000 entries.""" @@ -8115,54 +8266,6 @@ input WhereProposal { partners: WhereProposalPartners } -"""ProposalAttachment filter options. All specified items must match.""" -input WhereProposalAttachment { - """ - A list of nested attachment filters that all must match in order for the AND group as a whole to match. - """ - AND: [WhereProposalAttachment!] - - """ - A list of nested attachment filters where any one match causes the entire OR group as a whole to match. - """ - OR: [WhereProposalAttachment!] - - """ - A nested attachment filter that must not match in order for the NOT itself to match. - """ - NOT: WhereProposalAttachment - - """Matches the attachment file name.""" - fileName: WhereString - - """Matches the description.""" - description: WhereOptionString - - """Matches the attachment type""" - attachmentType: WhereProposalAttachmentType - - """Matches whether the attachment has been checked or not""" - checked: Boolean -} - -""" -Filters on equality of the property. All supplied -criteria must match, but usually only one is selected. E.g., 'EQ: SCIENCE' -""" -input WhereProposalAttachmentType { - """Matches if the property is exactly the supplied value.""" - EQ: ProposalAttachmentType - - """Matches if the property is not the supplied value.""" - NEQ: ProposalAttachmentType - - """Matches if the property value is any of the supplied options.""" - IN: [ProposalAttachmentType!] - - """Matches if the property value is none of the supplied values.""" - NIN: [ProposalAttachmentType!] -} - """Proposal class filter options.""" input WhereProposalClass { """Proposal class type match."""