sortie-dogs 0.8.2 → 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 (90) hide show
  1. package/README.md +1 -1
  2. package/dist/asset-version.d.ts +1 -1
  3. package/dist/asset-version.js +1 -1
  4. package/dist/core/acceptance-compiler.d.ts +66 -0
  5. package/dist/core/acceptance-compiler.js +125 -0
  6. package/dist/core/adaptive-eligibility.d.ts +34 -0
  7. package/dist/core/adaptive-eligibility.js +98 -0
  8. package/dist/core/adaptive-progression.d.ts +35 -0
  9. package/dist/core/adaptive-progression.js +60 -0
  10. package/dist/core/adaptive-remediation-runtime.d.ts +133 -0
  11. package/dist/core/adaptive-remediation-runtime.js +249 -0
  12. package/dist/core/adaptive-signal-comparison.d.ts +29 -0
  13. package/dist/core/adaptive-signal-comparison.js +64 -0
  14. package/dist/core/child-cancellation-plan.d.ts +45 -0
  15. package/dist/core/child-cancellation-plan.js +87 -0
  16. package/dist/core/child-lifecycle-runtime.d.ts +46 -0
  17. package/dist/core/child-lifecycle-runtime.js +154 -0
  18. package/dist/core/child-terminal-reconciliation.d.ts +44 -0
  19. package/dist/core/child-terminal-reconciliation.js +134 -0
  20. package/dist/core/critical-path.d.ts +46 -0
  21. package/dist/core/critical-path.js +152 -0
  22. package/dist/core/evidence-capsule.d.ts +86 -0
  23. package/dist/core/evidence-capsule.js +278 -0
  24. package/dist/core/evidence-ledger-audit.d.ts +34 -0
  25. package/dist/core/evidence-ledger-audit.js +108 -0
  26. package/dist/core/execution-plan.d.ts +26 -0
  27. package/dist/core/execution-plan.js +134 -0
  28. package/dist/core/experience-evidence-summary.d.ts +36 -0
  29. package/dist/core/experience-evidence-summary.js +151 -0
  30. package/dist/core/experience-route-policy.d.ts +76 -0
  31. package/dist/core/experience-route-policy.js +187 -0
  32. package/dist/core/experience-routing-runtime.d.ts +95 -0
  33. package/dist/core/experience-routing-runtime.js +394 -0
  34. package/dist/core/failure-diagnosis.d.ts +48 -0
  35. package/dist/core/failure-diagnosis.js +92 -0
  36. package/dist/core/failure-swarm-plan.d.ts +63 -0
  37. package/dist/core/failure-swarm-plan.js +136 -0
  38. package/dist/core/failure-swarm-runtime.d.ts +91 -0
  39. package/dist/core/failure-swarm-runtime.js +189 -0
  40. package/dist/core/goal-bound.d.ts +249 -0
  41. package/dist/core/goal-bound.js +228 -0
  42. package/dist/core/recovery-outcome-aggregate.d.ts +98 -0
  43. package/dist/core/recovery-outcome-aggregate.js +267 -0
  44. package/dist/core/run-flight-ledger.d.ts +385 -0
  45. package/dist/core/run-flight-ledger.js +941 -0
  46. package/dist/core/scope-lease-registry.d.ts +2 -0
  47. package/dist/core/scope-lease-registry.js +9 -0
  48. package/dist/core/terminal-rescue-policy.d.ts +76 -0
  49. package/dist/core/terminal-rescue-policy.js +152 -0
  50. package/dist/core/terminal-rescue-runtime.d.ts +61 -0
  51. package/dist/core/terminal-rescue-runtime.js +107 -0
  52. package/dist/core/types.d.ts +136 -1
  53. package/dist/core/validate-schema.d.ts +2 -1
  54. package/dist/core/validate-schema.js +148 -0
  55. package/dist/core/validation-budget.d.ts +29 -0
  56. package/dist/core/validation-budget.js +29 -0
  57. package/dist/core/wave-boundary-replay.d.ts +50 -0
  58. package/dist/core/wave-boundary-replay.js +108 -0
  59. package/dist/core/worktree-commit-artifact.d.ts +16 -3
  60. package/dist/core/worktree-commit-artifact.js +89 -22
  61. package/dist/core/worktree-integration-queue.js +26 -5
  62. package/dist/core/worktree-lifecycle.d.ts +5 -0
  63. package/dist/core/worktree-lifecycle.js +143 -47
  64. package/dist/core/worktree-parallel-dispatch.d.ts +62 -1
  65. package/dist/core/worktree-parallel-dispatch.js +690 -52
  66. package/dist/index.d.ts +18 -0
  67. package/dist/index.js +9 -0
  68. package/dist/plugin/adaptive-remediation-host.d.ts +161 -0
  69. package/dist/plugin/adaptive-remediation-host.js +289 -0
  70. package/dist/plugin/continuation.d.ts +8 -1
  71. package/dist/plugin/continuation.js +23 -5
  72. package/dist/plugin/fast-lane.d.ts +2 -1
  73. package/dist/plugin/fast-lane.js +4 -2
  74. package/dist/plugin/index.d.ts +2 -0
  75. package/dist/plugin/index.js +1748 -63
  76. package/dist/plugin/model-routing-hook.d.ts +2 -0
  77. package/dist/plugin/model-routing-hook.js +12 -1
  78. package/dist/plugin/run-metrics.d.ts +56 -1
  79. package/dist/plugin/run-metrics.js +101 -2
  80. package/dist/plugin/terminal-rescue-binding.d.ts +13 -0
  81. package/dist/plugin/terminal-rescue-binding.js +40 -0
  82. package/dist/plugin/terminal-rescue-host.d.ts +69 -0
  83. package/dist/plugin/terminal-rescue-host.js +167 -0
  84. package/dist/reflection/managed-block.d.ts +34 -0
  85. package/dist/reflection/managed-block.js +128 -0
  86. package/dist/reflection/managed-sync.d.ts +18 -0
  87. package/dist/reflection/managed-sync.js +144 -0
  88. package/dist/runtime-assets.d.ts +8 -8
  89. package/dist/runtime-assets.js +134 -15
  90. package/package.json +6 -2
package/README.md CHANGED
@@ -24,7 +24,7 @@ Requirements: Node.js 22.6 or newer, npm, and OpenCode.
24
24
 
25
25
  Guides: [日本語](docs/guide-ja.md) · [简体中文](docs/guide-zh-CN.md) · [CLI testing](docs/cli-testing.md)
26
26
 
27
- Release: [v0.8.2](https://github.com/zufall-upon/Sortie-dogs/releases/tag/v0.8.2)
27
+ Release: [v0.9.0](https://github.com/zufall-upon/Sortie-dogs/releases/tag/v0.9.0)
28
28
 
29
29
  ## Quick start
30
30
 
@@ -2,5 +2,5 @@
2
2
  * Version of the installable runtime assets. Kept in its own module so the plugin can compare an
3
3
  * installed project marker without importing every asset body.
4
4
  */
5
- export declare const RUNTIME_ASSET_VERSION = "0.3.69-luna-combined-validation-replay-v1";
5
+ export declare const RUNTIME_ASSET_VERSION = "0.3.75-sequential-acceptance-parent-v1";
6
6
  export type RuntimeAssetVersion = typeof RUNTIME_ASSET_VERSION;
@@ -2,4 +2,4 @@
2
2
  * Version of the installable runtime assets. Kept in its own module so the plugin can compare an
3
3
  * installed project marker without importing every asset body.
4
4
  */
5
- export const RUNTIME_ASSET_VERSION = "0.3.69-luna-combined-validation-replay-v1";
5
+ export const RUNTIME_ASSET_VERSION = "0.3.75-sequential-acceptance-parent-v1";
@@ -0,0 +1,66 @@
1
+ import type { FlightReferenceSet } from "./run-flight-ledger.js";
2
+ export declare const ACCEPTANCE_COMPILER_VERSION: "0.1";
3
+ export declare const MAX_ACCEPTANCE_COMPILE_ITEMS = 64;
4
+ export declare const MAX_ACCEPTANCE_COMPILE_GAPS = 128;
5
+ export interface AcceptanceCompileItem {
6
+ readonly acceptance_id: string;
7
+ readonly observable_criterion: string;
8
+ }
9
+ export interface AcceptanceCompileValidation {
10
+ readonly validation_id: string;
11
+ readonly unit_id: string;
12
+ readonly command_fingerprint: string;
13
+ readonly references: FlightReferenceSet;
14
+ }
15
+ export interface AcceptanceCompileCoverage {
16
+ readonly acceptance_id: string;
17
+ readonly unit_id: string;
18
+ readonly validation_ids: readonly string[];
19
+ }
20
+ export interface AcceptanceCompileProposal {
21
+ readonly version: typeof ACCEPTANCE_COMPILER_VERSION;
22
+ readonly provenance: {
23
+ readonly producer: "dog-coordinator";
24
+ readonly acceptance_fingerprint: string;
25
+ /** The capsule producer, not this compiler, is responsible for excluding secrets from capsule input. */
26
+ readonly capsule_inputs_exclude_secrets: true;
27
+ };
28
+ /** Identifier boundary for later binding to LunaFabricUnit; scope/dependency data stays in the DAG contract. */
29
+ readonly unit_ids: readonly string[];
30
+ readonly declared_capsule_ids: readonly string[];
31
+ readonly acceptance_items: readonly AcceptanceCompileItem[];
32
+ readonly validations: readonly AcceptanceCompileValidation[];
33
+ readonly coverage: readonly AcceptanceCompileCoverage[];
34
+ }
35
+ export type AcceptanceCompileGapCode = "malformed_proposal" | "duplicate_acceptance_id" | "duplicate_unit_id" | "duplicate_validation_id" | "duplicate_coverage" | "unknown_acceptance_id" | "unknown_unit_id" | "unknown_validation_id" | "validation_unit_mismatch" | "undeclared_capsule" | "validation_evidence_missing" | "uncovered_acceptance";
36
+ export interface AcceptanceCompileGap {
37
+ readonly code: AcceptanceCompileGapCode;
38
+ readonly pointer: string;
39
+ readonly acceptance_id: string | null;
40
+ readonly unit_id: string | null;
41
+ readonly validation_id: string | null;
42
+ }
43
+ export interface AcceptanceCoverageMapEntry {
44
+ readonly acceptance_id: string;
45
+ readonly unit_id: string;
46
+ readonly validation_ids: readonly string[];
47
+ readonly references: FlightReferenceSet;
48
+ }
49
+ interface CompileResultBase {
50
+ readonly proposal_id: string;
51
+ readonly acceptance_fingerprint: string | null;
52
+ }
53
+ export type AcceptanceCompileResult = (CompileResultBase & {
54
+ readonly status: "accepted";
55
+ readonly plan_id: string;
56
+ readonly coverage_map: readonly AcceptanceCoverageMapEntry[];
57
+ readonly gaps: readonly AcceptanceCompileGap[];
58
+ }) | (CompileResultBase & {
59
+ readonly status: "rejected";
60
+ readonly plan_id: string;
61
+ readonly coverage_map: readonly AcceptanceCoverageMapEntry[];
62
+ readonly gaps: readonly AcceptanceCompileGap[];
63
+ });
64
+ /** Deterministic schema/semantic compiler. It performs no natural-language inference, dispatch, or user interaction. */
65
+ export declare function compileAcceptanceCoverage(value: unknown): AcceptanceCompileResult;
66
+ export {};
@@ -0,0 +1,125 @@
1
+ import { createHash } from "node:crypto";
2
+ export const ACCEPTANCE_COMPILER_VERSION = "0.1";
3
+ export const MAX_ACCEPTANCE_COMPILE_ITEMS = 64;
4
+ export const MAX_ACCEPTANCE_COMPILE_GAPS = 128;
5
+ const HASH = /^sha256:[a-f0-9]{64}$/u;
6
+ const ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u;
7
+ const MAX_TEXT = 1000;
8
+ const object = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
9
+ const only = (value, keys) => Object.keys(value).every((key) => keys.includes(key));
10
+ const id = (value) => typeof value === "string" && ID.test(value);
11
+ const hash = (value) => typeof value === "string" && HASH.test(value);
12
+ const text = (value) => typeof value === "string" && value.length > 0 && value.length <= MAX_TEXT && !/[\u0000-\u001f\u007f]/u.test(value);
13
+ function canonicalValue(value) {
14
+ if (Array.isArray(value))
15
+ return value.map(canonicalValue);
16
+ if (object(value))
17
+ return Object.fromEntries(Object.keys(value).sort().map((key) => [key, canonicalValue(value[key])]));
18
+ return value;
19
+ }
20
+ function identity(value) {
21
+ let body;
22
+ try {
23
+ body = JSON.stringify(canonicalValue(value));
24
+ }
25
+ catch {
26
+ body = "unserializable";
27
+ }
28
+ return `sha256:${createHash("sha256").update(body ?? "undefined").digest("hex")}`;
29
+ }
30
+ function freezeReferences(references) {
31
+ return Object.freeze({ capsule_ids: Object.freeze([...references.capsule_ids]), artifact_ids: Object.freeze([...references.artifact_ids]) });
32
+ }
33
+ function validReferences(value) {
34
+ return object(value) && only(value, ["capsule_ids", "artifact_ids"]) && Array.isArray(value.capsule_ids) && Array.isArray(value.artifact_ids) &&
35
+ value.capsule_ids.length <= MAX_ACCEPTANCE_COMPILE_ITEMS && value.artifact_ids.length <= MAX_ACCEPTANCE_COMPILE_ITEMS &&
36
+ value.capsule_ids.every(hash) && value.artifact_ids.every(hash) && new Set(value.capsule_ids).size === value.capsule_ids.length &&
37
+ new Set(value.artifact_ids).size === value.artifact_ids.length;
38
+ }
39
+ function malformed(value) {
40
+ if (!object(value) || !only(value, ["version", "provenance", "unit_ids", "declared_capsule_ids", "acceptance_items", "validations", "coverage"]) || value.version !== ACCEPTANCE_COMPILER_VERSION ||
41
+ !object(value.provenance) || !only(value.provenance, ["producer", "acceptance_fingerprint", "capsule_inputs_exclude_secrets"]) ||
42
+ value.provenance.producer !== "dog-coordinator" || !hash(value.provenance.acceptance_fingerprint) || value.provenance.capsule_inputs_exclude_secrets !== true)
43
+ return true;
44
+ const { unit_ids: unitIds, declared_capsule_ids: capsuleIds, acceptance_items: items, validations, coverage } = value;
45
+ if (![unitIds, capsuleIds, items, validations, coverage].every((entry) => Array.isArray(entry) && entry.length <= MAX_ACCEPTANCE_COMPILE_ITEMS) ||
46
+ !Array.isArray(items) || !Array.isArray(unitIds) || !Array.isArray(capsuleIds) || !Array.isArray(validations) || !Array.isArray(coverage) || items.length === 0 || unitIds.length === 0)
47
+ return true;
48
+ if (!unitIds.every(id) || !capsuleIds.every(hash))
49
+ return true;
50
+ if (!items.every((entry) => object(entry) && only(entry, ["acceptance_id", "observable_criterion"]) && id(entry.acceptance_id) && text(entry.observable_criterion)))
51
+ return true;
52
+ if (!validations.every((entry) => object(entry) && only(entry, ["validation_id", "unit_id", "command_fingerprint", "references"]) && id(entry.validation_id) && id(entry.unit_id) && hash(entry.command_fingerprint) && validReferences(entry.references)))
53
+ return true;
54
+ return !coverage.every((entry) => object(entry) && only(entry, ["acceptance_id", "unit_id", "validation_ids"]) && id(entry.acceptance_id) && id(entry.unit_id) &&
55
+ Array.isArray(entry.validation_ids) && entry.validation_ids.length > 0 && entry.validation_ids.length <= MAX_ACCEPTANCE_COMPILE_ITEMS && entry.validation_ids.every(id));
56
+ }
57
+ function gap(code, pointer, acceptanceId = null, unitId = null, validationId = null) {
58
+ return Object.freeze({ code, pointer, acceptance_id: acceptanceId, unit_id: unitId, validation_id: validationId });
59
+ }
60
+ function duplicates(values) {
61
+ const seen = new Set();
62
+ return new Set(values.filter((value) => seen.has(value) || !seen.add(value)));
63
+ }
64
+ /** Deterministic schema/semantic compiler. It performs no natural-language inference, dispatch, or user interaction. */
65
+ export function compileAcceptanceCoverage(value) {
66
+ const proposalId = identity(value);
67
+ if (malformed(value))
68
+ return Object.freeze({ status: "rejected", proposal_id: proposalId, plan_id: identity({ proposal_id: proposalId, status: "rejected", gaps: ["malformed_proposal"] }), acceptance_fingerprint: null, coverage_map: Object.freeze([]), gaps: Object.freeze([gap("malformed_proposal", "/")]) });
69
+ const proposal = value;
70
+ const gaps = [];
71
+ const itemIds = proposal.acceptance_items.map((entry) => entry.acceptance_id);
72
+ const validationIds = proposal.validations.map((entry) => entry.validation_id);
73
+ for (const duplicate of duplicates(itemIds))
74
+ gaps.push(gap("duplicate_acceptance_id", "/acceptance_items", duplicate));
75
+ for (const duplicate of duplicates(proposal.unit_ids))
76
+ gaps.push(gap("duplicate_unit_id", "/unit_ids", null, duplicate));
77
+ for (const duplicate of duplicates(validationIds))
78
+ gaps.push(gap("duplicate_validation_id", "/validations", null, null, duplicate));
79
+ for (const duplicate of duplicates(proposal.coverage.map((entry) => entry.acceptance_id)))
80
+ gaps.push(gap("duplicate_coverage", "/coverage", duplicate));
81
+ const items = new Set(itemIds);
82
+ const units = new Set(proposal.unit_ids);
83
+ const declaredCapsules = new Set(proposal.declared_capsule_ids);
84
+ const validations = new Map(proposal.validations.map((entry) => [entry.validation_id, entry]));
85
+ proposal.validations.forEach((validation, index) => {
86
+ if (!units.has(validation.unit_id))
87
+ gaps.push(gap("unknown_unit_id", `/validations/${index}/unit_id`, null, validation.unit_id, validation.validation_id));
88
+ if (validation.references.capsule_ids.length + validation.references.artifact_ids.length === 0)
89
+ gaps.push(gap("validation_evidence_missing", `/validations/${index}/references`, null, validation.unit_id, validation.validation_id));
90
+ for (const capsuleId of validation.references.capsule_ids)
91
+ if (!declaredCapsules.has(capsuleId))
92
+ gaps.push(gap("undeclared_capsule", `/validations/${index}/references/capsule_ids`, null, validation.unit_id, validation.validation_id));
93
+ });
94
+ proposal.coverage.forEach((entry, index) => {
95
+ if (!items.has(entry.acceptance_id))
96
+ gaps.push(gap("unknown_acceptance_id", `/coverage/${index}/acceptance_id`, entry.acceptance_id, entry.unit_id));
97
+ if (!units.has(entry.unit_id))
98
+ gaps.push(gap("unknown_unit_id", `/coverage/${index}/unit_id`, entry.acceptance_id, entry.unit_id));
99
+ for (const validationId of entry.validation_ids) {
100
+ const validation = validations.get(validationId);
101
+ if (validation === undefined)
102
+ gaps.push(gap("unknown_validation_id", `/coverage/${index}/validation_ids`, entry.acceptance_id, entry.unit_id, validationId));
103
+ else if (validation.unit_id !== entry.unit_id)
104
+ gaps.push(gap("validation_unit_mismatch", `/coverage/${index}/validation_ids`, entry.acceptance_id, entry.unit_id, validationId));
105
+ }
106
+ });
107
+ const covered = new Set(proposal.coverage.map((entry) => entry.acceptance_id));
108
+ proposal.acceptance_items.forEach((entry, index) => { if (!covered.has(entry.acceptance_id))
109
+ gaps.push(gap("uncovered_acceptance", `/acceptance_items/${index}`, entry.acceptance_id)); });
110
+ const bounded = gaps.slice(0, MAX_ACCEPTANCE_COMPILE_GAPS);
111
+ if (bounded.length > 0) {
112
+ const frozenGaps = Object.freeze(bounded);
113
+ return Object.freeze({ status: "rejected", proposal_id: proposalId, plan_id: identity({ proposal_id: proposalId, status: "rejected", gaps: frozenGaps }), acceptance_fingerprint: proposal.provenance.acceptance_fingerprint, coverage_map: Object.freeze([]), gaps: frozenGaps });
114
+ }
115
+ const coverageMap = proposal.acceptance_items.map((item) => {
116
+ const coverage = proposal.coverage.find((entry) => entry.acceptance_id === item.acceptance_id);
117
+ const references = coverage.validation_ids.reduce((result, validationId) => {
118
+ const source = validations.get(validationId).references;
119
+ return { capsule_ids: [...new Set([...result.capsule_ids, ...source.capsule_ids])], artifact_ids: [...new Set([...result.artifact_ids, ...source.artifact_ids])] };
120
+ }, { capsule_ids: [], artifact_ids: [] });
121
+ return Object.freeze({ acceptance_id: item.acceptance_id, unit_id: coverage.unit_id, validation_ids: Object.freeze([...coverage.validation_ids]), references: freezeReferences(references) });
122
+ });
123
+ const planId = identity({ acceptance_fingerprint: proposal.provenance.acceptance_fingerprint, coverage_map: coverageMap });
124
+ return Object.freeze({ status: "accepted", proposal_id: proposalId, plan_id: planId, acceptance_fingerprint: proposal.provenance.acceptance_fingerprint, coverage_map: Object.freeze(coverageMap), gaps: Object.freeze([]) });
125
+ }
@@ -0,0 +1,34 @@
1
+ import type { AdaptiveRemediationPlatform, AdaptiveRemediationSelection } from "./types.js";
2
+ type Observation = boolean | null;
3
+ export interface AdaptiveEligibilityInput {
4
+ readonly platform: AdaptiveRemediationPlatform;
5
+ readonly canonical_validation_expensive: Observation;
6
+ readonly repeatable_typed_signal: Observation;
7
+ readonly signal_id: string | null;
8
+ readonly signal_definition: string | null;
9
+ readonly patch_reversible: Observation;
10
+ readonly patch_isolated: Observation;
11
+ readonly scope_bounded: Observation;
12
+ readonly security_sensitive: Observation;
13
+ readonly schema_migration: Observation;
14
+ readonly release_or_publication: Observation;
15
+ readonly irreversible_external_operation: Observation;
16
+ readonly explicit_standard_override: Observation;
17
+ }
18
+ export type AdaptiveEligibilityDetailReason = "eligible" | "explicit-standard-override" | "security-sensitive" | "schema-migration" | "release-or-publication" | "irreversible-external-operation" | "canonical-validation-not-expensive" | "canonical-validation-unknown" | "signal-not-repeatable" | "signal-repeatability-unknown" | "signal-undefined" | "patch-not-reversible" | "patch-reversibility-unknown" | "patch-not-isolated" | "patch-isolation-unknown" | "scope-not-bounded" | "scope-bounds-unknown" | "risk-status-unknown";
19
+ export type AdaptiveEligibilityRejectionReason = "invalid-input" | "unsupported-platform";
20
+ export type AdaptiveEligibilityOutcome = {
21
+ readonly status: "selected";
22
+ readonly selection: AdaptiveRemediationSelection;
23
+ readonly detail_reason: AdaptiveEligibilityDetailReason;
24
+ } | {
25
+ readonly status: "rejected";
26
+ readonly selection: null;
27
+ readonly reason: AdaptiveEligibilityRejectionReason;
28
+ };
29
+ /**
30
+ * Selects an inert remediation mode from declared eligibility observations only.
31
+ * It does not probe the platform, construct a runtime contract, or perform remediation.
32
+ */
33
+ export declare function selectAdaptiveRemediation(input: unknown): AdaptiveEligibilityOutcome;
34
+ export {};
@@ -0,0 +1,98 @@
1
+ const INPUT_KEYS = [
2
+ "platform",
3
+ "canonical_validation_expensive",
4
+ "repeatable_typed_signal",
5
+ "signal_id",
6
+ "signal_definition",
7
+ "patch_reversible",
8
+ "patch_isolated",
9
+ "scope_bounded",
10
+ "security_sensitive",
11
+ "schema_migration",
12
+ "release_or_publication",
13
+ "irreversible_external_operation",
14
+ "explicit_standard_override",
15
+ ];
16
+ const OBSERVATION_KEYS = [
17
+ "canonical_validation_expensive",
18
+ "repeatable_typed_signal",
19
+ "patch_reversible",
20
+ "patch_isolated",
21
+ "scope_bounded",
22
+ "security_sensitive",
23
+ "schema_migration",
24
+ "release_or_publication",
25
+ "irreversible_external_operation",
26
+ "explicit_standard_override",
27
+ ];
28
+ const isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
29
+ const isObservation = (value) => value === true || value === false || value === null;
30
+ const isOptionalIdentifier = (value) => value === null || (typeof value === "string" && value.length > 0 && value.trim() === value);
31
+ function selection(platform, mode, reason, detailReason) {
32
+ return {
33
+ status: "selected",
34
+ selection: { mode, reason, activation_reason: detailReason, platform },
35
+ detail_reason: detailReason,
36
+ };
37
+ }
38
+ /**
39
+ * Selects an inert remediation mode from declared eligibility observations only.
40
+ * It does not probe the platform, construct a runtime contract, or perform remediation.
41
+ */
42
+ export function selectAdaptiveRemediation(input) {
43
+ if (!isObject(input) || Object.keys(input).some((key) => !INPUT_KEYS.includes(key)) ||
44
+ !OBSERVATION_KEYS.every((key) => Object.hasOwn(input, key) && isObservation(input[key])) ||
45
+ !Object.hasOwn(input, "signal_id") || !isOptionalIdentifier(input.signal_id) ||
46
+ !Object.hasOwn(input, "signal_definition") || !isOptionalIdentifier(input.signal_definition)) {
47
+ return { status: "rejected", selection: null, reason: "invalid-input" };
48
+ }
49
+ if (input.platform !== "windows" && input.platform !== "wsl") {
50
+ return { status: "rejected", selection: null, reason: "unsupported-platform" };
51
+ }
52
+ const platform = input.platform;
53
+ if (input.explicit_standard_override === true) {
54
+ return selection(platform, "standard", "unsafe-target", "explicit-standard-override");
55
+ }
56
+ if (input.security_sensitive === true) {
57
+ return selection(platform, "standard", "unsafe-target", "security-sensitive");
58
+ }
59
+ if (input.schema_migration === true) {
60
+ return selection(platform, "standard", "unsafe-target", "schema-migration");
61
+ }
62
+ if (input.release_or_publication === true) {
63
+ return selection(platform, "standard", "unsafe-target", "release-or-publication");
64
+ }
65
+ if (input.irreversible_external_operation === true) {
66
+ return selection(platform, "standard", "unsafe-target", "irreversible-external-operation");
67
+ }
68
+ if ([
69
+ input.security_sensitive,
70
+ input.schema_migration,
71
+ input.release_or_publication,
72
+ input.irreversible_external_operation,
73
+ input.explicit_standard_override,
74
+ ].some((value) => value === null)) {
75
+ return selection(platform, "standard", "unsafe-target", "risk-status-unknown");
76
+ }
77
+ if (input.canonical_validation_expensive !== true) {
78
+ return selection(platform, "standard", "validation-ineligible", input.canonical_validation_expensive === false
79
+ ? "canonical-validation-not-expensive"
80
+ : "canonical-validation-unknown");
81
+ }
82
+ if (input.repeatable_typed_signal !== true) {
83
+ return selection(platform, "standard", "validation-ineligible", input.repeatable_typed_signal === false ? "signal-not-repeatable" : "signal-repeatability-unknown");
84
+ }
85
+ if (input.signal_id === null || input.signal_definition === null) {
86
+ return selection(platform, "standard", "validation-ineligible", "signal-undefined");
87
+ }
88
+ if (input.patch_reversible !== true) {
89
+ return selection(platform, "standard", "unsafe-target", input.patch_reversible === false ? "patch-not-reversible" : "patch-reversibility-unknown");
90
+ }
91
+ if (input.patch_isolated !== true) {
92
+ return selection(platform, "standard", "scope-ineligible", input.patch_isolated === false ? "patch-not-isolated" : "patch-isolation-unknown");
93
+ }
94
+ if (input.scope_bounded !== true) {
95
+ return selection(platform, "standard", "scope-ineligible", input.scope_bounded === false ? "scope-not-bounded" : "scope-bounds-unknown");
96
+ }
97
+ return selection(platform, "adaptive-remediation", "eligible-auto", "eligible");
98
+ }
@@ -0,0 +1,35 @@
1
+ import type { AdaptiveRemediationContract, AdaptiveRemediationFailureCode, AdaptiveRemediationIteration } from "./types.js";
2
+ export type AdaptiveProgressionRejectionCode = "iteration-sequence-mismatch" | "iteration-count-mismatch" | "validation-count-mismatch" | "selection-metrics-mismatch" | "iteration-state-mismatch" | "cleanup-state-mismatch" | "convergence-state-mismatch" | "review-state-mismatch" | "promotion-state-mismatch" | "verification-state-mismatch";
3
+ export type AdaptiveProgressionHoldReason = "standard-mode" | "initial-iteration-pending" | "review-remediation-required";
4
+ export type AdaptiveProgressionRequest = {
5
+ readonly phase: "probe";
6
+ readonly iteration: AdaptiveRemediationIteration["iteration"];
7
+ } | {
8
+ readonly phase: "full-validation";
9
+ } | {
10
+ readonly phase: "review";
11
+ } | {
12
+ readonly phase: "promotion";
13
+ readonly expected_target_head: string;
14
+ readonly candidate_head: string;
15
+ } | {
16
+ readonly phase: "post-merge-validation";
17
+ };
18
+ export type AdaptiveProgressionDecision = {
19
+ readonly kind: "rejected";
20
+ readonly code: AdaptiveProgressionRejectionCode;
21
+ readonly detail: string;
22
+ } | {
23
+ readonly kind: "hold";
24
+ readonly reason: AdaptiveProgressionHoldReason;
25
+ } | {
26
+ readonly kind: "request";
27
+ readonly request: AdaptiveProgressionRequest;
28
+ } | {
29
+ readonly kind: "stop";
30
+ readonly reason: AdaptiveRemediationFailureCode;
31
+ } | {
32
+ readonly kind: "complete";
33
+ };
34
+ /** Pure consistency guard mirroring the executing runtime's non-skippable stage order. */
35
+ export declare function decideAdaptiveProgression(contract: AdaptiveRemediationContract): AdaptiveProgressionDecision;
@@ -0,0 +1,60 @@
1
+ const reject = (code, detail) => ({ kind: "rejected", code, detail });
2
+ /** Pure consistency guard mirroring the executing runtime's non-skippable stage order. */
3
+ export function decideAdaptiveProgression(contract) {
4
+ for (let index = 0; index < contract.iterations.length; index += 1) {
5
+ if (contract.iterations[index]?.iteration !== index + 1)
6
+ return reject("iteration-sequence-mismatch", "Iterations must be consecutive from one.");
7
+ }
8
+ if (contract.iterations.length !== contract.metrics.iteration_count)
9
+ return reject("iteration-count-mismatch", "Iteration metric differs from evidence.");
10
+ const expectedProbes = (contract.baseline_probe === null ? 0 : 1) + contract.iterations.length;
11
+ const expectedFull = contract.full_validation.status === "pending" ? 0 : 1;
12
+ const expectedPost = contract.post_merge.status === "pending" ? 0 : 1;
13
+ if (contract.metrics.probe_count !== expectedProbes || contract.metrics.full_validation_count !== expectedFull ||
14
+ contract.metrics.post_merge_validation_count !== expectedPost)
15
+ return reject("validation-count-mismatch", "Validation counts differ from measured evidence.");
16
+ if (contract.metrics.mode !== contract.selection.mode || contract.metrics.reason !== contract.selection.reason ||
17
+ contract.metrics.activation_reason !== contract.selection.activation_reason)
18
+ return reject("selection-metrics-mismatch", "Selection audit fields differ.");
19
+ if (contract.iterations.some((entry) => entry.cleanup.status === "pass" && entry.cleanup.remaining_paths.length > 0)) {
20
+ return reject("cleanup-state-mismatch", "Passing cleanup retains residue.");
21
+ }
22
+ for (const entry of contract.iterations.slice(0, -1)) {
23
+ if (entry.measured_probe.outcome !== "improved" || entry.cleanup.status !== "pass")
24
+ return reject("iteration-state-mismatch", "Only improved clean candidates may be refined.");
25
+ }
26
+ const latest = contract.iterations.at(-1);
27
+ if (contract.converged && (latest?.measured_probe.outcome !== "improved" || latest.cleanup.status !== "pass")) {
28
+ return reject("convergence-state-mismatch", "Convergence requires measured improvement and cleanup.");
29
+ }
30
+ if (!contract.converged && contract.full_validation.status !== "pending")
31
+ return reject("convergence-state-mismatch", "Canonical validation preceded convergence.");
32
+ if (contract.review.status !== "pending" && contract.full_validation.status !== "pass")
33
+ return reject("review-state-mismatch", "Review preceded canonical success.");
34
+ if (contract.promotion.status !== "pending" && contract.review.status !== "pass")
35
+ return reject("promotion-state-mismatch", "Promotion preceded review approval.");
36
+ if (contract.post_merge.status !== "pending" && contract.promotion.status !== "promoted")
37
+ return reject("verification-state-mismatch", "Post-merge validation preceded promotion.");
38
+ if (contract.state === "VERIFIED") {
39
+ if (contract.post_merge.status !== "pass" || contract.failure !== null)
40
+ return reject("verification-state-mismatch", "VERIFIED requires passing post-merge evidence and no failure.");
41
+ return { kind: "complete" };
42
+ }
43
+ if (contract.failure !== null)
44
+ return { kind: "stop", reason: contract.failure.code };
45
+ if (contract.selection.mode === "standard")
46
+ return { kind: "hold", reason: "standard-mode" };
47
+ if (latest === undefined)
48
+ return { kind: "hold", reason: "initial-iteration-pending" };
49
+ if (!contract.converged)
50
+ return { kind: "request", request: { phase: "probe", iteration: (contract.iterations.length + 1) } };
51
+ if (contract.full_validation.status === "pending")
52
+ return { kind: "request", request: { phase: "full-validation" } };
53
+ if (contract.review.status === "pending")
54
+ return { kind: "request", request: { phase: "review" } };
55
+ if (contract.review.status === "remediation-required")
56
+ return { kind: "hold", reason: "review-remediation-required" };
57
+ if (contract.promotion.status === "pending")
58
+ return { kind: "request", request: { phase: "promotion", expected_target_head: contract.promotion.expected_target_head, candidate_head: latest.candidate_head } };
59
+ return { kind: "request", request: { phase: "post-merge-validation" } };
60
+ }
@@ -0,0 +1,133 @@
1
+ import { type AdaptiveEligibilityInput } from "./adaptive-eligibility.js";
2
+ import { RunFlightLedger } from "./run-flight-ledger.js";
3
+ import type { AdaptiveRemediationCommand, AdaptiveRemediationContract, AdaptiveRemediationProbeCommand, AdaptiveRemediationSignal, AdaptiveRemediationValidationEvidence } from "./types.js";
4
+ export interface AdaptiveRemediationRequest {
5
+ readonly task_id: string;
6
+ readonly eligibility: AdaptiveEligibilityInput;
7
+ readonly target_ref: string;
8
+ readonly allowed_paths: {
9
+ readonly read: readonly string[];
10
+ readonly write: readonly string[];
11
+ };
12
+ readonly iteration_budget: 1 | 2 | 3;
13
+ readonly max_changed_paths: number;
14
+ readonly cleanup_timeout_ms: number;
15
+ readonly probe_validation: AdaptiveRemediationProbeCommand;
16
+ readonly canonical_validation: AdaptiveRemediationCommand;
17
+ readonly improvement_signal: AdaptiveRemediationSignal;
18
+ readonly risk_class: "low" | "medium" | "high";
19
+ readonly post_merge_validation: AdaptiveRemediationCommand;
20
+ readonly acceptance: readonly string[];
21
+ }
22
+ export interface AdaptiveProbeEvidence {
23
+ readonly command: readonly string[];
24
+ readonly exit_code: number | null;
25
+ readonly fingerprint: string;
26
+ readonly signal_id: string;
27
+ readonly value: number | null;
28
+ }
29
+ export interface AdaptiveCandidate {
30
+ readonly worktree_id: string;
31
+ readonly path: string;
32
+ readonly parent_head: string;
33
+ }
34
+ export interface AdaptivePatchEvidence {
35
+ readonly candidate: AdaptiveCandidate;
36
+ readonly candidate_head: string;
37
+ readonly hypothesis: string;
38
+ readonly patch_fingerprint: string;
39
+ readonly changed_paths: readonly string[];
40
+ readonly probe: AdaptiveProbeEvidence;
41
+ }
42
+ export interface AdaptiveRemediationRuntimeHost {
43
+ snapshotTarget(targetRef: string): Promise<{
44
+ readonly head: string;
45
+ readonly tree: string;
46
+ }>;
47
+ openCandidate(parentHead: string, iteration: 1 | 2 | 3): Promise<AdaptiveCandidate>;
48
+ runBaselineProbe(candidate: AdaptiveCandidate, command: AdaptiveRemediationProbeCommand): Promise<AdaptiveProbeEvidence>;
49
+ producePatch(input: {
50
+ readonly candidate: AdaptiveCandidate;
51
+ readonly iteration: 1 | 2 | 3;
52
+ readonly acceptance: readonly string[];
53
+ readonly allowed_paths: AdaptiveRemediationRequest["allowed_paths"];
54
+ readonly probe_validation: AdaptiveRemediationProbeCommand;
55
+ }): Promise<AdaptivePatchEvidence>;
56
+ reserveProbe?(input: {
57
+ readonly task_id: string;
58
+ readonly iteration: 1 | 2 | 3;
59
+ readonly parent_candidate: string;
60
+ }): Promise<string>;
61
+ finishProbe?(input: {
62
+ readonly reservation_id: string;
63
+ readonly patch: AdaptivePatchEvidence;
64
+ readonly duration_ms: number;
65
+ }): Promise<void>;
66
+ failProbe?(input: {
67
+ readonly reservation_id: string;
68
+ readonly duration_ms: number;
69
+ readonly code: string;
70
+ }): Promise<void>;
71
+ inspectCleanup(candidate: AdaptiveCandidate, timeoutMs: number): Promise<{
72
+ readonly ok: boolean;
73
+ readonly remaining_paths: readonly string[];
74
+ }>;
75
+ discardCandidate(candidate: AdaptiveCandidate): Promise<void>;
76
+ runCanonical(candidate: AdaptiveCandidate, command: AdaptiveRemediationCommand): Promise<AdaptiveRemediationValidationEvidence>;
77
+ review(input: {
78
+ readonly candidate: AdaptiveCandidate;
79
+ readonly candidate_head: string;
80
+ readonly risk_class: AdaptiveRemediationRequest["risk_class"];
81
+ }): Promise<{
82
+ readonly status: "pass" | "remediation-required" | "fail";
83
+ readonly fingerprint: string;
84
+ }>;
85
+ promote(input: {
86
+ readonly target_ref: string;
87
+ readonly expected_head: string;
88
+ readonly candidate_head: string;
89
+ }): Promise<{
90
+ readonly status: "promoted" | "cas-drift";
91
+ readonly observed_head: string;
92
+ }>;
93
+ runPostMerge(command: AdaptiveRemediationCommand): Promise<AdaptiveRemediationValidationEvidence>;
94
+ release(candidates: readonly AdaptiveCandidate[]): Promise<{
95
+ readonly ok: boolean;
96
+ readonly remaining_paths: readonly string[];
97
+ }>;
98
+ }
99
+ export interface AdaptiveLineageOptions {
100
+ readonly ledger: RunFlightLedger;
101
+ readonly unit_id: string;
102
+ readonly route_id: string;
103
+ readonly candidate_id: string;
104
+ readonly selected_model: string;
105
+ readonly selected_variant: string | null;
106
+ readonly predecessor_attempt_id: string | null;
107
+ /** Set only when a model is actually dispatched for each patch. */
108
+ readonly model_attempt_per_patch: boolean;
109
+ }
110
+ /** Shared RunFlightLedger adapter: probe iterations charge the existing cumulative recovery authority. */
111
+ export declare class AdaptiveRunFlightLineage {
112
+ readonly options: AdaptiveLineageOptions;
113
+ private predecessor;
114
+ private readonly reservations;
115
+ constructor(options: AdaptiveLineageOptions);
116
+ reserveProbe(): Promise<string>;
117
+ finishProbe(input: {
118
+ readonly reservation_id: string;
119
+ readonly patch: AdaptivePatchEvidence;
120
+ readonly duration_ms: number;
121
+ }): Promise<void>;
122
+ failProbe(input: {
123
+ readonly reservation_id: string;
124
+ readonly duration_ms: number;
125
+ readonly code: string;
126
+ }): Promise<void>;
127
+ }
128
+ /** Executes the bounded state machine. Hosts own process/worktree mechanics; evidence cannot skip a stage. */
129
+ export declare class AdaptiveRemediationRuntime {
130
+ readonly host: AdaptiveRemediationRuntimeHost;
131
+ constructor(host: AdaptiveRemediationRuntimeHost);
132
+ execute(request: AdaptiveRemediationRequest): Promise<AdaptiveRemediationContract>;
133
+ }