import { type CreateFieldMetadata, type CreateIssueInput, type CreateIssueType, type CreateSchemaRequirements } from "../domain/write.js"; /** * What JAM will agree to create, decided from what Jira says it accepts. * * Creation is the one write with no issue to look at first, so every check * here is against the project's create schema instead. The rule throughout is * the one the rest of the write plane follows: resolve against what Jira just * reported, never against what the caller asserted or what a name suggests. An * issue type id is not derived from a type name, a priority is not sent * because it looked plausible, and a required field JAM cannot express is * refused here rather than posted and rejected as a 400. */ /** * Jira field ids for the fields JAM can put on a create. * * The bridge between the public contract (CREATABLE_FIELDS, which an agent * sees) and Jira's own ids (which the required-field gate compares against). * Both directions matter: one decides what may be asked for, the other decides * what counts as "JAM supplies this". */ export declare const CREATE_FIELD_IDS: { readonly issueType: "issuetype"; readonly summary: "summary"; readonly description: "description"; readonly priority: "priority"; readonly labels: "labels"; readonly components: "components"; }; /** * Match a requested issue type against the ones Jira offers for this project. * * Case-insensitive, because "task" and "Task" are the same intent and an agent * has no way to learn Jira's casing before asking. Nothing else is inferred: * the id comes from Jira's own list, and a type that is not on it is refused * with the list attached, so the next move is to pick one rather than to * rephrase the same one. * * Subtask types are refused separately. They need a parent, which is not in * this version's contract, so "not available" would be the wrong answer - the * type exists, and JAM cannot use it yet. */ export declare function resolveIssueType(requested: string, available: CreateIssueType[]): CreateIssueType; /** * Refuse a create whose project requires something JAM cannot put on it. * * The alternative - post it and let Jira answer 400 - is worse twice over: the * agent gets a vendor error instead of a JAM decision, and creation is the one * write where "did it happen?" is expensive to answer after the fact. So the * answer is worked out before anything is sent. * * A field Jira says it will default is not JAM's to supply. That is Jira * stating a fact about its own configuration, not JAM guessing one. * * Returns the required field ids, which the plan records so apply can tell a * newly-required field from one that was always there. */ export declare function assertRequiredFieldsSupported(fields: CreateFieldMetadata[], input: CreateIssueInput): string[]; /** * Turn a requested value into one Jira currently offers for that field. * * An unconstrained field passes the value through: there is no list to check * it against, and inventing one would refuse valid input. Absent and empty are * different - absent means Jira did not constrain the field, empty means it * constrains it and offers nothing. * * The shape is resolveTransition's, deliberately: human intent, then * Jira-provided candidates, then a concrete Jira value. Nothing in between * guesses. */ export declare function resolveAllowedValue(field: CreateFieldMetadata | undefined, requested: string, label: string): { requested: string; resolved: string; }; /** * Are this plan's premises still true? * * Semantic, not a document comparison. Comparing a hash of the metadata would * make an unrelated optional field appearing on the create screen invalidate * every outstanding plan - which is wrong, and on an active project constant. * What matters is narrower: the issue type still exists, no new required field * has appeared that JAM cannot fill, and every value resolved from an allowed * list is still on it. * * Everything else about the schema may change freely between plan and apply. */ export declare function assertSchemaUnchanged(requirements: CreateSchemaRequirements, issueTypes: CreateIssueType[], fields: CreateFieldMetadata[], input: CreateIssueInput): void;