gh-inari 0.7.0 → 0.9.0

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.
Files changed (56) hide show
  1. package/.codex-plugin/plugin.json +1 -1
  2. package/README.md +35 -10
  3. package/dist/artifact.d.ts +158 -15
  4. package/dist/artifact.js +834 -78
  5. package/dist/artifact.js.map +1 -1
  6. package/dist/cli.js +484 -65
  7. package/dist/cli.js.map +1 -1
  8. package/dist/contract/index.d.ts +2 -0
  9. package/dist/contract/index.js +2 -0
  10. package/dist/contract/index.js.map +1 -1
  11. package/dist/contract/ir.d.ts +15 -0
  12. package/dist/contract/ir.js +40 -2
  13. package/dist/contract/ir.js.map +1 -1
  14. package/dist/contract/issue-form.js +16 -3
  15. package/dist/contract/issue-form.js.map +1 -1
  16. package/dist/contract/issue-reference.d.ts +58 -0
  17. package/dist/contract/issue-reference.js +157 -0
  18. package/dist/contract/issue-reference.js.map +1 -0
  19. package/dist/contract/normalization.d.ts +31 -0
  20. package/dist/contract/normalization.js +73 -0
  21. package/dist/contract/normalization.js.map +1 -0
  22. package/dist/contract/schema.d.ts +4 -0
  23. package/dist/contract/schema.js +42 -1
  24. package/dist/contract/schema.js.map +1 -1
  25. package/dist/contract/validation.d.ts +120 -2
  26. package/dist/contract/validation.js +476 -3
  27. package/dist/contract/validation.js.map +1 -1
  28. package/dist/diagnostics.d.ts +133 -0
  29. package/dist/diagnostics.js +421 -0
  30. package/dist/diagnostics.js.map +1 -0
  31. package/dist/github/adapter.d.ts +2 -0
  32. package/dist/github/adapter.js +80 -32
  33. package/dist/github/adapter.js.map +1 -1
  34. package/dist/github/capability.js +1 -0
  35. package/dist/github/capability.js.map +1 -1
  36. package/dist/github/types.d.ts +7 -0
  37. package/dist/governance.d.ts +8 -2
  38. package/dist/governance.js +56 -4
  39. package/dist/governance.js.map +1 -1
  40. package/dist/index.d.ts +2 -0
  41. package/dist/index.js +2 -0
  42. package/dist/index.js.map +1 -1
  43. package/dist/pr-policy.d.ts +9 -0
  44. package/dist/pr-policy.js +36 -16
  45. package/dist/pr-policy.js.map +1 -1
  46. package/dist/pr-sync-input.d.ts +74 -0
  47. package/dist/pr-sync-input.js +231 -0
  48. package/dist/pr-sync-input.js.map +1 -0
  49. package/dist/reconciliation.d.ts +21 -14
  50. package/dist/reconciliation.js +515 -42
  51. package/dist/reconciliation.js.map +1 -1
  52. package/dist/semantic-template.js +32 -5
  53. package/dist/semantic-template.js.map +1 -1
  54. package/dist/skill.js +55 -21
  55. package/dist/skill.js.map +1 -1
  56. package/package.json +3 -3
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "inari",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "Governed GitHub Issue/PR/template workflows via the inari CLI. Prefer inari over raw gh for operations it owns; use inari skill for operational playbooks.",
5
5
  "skills": "skills/inari"
6
6
  }
package/README.md CHANGED
@@ -129,6 +129,16 @@ marketplace registration and installation via Codex plugin commands to
129
129
  activate the skill; standard `npm install` alone does not automatically
130
130
  surface the plugin to Codex-aware agents.
131
131
 
132
+ To discover and install it from this repository's marketplace:
133
+
134
+ ```bash
135
+ codex plugin marketplace add .
136
+ ```
137
+
138
+ In Codex, run `/plugins`, select the `gh-inari` marketplace, and install
139
+ `inari`. Start a new Codex session after installation so the bundled Skill
140
+ is available.
141
+
132
142
  The Skill is deliberately thin: it identifies governed GitHub Issue/PR/
133
143
  template workflows as Inari-owned and routes agents to `inari skill` /
134
144
  `inari skill <scenario>` for the actual operational playbooks, and to
@@ -156,8 +166,8 @@ inari issue get <number> [--template <template>] --json
156
166
  inari pr get <number> [--template <template>] --json
157
167
  inari issue check <number> [--template <template>]
158
168
  inari pr check <number> [--template <template>]
159
- inari issue edit <number> --from patch.json [--dry-run]
160
- inari pr edit <number> --from patch.json [--dry-run]
169
+ inari issue edit <number> [--from patch.json] [--field name=value] [--title title] [--dry-run]
170
+ inari pr edit <number> [--from patch.json] [--field name=value] [--title title] [--base branch] [--maintainer-can-modify] [--dry-run]
161
171
  inari issue normalize <number> [--dry-run]
162
172
  inari pr normalize <number> [--dry-run]
163
173
  inari issue sync <number> --from desired.json [--dry-run]
@@ -174,7 +184,14 @@ inari pr sync <number> --from desired.json [--dry-run]
174
184
  }
175
185
  ```
176
186
 
177
- The `fields` object is the semantic input contract shown by `schema`. Issue creation also accepts `assignees`; pull request creation accepts `head`, `base`, `draft`, and `maintainerCanModify`. `--title`, `--head`, and `--base` override envelope metadata.
187
+ The `fields` object is the semantic input contract shown by `schema`; the same schema output exposes the separate required create metadata schema. Issue creation also accepts `assignees`; pull request creation accepts `head`, `base`, `draft`, and `maintainerCanModify`. Caller-supplied `title` metadata is required for both create commands, and `--title`, `--head`, and `--base` override envelope metadata. Existing `edit` commands use the remote artifact as their patch base: `--title` is supported for Issues and pull requests, while pull requests also support `--base` and `--maintainer-can-modify`; `--draft` is rejected for edit because pull-request PATCH does not accept it. Omitted values are preserved and unsupported or immutable metadata is rejected.
188
+
189
+ `pr sync --from` accepts a complete pull-request desired-state envelope. Use
190
+ `inari pr sync --help` for the top-level contract, or
191
+ `inari pr schema <template> --json` for its machine-readable `syncInput.schema`
192
+ and a valid `syncInput.minimalExample`.
193
+ `issue sync --from` overlays supplied semantic fields and metadata onto the
194
+ current artifact, preserving values omitted from the input.
178
195
 
179
196
  Schema and validation output is JSON. `--json` makes render and create output JSON as well. Validation failures return exit status `2`; usage errors return `1`; GitHub/transport failures return `3`. Error objects contain stable `code`, `path` where applicable, and ordered `violations`.
180
197
 
@@ -185,25 +202,33 @@ parse the existing artifact with the same parser and semantic validator as
185
202
  metadata. Successful reads report `projection: "canonical"`; wrong-template,
186
203
  unparseable, ambiguous, and semantically invalid artifacts report structured
187
204
  diagnostics with `projection: "unavailable"` and never return guessed fields.
188
- When `--template` is omitted, all supported candidates are evaluated
205
+ When `--template` is omitted, Inari first looks for the bounded invisible
206
+ template identity marker every rendered artifact now carries. A valid marker
207
+ resolves the contract directly; an unknown, stale, or wrong-kind marker fails
208
+ closed with a diagnostic instead of guessing another template. Artifacts
209
+ without a marker fall back to evaluating all supported candidates
189
210
  deterministically; multiple structural matches fail closed. Native template
190
211
  boilerplate and raw Markdown are intentionally absent from successful output.
191
212
 
192
213
  Existing artifact remediation uses one semantic pipeline for both Issues and
193
214
  pull requests. `check` is read-only and classifies an artifact as
194
215
  `valid-current`, `non-canonical`, `semantically-invalid`, `unsupported`, or
195
- `ambiguous`. `edit` applies only an explicit semantic patch from JSON; it never
196
- accepts raw Markdown as the mutation contract. `normalize` re-renders a
216
+ `ambiguous`. `edit` applies an explicit semantic/metadata patch from JSON or
217
+ direct CLI options; it never accepts raw Markdown as the mutation contract. `normalize` re-renders a
197
218
  parseable, semantically valid artifact and fails closed when preservation is
198
- not proven. `sync` treats its input as the complete desired semantic state and
199
- reconciles the canonical projection deterministically. A successful no-op is
219
+ not proven. `issue sync` overlays its input onto the current canonical state,
220
+ while `pr sync` treats its input as the complete desired semantic state; both
221
+ reconcile the canonical projection deterministically. A successful no-op is
200
222
  reported explicitly, and `--dry-run` returns a bounded semantic/rendered diff
201
- without calling a GitHub mutation.
223
+ plus the validated resulting fields, metadata, and canonical body without
224
+ calling a GitHub mutation.
202
225
 
203
226
  ## Source of truth and supported semantics
204
227
 
205
228
  `.github/ISSUE_TEMPLATE/**` remains the Issue source of truth. For pull requests, Inari discovers GitHub's supported repository locations: `pull_request_template` files under the repository root, `docs/`, or `.github/`, plus `PULL_REQUEST_TEMPLATE/` directories under each location. Native PR template filenames and the `.md`/`.txt` extensions supported by Inari are matched case-insensitively. Other PR-template extension surfaces are intentionally unsupported in v1 and fail closed. Inari discovers and compiles those files; it does not replace them with a proprietary body schema. Supported Issue Form nodes are `input`, `textarea` (including native `render` code fences), single- and multi-select `dropdown`, `checkboxes`, and `markdown`. Browser-only or ambiguous behavior, such as uploads or unsupported textarea rendering modes, fails closed. Markdown nodes are retained for contract/schema explainability but never emitted into an Issue body.
206
229
 
230
+ Issue dependencies are a separate, template-independent semantic object. Structured Issue envelopes may provide `dependencies.blockedBy` and `dependencies.blocks`; each reference is the canonical `{ "repositoryHost": "github.com", "repositoryId": "<decimal REST repository database id>", "repository": "owner/name", "number": N }` identity. `repositoryHost` plus `repositoryId` is authoritative: the host/install boundary prevents IDs from different GH_HOST/GHES installations colliding. Within one host, rename/transfer preserves the repository identity tuple and changes only the optional locator; cross-host migration is a different identity. The GitHub adapter obtains this decimal ID from the REST repository endpoint through `gh api`, including for repository overrides through a read-only identity lookup; a context that cannot obtain it does not synthesize one from owner/name. Inari sorts and validates these references (including duplicate, self, malformed, and contradictory declarations) before rendering. Non-empty dependencies are preserved in a bounded reserved body marker and projected back as normalized JSON; ordinary Markdown and GitHub-native dependency metadata are never inferred as semantic input. GitHub-native dependency state is not currently mutated by Inari, so there is no competing authority or implicit drift reconciliation.
231
+
207
232
  Native PR Markdown expresses structure but not policy. A small versioned overlay may add constraints unavailable in Markdown without changing section order or content. The supported v1 form is:
208
233
 
209
234
  ```yaml
@@ -235,7 +260,7 @@ templates:
235
260
 
236
261
  Template and section bindings are deterministic. Stale, unknown, or ambiguous template/section references fail closed. `linkedIssue: true` means that the field contains a GitHub closing reference: `close`, `closes`, `closed`, `fix`, `fixes`, `fixed`, `resolve`, `resolves`, or `resolved`, followed by `#ISSUE-NUMBER` or `OWNER/REPOSITORY#ISSUE-NUMBER`, with an optional colon and case-insensitive keyword. This validates syntax only; GitHub applies automatic linking/closure only under its own contextual rules, including the target default branch.
237
262
 
238
- Issue Form top-level `title` is the exact default title used when the caller omits a title; an explicit caller title replaces it without inferred prefix concatenation. Top-level `labels` are repository-governed defaults and are always retained; caller-supplied labels are appended in order with duplicates removed. Top-level `assignees`, `projects`, and `type`, and upload fields remain unsupported and fail closed rather than being approximated.
263
+ Issue Form top-level `title` is a fixed native prefix for create validation, but it does not satisfy the caller's required title metadata by itself. An explicit caller title is used as supplied without inferred prefix concatenation or automatic generation. Top-level `labels` are repository-governed defaults and are always retained; caller-supplied labels are appended in order with duplicates removed. Top-level `assignees`, `projects`, and `type`, and upload fields remain unsupported and fail closed rather than being approximated.
239
264
 
240
265
  ## Scope
241
266
 
@@ -1,5 +1,7 @@
1
- import { type SemanticValidationResult, type SemanticViolation } from "./contract/validation.js";
2
- import { type CanonicalContract } from "./contract/ir.js";
1
+ import { type PartialSemanticValidationResult, type PartialSemanticRepairResult, type SemanticValidationResult, type SemanticViolation } from "./contract/validation.js";
2
+ import { type ArtifactDiagnostic, type ArtifactDiagnosticReport } from "./diagnostics.js";
3
+ import { type ArtifactKind, type CanonicalContract } from "./contract/ir.js";
4
+ import { type IssueDependencies, type IssueReference } from "./contract/issue-reference.js";
3
5
  import { type ValidatedRenderedIssueArtifact, type ValidatedRenderedPullRequestArtifact } from "./github/types.js";
4
6
  export interface ArtifactInputMetadata {
5
7
  readonly title?: string;
@@ -13,31 +15,66 @@ export interface ArtifactInputMetadata {
13
15
  export interface ArtifactInputDocument {
14
16
  readonly fields: Readonly<Record<string, unknown>>;
15
17
  readonly metadata: ArtifactInputMetadata;
18
+ /** Generic Issue relationships, independent of template-specific fields. */
19
+ readonly dependencies?: IssueDependencies;
20
+ }
21
+ /**
22
+ * A representation-independent candidate entering the canonical contract.
23
+ * Adapters may decode JSON, native Markdown, an existing GitHub body, or
24
+ * internal field input, but they never validate or materialize contract
25
+ * semantics themselves.
26
+ */
27
+ export type ArtifactCandidateSource = "json" | "markdown" | "existing" | "fields";
28
+ export interface ArtifactCandidate {
29
+ readonly fields: unknown;
30
+ readonly metadata: ArtifactInputMetadata;
31
+ readonly source: ArtifactCandidateSource;
32
+ readonly dependencies?: IssueDependencies;
33
+ }
34
+ export interface ArtifactCandidateAdapterResult {
35
+ readonly parsed: boolean;
36
+ readonly candidate?: ArtifactCandidate;
37
+ readonly diagnostics: readonly ExistingArtifactDiagnostic[];
38
+ }
39
+ /** Result of the one candidate -> selected contract -> canonical JSON boundary. */
40
+ export interface CanonicalArtifactLoadResult {
41
+ readonly valid: boolean;
42
+ readonly complete: boolean;
43
+ /** Canonical contract-shaped semantic JSON. Never contains rejected fields. */
44
+ readonly canonical: Readonly<Record<string, unknown>>;
45
+ /** Explicit alias for callers that name the output canonical JSON. */
46
+ readonly canonicalJson: Readonly<Record<string, unknown>>;
47
+ /** Backward-compatible semantic value name used by renderer callers. */
48
+ readonly values: Readonly<Record<string, unknown>>;
49
+ readonly candidate: ArtifactCandidate;
50
+ readonly acceptedFields: readonly string[];
51
+ readonly missingFields: PartialSemanticValidationResult["missingFields"];
52
+ readonly invalidFields: PartialSemanticValidationResult["invalidFields"];
53
+ readonly diagnostics: ArtifactDiagnosticReport;
54
+ readonly violations: readonly SemanticViolation[];
55
+ readonly dependencies?: IssueDependencies;
16
56
  }
17
57
  export interface ArtifactMetadataViolation {
18
58
  readonly code: "INPUT_METADATA_INVALID";
19
59
  readonly path: string;
20
60
  readonly message: string;
21
61
  }
22
- export type ArtifactInputErrorCode = "INPUT_DOCUMENT_INVALID" | "INPUT_METADATA_INVALID";
62
+ export type ArtifactInputErrorCode = "INPUT_DOCUMENT_INVALID" | "INPUT_METADATA_INVALID" | "INPUT_DEPENDENCIES_INVALID";
23
63
  export declare class ArtifactInputError extends Error {
24
64
  readonly code: ArtifactInputErrorCode;
25
65
  readonly path: string;
26
- constructor(code: ArtifactInputErrorCode, message: string, path?: string);
66
+ readonly details?: unknown;
67
+ constructor(code: ArtifactInputErrorCode, message: string, path?: string, details?: unknown);
27
68
  }
28
69
  export type ArtifactPreparationErrorCode = "ARTIFACT_PROVENANCE_MISSING" | "ARTIFACT_ROUND_TRIP_INVALID";
29
- export type ArtifactRoundTripDiagnosticCode = "ROUND_TRIP_PARSE" | "ROUND_TRIP_SEMANTIC" | "ROUND_TRIP_MISMATCH";
30
- export interface ArtifactRoundTripDiagnostic {
31
- readonly code: ArtifactRoundTripDiagnosticCode;
32
- readonly path: string;
33
- readonly message: string;
34
- readonly expected?: unknown;
35
- readonly actual?: unknown;
36
- }
70
+ /** @deprecated Round-trip diagnostics use the shared #118 diagnostic contract. */
71
+ export type ArtifactRoundTripDiagnostic = ArtifactDiagnostic;
72
+ /** @deprecated Use ArtifactDiagnosticCode/ArtifactDiagnosticDetailCode. */
73
+ export type ArtifactRoundTripDiagnosticCode = ArtifactDiagnostic["code"];
37
74
  /** Stable failures raised before a mutation-capable artifact is created. */
38
75
  export declare class ArtifactPreparationError extends Error {
39
76
  readonly code: ArtifactPreparationErrorCode;
40
- readonly diagnostics: readonly ArtifactRoundTripDiagnostic[];
77
+ readonly diagnostics: readonly ArtifactDiagnostic[];
41
78
  constructor(code: ArtifactPreparationErrorCode, message: string, diagnostics?: readonly ArtifactRoundTripDiagnostic[]);
42
79
  }
43
80
  export interface PreparedIssueArtifact {
@@ -51,7 +88,7 @@ export interface PreparedPullRequestArtifact {
51
88
  readonly artifact: ValidatedRenderedPullRequestArtifact;
52
89
  }
53
90
  export type ExistingArtifactClassification = "valid" | "semantic" | "wrong-template" | "unparseable" | "ambiguous";
54
- export type ExistingArtifactDiagnosticCode = "EXISTING_WRONG_TEMPLATE" | "EXISTING_UNPARSEABLE" | "EXISTING_EXTRA_CONTENT" | "EXISTING_UNKNOWN_CHECKLIST_ITEM" | "EXISTING_AMBIGUOUS_TEMPLATE" | "EXISTING_NON_CANONICAL" | "EXISTING_TEMPLATE_COMPILE_FAILED";
91
+ export type ExistingArtifactDiagnosticCode = "EXISTING_WRONG_TEMPLATE" | "EXISTING_UNPARSEABLE" | "EXISTING_EXTRA_CONTENT" | "EXISTING_UNKNOWN_CHECKLIST_ITEM" | "EXISTING_AMBIGUOUS_TEMPLATE" | "EXISTING_NON_CANONICAL" | "EXISTING_TEMPLATE_COMPILE_FAILED" | "EXISTING_TEMPLATE_MARKER_INVALID";
55
92
  export interface ExistingArtifactDiagnostic {
56
93
  readonly code: ExistingArtifactDiagnosticCode;
57
94
  readonly path: string;
@@ -60,6 +97,19 @@ export interface ExistingArtifactDiagnostic {
60
97
  export interface ExistingArtifactParseResult {
61
98
  readonly parsed: boolean;
62
99
  readonly values: Readonly<Record<string, unknown>>;
100
+ readonly dependencies?: IssueDependencies;
101
+ /** Raw dependency declaration retained for the semantic validation boundary. */
102
+ readonly dependencyInput?: unknown;
103
+ readonly diagnostics: readonly ExistingArtifactDiagnostic[];
104
+ }
105
+ /**
106
+ * Semantic values recovered from an artifact that did not pass the strict
107
+ * structural parser. Values are extracted only from unambiguous contract
108
+ * sections and are still subject to the canonical semantic loader before use.
109
+ */
110
+ export interface RecoverableArtifactValues {
111
+ readonly values: Readonly<Record<string, unknown>>;
112
+ readonly dependencies?: IssueDependencies;
63
113
  readonly diagnostics: readonly ExistingArtifactDiagnostic[];
64
114
  }
65
115
  export interface ExistingArtifactValidationResult {
@@ -74,6 +124,8 @@ export interface ExistingIssueReader {
74
124
  getIssue(issueNumber: number): Promise<{
75
125
  readonly body: string | null;
76
126
  readonly url: string;
127
+ readonly repositoryId?: string;
128
+ readonly repositoryHost?: string;
77
129
  }>;
78
130
  }
79
131
  export interface ExistingPullRequestReader {
@@ -82,6 +134,51 @@ export interface ExistingPullRequestReader {
82
134
  readonly url: string;
83
135
  }>;
84
136
  }
137
+ /**
138
+ * Bounded invisible template identity marker embedded in newly rendered
139
+ * artifacts. It is the primary template-selection signal for governed
140
+ * read/repair/validation; legacy artifacts without a marker (or with one
141
+ * that cannot be trusted) fall back to deterministic structural matching.
142
+ * The marker is metadata only: it never substitutes for the authoritative
143
+ * repository governance/provenance that resolves the actual contract.
144
+ */
145
+ export declare const TEMPLATE_IDENTITY_MARKER_VERSION: "1";
146
+ export declare const ISSUE_DEPENDENCY_MARKER_VERSION: "1";
147
+ export interface TemplateIdentityMarker {
148
+ readonly version: string;
149
+ readonly kind: ArtifactKind;
150
+ readonly path: string;
151
+ }
152
+ export type TemplateIdentityMarkerStatus = "absent" | "valid" | "malformed" | "unsupported-version";
153
+ export interface TemplateIdentityMarkerExtraction {
154
+ readonly status: TemplateIdentityMarkerStatus;
155
+ readonly marker?: TemplateIdentityMarker;
156
+ /** Body with a recognized trailing marker line removed; unchanged when none is present. */
157
+ readonly body: string;
158
+ }
159
+ export type IssueDependencyMarkerStatus = "absent" | "valid" | "malformed" | "unsupported-version";
160
+ export interface IssueDependencyMarkerExtraction {
161
+ readonly status: IssueDependencyMarkerStatus;
162
+ readonly dependencies?: IssueDependencies;
163
+ /** Body with a recognized trailing dependency marker removed. */
164
+ readonly body: string;
165
+ }
166
+ /**
167
+ * Read only the reserved trailing dependency marker emitted by Inari. No
168
+ * ordinary Markdown is interpreted as a relationship declaration.
169
+ */
170
+ export declare function extractIssueDependencyMarker(body: string): IssueDependencyMarkerExtraction;
171
+ /**
172
+ * Recognize and remove a trailing template identity marker line without
173
+ * applying semantic parsing. Only a line starting with the exact reserved
174
+ * marker prefix is treated as a marker attempt at all; ordinary trailing
175
+ * HTML comments (e.g. PR template scaffolding) are left untouched here and
176
+ * handled by the existing comment-stripping path. Once the reserved prefix
177
+ * is detected, the line is never silently ignored as "absent" again: an
178
+ * oversized, truncated, or otherwise broken marker attempt fails closed as
179
+ * "malformed" instead of falling through to structural matching.
180
+ */
181
+ export declare function extractTemplateIdentityMarker(body: string): TemplateIdentityMarkerExtraction;
85
182
  export interface FetchedExistingArtifact {
86
183
  readonly number: number;
87
184
  readonly url: string;
@@ -89,6 +186,41 @@ export interface FetchedExistingArtifact {
89
186
  }
90
187
  /** Parse the documented JSON input envelope while keeping field semantics adapter-independent. */
91
188
  export declare function parseArtifactInputDocument(input: unknown): ArtifactInputDocument;
189
+ /** Adapt a parsed JSON envelope without granting it canonical status. */
190
+ export declare function adaptJsonArtifactCandidate(input: unknown): ArtifactCandidate;
191
+ /** Adapt internal structured fields to the same candidate shape as JSON. */
192
+ export declare function adaptFieldArtifactCandidate(fields: unknown, metadata?: ArtifactInputMetadata): ArtifactCandidate;
193
+ /** Alias used by command adapters that call this input the CLI field path. */
194
+ export declare const adaptCliFieldCandidate: typeof adaptFieldArtifactCandidate;
195
+ /** Generic adapter spelling for callers that already hold structured fields. */
196
+ export declare const adaptArtifactCandidate: typeof adaptFieldArtifactCandidate;
197
+ /** Adapt an existing native artifact body through the repository parser. */
198
+ export declare function adaptMarkdownArtifactCandidate(contractInput: unknown, body: string | null | undefined): ArtifactCandidateAdapterResult;
199
+ /** Existing GitHub bodies use the same native Markdown adapter by design. */
200
+ export declare function adaptExistingArtifactCandidate(contractInput: unknown, body: string | null | undefined): ArtifactCandidateAdapterResult;
201
+ /**
202
+ * Reload a candidate against the selected canonical contract. Complete input
203
+ * takes the normal one-pass validator (and therefore may materialize contract
204
+ * defaults); incomplete/invalid input uses the bounded partial contract and
205
+ * exposes only accepted semantic values.
206
+ */
207
+ export declare function loadCanonicalArtifact(contractInput: unknown, candidateInput: unknown): CanonicalArtifactLoadResult;
208
+ /** Explicitly named alias for callers that pass a candidate object. */
209
+ export declare const loadCanonicalCandidate: typeof loadCanonicalArtifact;
210
+ /** Load a JSON representation through the canonical contract boundary. */
211
+ export declare function loadCanonicalJsonArtifact(contractInput: unknown, input: unknown): CanonicalArtifactLoadResult;
212
+ /** Load native Markdown through the same parser and canonical contract. */
213
+ export declare function loadCanonicalMarkdownArtifact(contractInput: unknown, body: string | null | undefined): CanonicalArtifactLoadResult;
214
+ /** Existing-body spelling retained so read/repair callers share one boundary. */
215
+ export declare function loadCanonicalExistingArtifact(contractInput: unknown, body: string | null | undefined): CanonicalArtifactLoadResult;
216
+ /** Classify an artifact input envelope without applying semantic defaults. */
217
+ export declare function validatePartialArtifactInput(contractInput: unknown, input: unknown): PartialSemanticValidationResult;
218
+ /** Terminology alias for callers that treat validation as classification. */
219
+ export declare const classifyPartialArtifactInput: typeof validatePartialArtifactInput;
220
+ /** Merge only a targeted field patch into a prior stateless partial result. */
221
+ export declare function repairPartialArtifactInput(contractInput: unknown, previous: unknown, patch?: unknown): PartialSemanticRepairResult;
222
+ /** Terminology alias for callers that describe targeted repair as a merge. */
223
+ export declare const mergePartialArtifactInput: typeof repairPartialArtifactInput;
92
224
  export declare function renderIssueArtifact(contractInput: unknown, input: unknown): string;
93
225
  export declare function renderPullRequestArtifact(contractInput: unknown, input: unknown): string;
94
226
  /** Construct the only values accepted by the GitHub mutation adapter. */
@@ -96,7 +228,15 @@ export declare function prepareIssueArtifact(contractInput: unknown, input: Arti
96
228
  export declare function preparePullRequestArtifact(contractInput: unknown, input: ArtifactInputDocument): PreparedPullRequestArtifact;
97
229
  export declare function parseExistingIssueArtifact(contractInput: unknown, body: string | null | undefined): ExistingArtifactParseResult;
98
230
  export declare function parseExistingPullRequestArtifact(contractInput: unknown, body: string | null | undefined): ExistingArtifactParseResult;
99
- export declare function validateExistingIssueArtifact(contractInput: unknown, body: string | null | undefined): ExistingArtifactValidationResult;
231
+ /**
232
+ * Recover field values from a malformed or wrong-template body without
233
+ * weakening the strict existing-artifact parser. The section boundaries and
234
+ * field decoding are the same parser primitives used by strict parsing; only
235
+ * the order/complete-structure requirement is relaxed for an explicitly
236
+ * selected repair target.
237
+ */
238
+ export declare function recoverExistingArtifactValues(contractInput: unknown, body: string | null | undefined): RecoverableArtifactValues;
239
+ export declare function validateExistingIssueArtifact(contractInput: unknown, body: string | null | undefined, subject?: IssueReference): ExistingArtifactValidationResult;
100
240
  export declare function validateExistingPullRequestArtifact(contractInput: unknown, body: string | null | undefined): ExistingArtifactValidationResult;
101
241
  export interface ExistingArtifactCandidate {
102
242
  readonly contract: CanonicalContract;
@@ -111,6 +251,7 @@ export interface ExistingArtifactProjection {
111
251
  readonly projection: "canonical" | "unavailable";
112
252
  readonly classification: ExistingArtifactClassification;
113
253
  readonly fields?: Readonly<Record<string, unknown>>;
254
+ readonly dependencies?: IssueDependencies;
114
255
  readonly diagnostics: readonly ExistingArtifactDiagnostic[];
115
256
  readonly violations?: readonly SemanticViolation[];
116
257
  readonly attemptedTemplates?: readonly string[];
@@ -123,6 +264,8 @@ export declare function selectExistingArtifactCandidate(candidates: readonly Exi
123
264
  export declare function validateRequiredMetadataString(value: unknown, key: string): ArtifactMetadataViolation | undefined;
124
265
  export declare function validateExistingIssueFromAdapter(reader: ExistingIssueReader, contract: unknown, issueNumber: number): Promise<FetchedExistingArtifact>;
125
266
  export declare function validateExistingPullRequestFromAdapter(reader: ExistingPullRequestReader, contract: unknown, pullRequestNumber: number): Promise<FetchedExistingArtifact>;
267
+ /** @internal Validate the canonical Issue metadata handoff before mutation. */
268
+ export declare function verifyIssueMetadataRoundTrip(expected: Readonly<Record<string, unknown>>, artifact: ValidatedRenderedIssueArtifact): void;
126
269
  /** Escape only Markdown constructs that could change the canonical section structure. */
127
270
  export declare function escapeMarkdownValue(value: string): string;
128
271
  export declare function removeHtmlComments(value: string): string;