@davesheffer/hunch 1.31.1 → 1.32.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 (220) hide show
  1. package/README.md +1 -0
  2. package/dist/cli/automaticReviewMemory.d.ts +13 -0
  3. package/dist/cli/dna.d.ts +2 -0
  4. package/dist/cli/index.d.ts +16 -0
  5. package/dist/cli/index.js +602 -43
  6. package/dist/cli/integrations.d.ts +2 -0
  7. package/dist/cli/integrations.js +5 -2
  8. package/dist/cli/invocation.d.ts +35 -0
  9. package/dist/cli/preflight.d.ts +1 -0
  10. package/dist/cli/reviewMemory.d.ts +4 -0
  11. package/dist/cli/reviewMemoryProvider.d.ts +14 -0
  12. package/dist/cli/serve.d.ts +2 -0
  13. package/dist/cli/taskReport.d.ts +6 -0
  14. package/dist/cli/taskReport.js +124 -0
  15. package/dist/cli/update.d.ts +14 -0
  16. package/dist/client/state.d.ts +248 -0
  17. package/dist/constitution/adapters.d.ts +29 -0
  18. package/dist/constitution/behaviorAttestationBinding.d.ts +3 -0
  19. package/dist/constitution/behaviorEvaluator.d.ts +8 -0
  20. package/dist/constitution/behaviorProof.d.ts +9 -0
  21. package/dist/constitution/behaviorWorkspace.d.ts +25 -0
  22. package/dist/constitution/bootstrap.d.ts +30 -0
  23. package/dist/constitution/canonical.d.ts +15 -0
  24. package/dist/constitution/card.d.ts +58 -0
  25. package/dist/constitution/compiler.d.ts +52 -0
  26. package/dist/constitution/composition.d.ts +10 -0
  27. package/dist/constitution/corpus.d.ts +7 -0
  28. package/dist/constitution/correctionPolicyMaterializer.d.ts +57 -0
  29. package/dist/constitution/delta.d.ts +4 -0
  30. package/dist/constitution/disposition.d.ts +20 -0
  31. package/dist/constitution/evaluator.d.ts +47 -0
  32. package/dist/constitution/experiment.d.ts +466 -0
  33. package/dist/constitution/experimentRunner.d.ts +7 -0
  34. package/dist/constitution/g2.d.ts +209 -0
  35. package/dist/constitution/g2BehaviorAttestation.d.ts +45 -0
  36. package/dist/constitution/g2BehaviorCandidates.d.ts +123 -0
  37. package/dist/constitution/g2BehaviorDependencies.d.ts +83 -0
  38. package/dist/constitution/g2BehaviorMaterialization.d.ts +77 -0
  39. package/dist/constitution/g2BehaviorPolicyMaterializer.d.ts +48 -0
  40. package/dist/constitution/g2CandidateAttestation.d.ts +43 -0
  41. package/dist/constitution/g2Candidates.d.ts +80 -0
  42. package/dist/constitution/g2Drills.d.ts +33 -0
  43. package/dist/constitution/g3.d.ts +311 -0
  44. package/dist/constitution/g3Conformance.d.ts +33 -0
  45. package/dist/constitution/lifecycle.d.ts +25 -0
  46. package/dist/constitution/mutation.d.ts +15 -0
  47. package/dist/constitution/nodeTestEvidence.d.ts +13 -0
  48. package/dist/constitution/plan.d.ts +18 -0
  49. package/dist/constitution/policyRuntime.d.ts +5 -0
  50. package/dist/constitution/proof.d.ts +11 -0
  51. package/dist/constitution/repairPolicies.d.ts +34 -0
  52. package/dist/constitution/replacementFreeGit.d.ts +14 -0
  53. package/dist/constitution/replay.d.ts +40 -0
  54. package/dist/constitution/replayCache.d.ts +14 -0
  55. package/dist/constitution/replayWorker.d.ts +1 -0
  56. package/dist/constitution/repository.d.ts +129 -0
  57. package/dist/constitution/safeCheckout.d.ts +9 -0
  58. package/dist/constitution/schema.d.ts +1763 -0
  59. package/dist/constitution/scorecard.d.ts +219 -0
  60. package/dist/constitution/service.d.ts +398 -0
  61. package/dist/constitution/shadow.d.ts +54 -0
  62. package/dist/constitution/sourceMutation.d.ts +15 -0
  63. package/dist/constitution/staticGraphBaseline.d.ts +13 -0
  64. package/dist/constitution/structural.d.ts +64 -0
  65. package/dist/core/agenthook.d.ts +63 -0
  66. package/dist/core/agenthook.js +1 -0
  67. package/dist/core/automaticReviewMemory.d.ts +60 -0
  68. package/dist/core/autoreview.d.ts +66 -0
  69. package/dist/core/canonicalOrder.d.ts +3 -0
  70. package/dist/core/capturetoken.d.ts +19 -0
  71. package/dist/core/changeIdentity.d.ts +22 -0
  72. package/dist/core/changeProof.d.ts +14 -0
  73. package/dist/core/checkreport.d.ts +140 -0
  74. package/dist/core/commitrepair.d.ts +171 -0
  75. package/dist/core/commitrepair.js +238 -0
  76. package/dist/core/compare.d.ts +21 -0
  77. package/dist/core/config.d.ts +20 -0
  78. package/dist/core/conformance.d.ts +35 -0
  79. package/dist/core/constraintmatch.d.ts +54 -0
  80. package/dist/core/correction.d.ts +42 -0
  81. package/dist/core/correctionStage.d.ts +224 -0
  82. package/dist/core/declarationClusters.d.ts +149 -0
  83. package/dist/core/delivery.d.ts +110 -0
  84. package/dist/core/docanchors.d.ts +32 -0
  85. package/dist/core/docscan.d.ts +26 -0
  86. package/dist/core/drift.d.ts +13 -0
  87. package/dist/core/drift.js +31 -1
  88. package/dist/core/dupdetect.d.ts +43 -0
  89. package/dist/core/escalations.d.ts +129 -0
  90. package/dist/core/escalations.js +165 -0
  91. package/dist/core/events.d.ts +29 -0
  92. package/dist/core/evidenceMap.d.ts +164 -0
  93. package/dist/core/externalImports.d.ts +8 -0
  94. package/dist/core/format.d.ts +13 -0
  95. package/dist/core/glob.d.ts +9 -0
  96. package/dist/core/groundingLag.d.ts +84 -0
  97. package/dist/core/groundingLag.js +16 -2
  98. package/dist/core/groundingMerge.d.ts +15 -0
  99. package/dist/core/groundingMerge.js +95 -0
  100. package/dist/core/hookcache.d.ts +10 -0
  101. package/dist/core/hookpolicy.d.ts +47 -0
  102. package/dist/core/ids.d.ts +36 -0
  103. package/dist/core/importReview.d.ts +30 -0
  104. package/dist/core/io.d.ts +23 -0
  105. package/dist/core/jsonc.d.ts +4 -0
  106. package/dist/core/landscapeAdoption.d.ts +66 -0
  107. package/dist/core/landscapeDelivery.d.ts +76 -0
  108. package/dist/core/memorylog.d.ts +37 -0
  109. package/dist/core/migrate.d.ts +28 -0
  110. package/dist/core/outcomeExperience.d.ts +89 -0
  111. package/dist/core/overlaySafety.d.ts +24 -0
  112. package/dist/core/overlaySafety.js +7 -1
  113. package/dist/core/paths.d.ts +31 -0
  114. package/dist/core/pipeline.d.ts +289 -0
  115. package/dist/core/premises.d.ts +43 -0
  116. package/dist/core/provenance.d.ts +21 -0
  117. package/dist/core/publication.d.ts +54 -0
  118. package/dist/core/refrepair.d.ts +24 -0
  119. package/dist/core/refrepair.js +1 -1
  120. package/dist/core/relativeImports.d.ts +11 -0
  121. package/dist/core/repair.d.ts +44 -0
  122. package/dist/core/repairqueue.d.ts +40 -0
  123. package/dist/core/repairqueue.js +133 -0
  124. package/dist/core/reviewMemory.d.ts +40 -0
  125. package/dist/core/reviewqueue.d.ts +54 -0
  126. package/dist/core/safeRepoFile.d.ts +20 -0
  127. package/dist/core/served.d.ts +57 -0
  128. package/dist/core/served.js +14 -0
  129. package/dist/core/stateContract.d.ts +979 -0
  130. package/dist/core/stateDelivery.d.ts +78 -0
  131. package/dist/core/stateRecords.d.ts +383 -0
  132. package/dist/core/stats.d.ts +88 -0
  133. package/dist/core/strictgate.d.ts +33 -0
  134. package/dist/core/taskReport.d.ts +226 -0
  135. package/dist/core/taskReport.js +514 -0
  136. package/dist/core/taskReportCapture.d.ts +8 -0
  137. package/dist/core/taskReportCapture.js +36 -0
  138. package/dist/core/taskReportEvidence.d.ts +26 -0
  139. package/dist/core/taskReportEvidence.js +268 -0
  140. package/dist/core/taskReportHook.d.ts +20 -0
  141. package/dist/core/taskReportHook.js +76 -0
  142. package/dist/core/taskReportPaths.d.ts +3 -0
  143. package/dist/core/taskReportPaths.js +23 -0
  144. package/dist/core/taskReportPublic.d.ts +31 -0
  145. package/dist/core/taskReportPublic.js +45 -0
  146. package/dist/core/taskReportRender.d.ts +6 -0
  147. package/dist/core/taskReportRender.js +97 -0
  148. package/dist/core/topics.d.ts +73 -0
  149. package/dist/core/types.d.ts +1239 -0
  150. package/dist/core/version.d.ts +10 -0
  151. package/dist/eval/guards.d.ts +45 -0
  152. package/dist/eval/harness.d.ts +58 -0
  153. package/dist/extractors/adrImport.d.ts +59 -0
  154. package/dist/extractors/comments.d.ts +7 -0
  155. package/dist/extractors/correctionSources.d.ts +11 -0
  156. package/dist/extractors/diff.d.ts +40 -0
  157. package/dist/extractors/git.d.ts +304 -0
  158. package/dist/extractors/git.js +208 -20
  159. package/dist/extractors/helm.d.ts +31 -0
  160. package/dist/extractors/indexer.d.ts +55 -0
  161. package/dist/extractors/landscapeDiscovery.d.ts +41 -0
  162. package/dist/extractors/languages.d.ts +77 -0
  163. package/dist/extractors/nativeTreeSitter.d.ts +16 -0
  164. package/dist/extractors/parse.d.ts +54 -0
  165. package/dist/extractors/php.d.ts +26 -0
  166. package/dist/extractors/repoSource.d.ts +53 -0
  167. package/dist/extractors/testreport.d.ts +36 -0
  168. package/dist/integrations/ciAction.d.ts +8 -0
  169. package/dist/integrations/claudeConfig.d.ts +44 -0
  170. package/dist/integrations/claudemd.d.ts +13 -0
  171. package/dist/integrations/claudemd.js +11 -2
  172. package/dist/integrations/gitignore.d.ts +16 -0
  173. package/dist/integrations/gitignore.js +7 -0
  174. package/dist/integrations/health.d.ts +74 -0
  175. package/dist/integrations/hooks.d.ts +41 -0
  176. package/dist/integrations/hooks.js +92 -66
  177. package/dist/integrations/madrExport.d.ts +39 -0
  178. package/dist/integrations/madrManifest.d.ts +69 -0
  179. package/dist/integrations/mergeDriver.d.ts +3 -0
  180. package/dist/integrations/mergeDriver.js +25 -8
  181. package/dist/integrations/probe.d.ts +4 -0
  182. package/dist/integrations/providers.d.ts +103 -0
  183. package/dist/integrations/scaffold.d.ts +29 -0
  184. package/dist/integrations/sync.d.ts +30 -0
  185. package/dist/integrations/sync.js +3 -2
  186. package/dist/integrations/team.d.ts +70 -0
  187. package/dist/integrations/worktree.d.ts +8 -0
  188. package/dist/mcp/roots.d.ts +16 -0
  189. package/dist/mcp/server.d.ts +36 -0
  190. package/dist/mcp/server.js +74 -22
  191. package/dist/mcp/taskReportTools.d.ts +3 -0
  192. package/dist/mcp/taskReportTools.js +106 -0
  193. package/dist/serve/app.d.ts +36 -0
  194. package/dist/serve/config.d.ts +100 -0
  195. package/dist/serve/writelock.d.ts +22 -0
  196. package/dist/store/changeLedger.d.ts +132 -0
  197. package/dist/store/compact.d.ts +33 -0
  198. package/dist/store/db.d.ts +9 -0
  199. package/dist/store/embedder.d.ts +32 -0
  200. package/dist/store/hunchStore.d.ts +624 -0
  201. package/dist/store/hunchStore.js +6 -3
  202. package/dist/store/jsonStore.d.ts +125 -0
  203. package/dist/store/merge.d.ts +39 -0
  204. package/dist/store/privateMigrate.d.ts +24 -0
  205. package/dist/store/replay.d.ts +56 -0
  206. package/dist/store/schema.d.ts +17 -0
  207. package/dist/store/stateBinding.d.ts +145 -0
  208. package/dist/store/stateCapture.d.ts +15 -0
  209. package/dist/synthesis/cliAdapter.d.ts +22 -0
  210. package/dist/synthesis/initiator.d.ts +13 -0
  211. package/dist/synthesis/provider.d.ts +307 -0
  212. package/dist/synthesis/synthesize.d.ts +117 -0
  213. package/dist/synthesis/tripwires.d.ts +9 -0
  214. package/dist/taskReports.d.ts +76 -0
  215. package/dist/taskReports.js +67 -0
  216. package/dist/wiki/adopt.d.ts +22 -0
  217. package/dist/wiki/graph.d.ts +87 -0
  218. package/dist/wiki/wiki.d.ts +242 -0
  219. package/package.json +6 -5
  220. package/server.json +2 -2
@@ -0,0 +1,149 @@
1
+ export declare const FILE_FIRST_DECLARATION_CLUSTER_RULE: "flat-file-anchored-semantic-clusters-v3";
2
+ export declare const FILE_FIRST_FILE_LIMIT = 5;
3
+ export declare const FILE_FIRST_CLUSTER_LIMIT = 2;
4
+ export declare const FILE_FIRST_MEMBER_LIMIT = 3;
5
+ export declare const PROGRESSIVE_DECLARATION_PLAN_RULE: "promoted-only-progressive-inspection-v4";
6
+ export declare const PROGRESSIVE_DECLARATION_BASELINE_LIMIT = 5;
7
+ export declare const PROGRESSIVE_DECLARATION_PRIMARY_LIMIT = 10;
8
+ export declare const PROGRESSIVE_DECLARATION_TOTAL_LIMIT = 11;
9
+ export declare const FILE_FIRST_DECLARATION_CLUSTER_TRANSFER: {
10
+ readonly benchmark: "flat-file-anchored-clusters-transfer-v3";
11
+ readonly scorable_tasks: 12;
12
+ readonly baseline_top_five_hits: 3;
13
+ readonly combined_hits: 6;
14
+ readonly combined_improvement_points: 0.25;
15
+ readonly baseline_file_hits: 8;
16
+ readonly cluster_file_hits: 10;
17
+ readonly rescues: 3;
18
+ readonly average_inspected_declarations: 18.83;
19
+ readonly max_inspected_declarations: 24;
20
+ readonly decision: "promoted-supplemental-diagnostic";
21
+ readonly exact_owner_policy: "disabled";
22
+ };
23
+ export declare const PROGRESSIVE_DECLARATION_DEVELOPMENT: {
24
+ readonly benchmark: "revealed-cluster-transfer-v1-v2-v3-replay";
25
+ readonly scorable_tasks: 36;
26
+ readonly baseline_top_five_hits: 15;
27
+ readonly progressive_plan_hits: 21;
28
+ readonly full_cluster_union_hits: 21;
29
+ readonly previous_average_inspected_declarations: 19.81;
30
+ readonly progressive_max_inspected_declarations: 11;
31
+ readonly inspection_reduction: 0.4446;
32
+ readonly decision: "candidate-awaiting-fresh-transfer";
33
+ readonly exact_owner_policy: "disabled";
34
+ };
35
+ export declare const PROGRESSIVE_DECLARATION_TRANSFER: {
36
+ readonly benchmark: "progressive-inspection-cross-repository-transfer-v4";
37
+ readonly scorable_tasks: 12;
38
+ readonly baseline_top_five_hits: 5;
39
+ readonly progressive_plan_hits: 5;
40
+ readonly full_cluster_union_hits: 5;
41
+ readonly rescues: 0;
42
+ readonly losses: 0;
43
+ readonly average_inspected_declarations: 11;
44
+ readonly previous_average_inspected_declarations: 18.92;
45
+ readonly inspection_reduction: 0.4185;
46
+ readonly decision: "retain-efficiency-advisory-v4";
47
+ readonly accuracy_promotion: "rejected-no-fresh-rescue";
48
+ readonly exact_owner_policy: "disabled";
49
+ };
50
+ export interface ClusterableDeclarationCandidate {
51
+ owner: string;
52
+ score: number;
53
+ runtime_declaration: boolean;
54
+ type_scaffolding: boolean;
55
+ }
56
+ export interface DeclarationClusterMember {
57
+ owner: string;
58
+ global_rank: number;
59
+ static_score: number;
60
+ runtime_declaration: boolean;
61
+ type_scaffolding: boolean;
62
+ }
63
+ export interface SemanticDeclarationCluster {
64
+ cluster_id: string;
65
+ label: string;
66
+ semantic_terms: string[];
67
+ representative: string;
68
+ representative_global_rank: number;
69
+ members: DeclarationClusterMember[];
70
+ members_truncated: number;
71
+ }
72
+ export interface FileFirstDeclarationCluster {
73
+ path: string;
74
+ file_rank: number;
75
+ file_score: number;
76
+ first_candidate_rank: number;
77
+ declaration_clusters: SemanticDeclarationCluster[];
78
+ }
79
+ export interface FileFirstDeclarationClusterReceipt {
80
+ version: 3;
81
+ receipt_id: string;
82
+ rule: typeof FILE_FIRST_DECLARATION_CLUSTER_RULE;
83
+ source_candidates: number;
84
+ file_limit: number;
85
+ cluster_limit_per_file: number;
86
+ member_limit_per_cluster: number;
87
+ selected_files: string[];
88
+ selected_cluster_ids: string[];
89
+ file_selection_strategy: "flat-shortlist-file-anchor";
90
+ flat_shortlist_anchor_size: 5;
91
+ flat_shortlist_preserved: true;
92
+ exact_owner_enabled: false;
93
+ }
94
+ export interface FileFirstDeclarationDiagnostic {
95
+ files: FileFirstDeclarationCluster[];
96
+ receipt: FileFirstDeclarationClusterReceipt;
97
+ transfer_calibration: typeof FILE_FIRST_DECLARATION_CLUSTER_TRANSFER;
98
+ }
99
+ export interface ProgressiveInspectionCandidate {
100
+ owner: string;
101
+ inspection_rank: number;
102
+ phase: "flat-shortlist" | "cluster-expansion" | "cluster-fallback";
103
+ file_path: string;
104
+ global_rank: number;
105
+ cluster_id: string | null;
106
+ cluster_label: string | null;
107
+ runtime_declaration: boolean;
108
+ type_scaffolding: boolean;
109
+ }
110
+ export interface ProgressiveInspectionPhase {
111
+ phase: ProgressiveInspectionCandidate["phase"];
112
+ instruction: string;
113
+ stop_condition: string;
114
+ candidates: ProgressiveInspectionCandidate[];
115
+ }
116
+ export interface ProgressiveDeclarationPlanReceipt {
117
+ version: 1;
118
+ receipt_id: string;
119
+ rule: typeof PROGRESSIVE_DECLARATION_PLAN_RULE;
120
+ baseline_limit: number;
121
+ primary_limit: number;
122
+ total_limit: number;
123
+ selected_owners: string[];
124
+ selected_cluster_ids: string[];
125
+ promoted_mechanisms: readonly ["repository-adaptive-ranking", "flat-file-anchored-semantic-clusters"];
126
+ rejected_rerankers_disabled: true;
127
+ flat_shortlist_preserved: true;
128
+ exact_owner_enabled: false;
129
+ }
130
+ export interface ProgressiveDeclarationPlan {
131
+ phases: ProgressiveInspectionPhase[];
132
+ candidates: ProgressiveInspectionCandidate[];
133
+ receipt: ProgressiveDeclarationPlanReceipt;
134
+ development_calibration: typeof PROGRESSIVE_DECLARATION_DEVELOPMENT;
135
+ transfer_calibration: typeof PROGRESSIVE_DECLARATION_TRANSFER;
136
+ }
137
+ /** Build a hierarchical diagnostic from the existing static ranking. The flat
138
+ * shortlist remains untouched: this view collapses related declaration
139
+ * scaffolding into semantic families so one noisy family cannot consume every
140
+ * inspection slot inside a promising file. It is still a candidate view, not
141
+ * an exact-owner claim. */
142
+ export declare function buildFileFirstDeclarationClusters(rankedCandidatesValue: ClusterableDeclarationCandidate[], requestedFileLimit?: number, requestedClusterLimit?: number, requestedMemberLimit?: number): FileFirstDeclarationDiagnostic;
143
+ /** Turn the promoted flat shortlist and semantic clusters into a progressive
144
+ * inspection queue. The first five candidates remain byte-for-byte intact.
145
+ * Supplemental candidates must already belong to a selected semantic family,
146
+ * and are ordered by the frozen repository-adaptive rank instead of widening
147
+ * to every declaration in the file. The last slot is explicitly a fallback so
148
+ * callers can stop after ten inspections when the behavior is already owned. */
149
+ export declare function buildProgressiveDeclarationPlan(rankedCandidatesValue: ClusterableDeclarationCandidate[], clusters: FileFirstDeclarationDiagnostic, requestedBaselineLimit?: number, requestedTotalLimit?: number): ProgressiveDeclarationPlan;
@@ -0,0 +1,110 @@
1
+ import type { AssembledContext } from "../store/hunchStore.js";
2
+ import type { Component, Decision, Symbol } from "./types.js";
3
+ import type { ExecutionObligation } from "./pipeline.js";
4
+ import { type LandscapeDeliveryFragment } from "./landscapeDelivery.js";
5
+ export declare const DELIVERY_ENVELOPE_SCHEMA_VERSION: "hunch.delivery-envelope/1";
6
+ export declare const DELIVERY_PROFILE_POLICY_VERSION: "hunch.delivery-profile/1";
7
+ export declare const DELIVERY_PROFILES: readonly ["builder", "reviewer", "architect"];
8
+ export type DeliveryProfile = (typeof DELIVERY_PROFILES)[number];
9
+ export type DeliveryKind = "constraints" | "decisions" | "bugs" | "findings" | "resources" | "relationships";
10
+ export type CommitReachability = "reachable" | "unreachable" | "unknown";
11
+ export interface DeliveryRef {
12
+ kind: DeliveryKind;
13
+ record_id: string;
14
+ }
15
+ export type DeliveryReason = "ranked" | "blocking-reserved";
16
+ export type DeliveryProvenanceStatus = "current" | "unverified" | "stale";
17
+ export interface DeliveredItem extends DeliveryRef {
18
+ /** One-based position in the eligible memory ranking. */
19
+ rank: number;
20
+ delivery_reason: DeliveryReason;
21
+ provenance_status: DeliveryProvenanceStatus;
22
+ /** Deterministic approximation: four Unicode code points per token. */
23
+ token_cost: number;
24
+ }
25
+ export interface DeliverySupplement {
26
+ id: string;
27
+ kind: string;
28
+ text: string;
29
+ /** Higher values are attempted first after ranked memory. */
30
+ priority?: number;
31
+ }
32
+ export interface DeliveredSupplement {
33
+ id: string;
34
+ kind: string;
35
+ delivered: boolean;
36
+ reason: "supplemental" | "budget" | "empty" | "abstained";
37
+ rank: number;
38
+ token_cost: number;
39
+ }
40
+ export interface DeliveryOmission extends DeliveryRef {
41
+ reason: "budget" | "stale-provenance" | "retired" | "actionability-cap" | "endpoint-not-delivered" | "landscape-cap" | "profile-cap" | DeliveryAbstentionReason;
42
+ detail: string;
43
+ }
44
+ export type DeliveryAbstentionReason = "low-confidence" | "insufficient-context" | "low-relevance";
45
+ export interface DeliveryAbstention {
46
+ /** True when Hunch found prescriptive memory but deliberately withheld it. */
47
+ active: boolean;
48
+ withheld: number;
49
+ reasons: Record<DeliveryAbstentionReason, number>;
50
+ /** A concrete recovery path instead of a silent empty result. */
51
+ retry_hint: string | null;
52
+ }
53
+ /** A bounded, falsifiable interpretation of one delivered decision. The packet
54
+ * is derived only from stored record/query fields; it never invents a fix. */
55
+ export interface DeliveryHypothesis {
56
+ kind: "decision";
57
+ record_id: string;
58
+ /** Rank of the corresponding delivered record in this envelope. */
59
+ rank: number;
60
+ why: string;
61
+ where: string[];
62
+ historical_pattern: string;
63
+ verify: string;
64
+ disprove: string;
65
+ /** Observable controller checks derived from immutable record evidence. */
66
+ obligations: ExecutionObligation[];
67
+ }
68
+ export interface DeliveryEnvelope {
69
+ schema_version: typeof DELIVERY_ENVELOPE_SCHEMA_VERSION;
70
+ /** Role-specific ordering only; never enforcement or authority. */
71
+ profile: DeliveryProfile;
72
+ ranking_policy: typeof DELIVERY_PROFILE_POLICY_VERSION;
73
+ /** Content-addressed identity for exactly what this envelope returned. */
74
+ receipt_id: string;
75
+ text: string;
76
+ delivered: DeliveredItem[];
77
+ hypotheses: DeliveryHypothesis[];
78
+ obligations: ExecutionObligation[];
79
+ supplements: DeliveredSupplement[];
80
+ omitted: DeliveryOmission[];
81
+ /** Reviewed graph records delivered through this same budget and receipt. */
82
+ landscape: LandscapeDeliveryFragment | null;
83
+ budget_tokens: number;
84
+ used_chars: number;
85
+ /** Conservative text + structured landscape payload accounting. */
86
+ accounted_chars: number;
87
+ /** True only when the requested budget is mathematically too small to name
88
+ * every active blocking invariant. Safety wins, and the overflow is explicit. */
89
+ blocking_overflow: boolean;
90
+ abstention: DeliveryAbstention;
91
+ }
92
+ export interface DeliveryOptions {
93
+ /** Defaults to builder for day-to-day coding work. */
94
+ profile?: DeliveryProfile;
95
+ root?: string;
96
+ symbols?: readonly Pick<Symbol, "id" | "name" | "file">[];
97
+ components?: readonly Pick<Component, "id" | "status" | "paths">[];
98
+ /** Full decision corpus lets the envelope explain only decisions it actually delivered. */
99
+ decisionCorpus?: readonly Decision[];
100
+ /** Caller-specific grounding that must share the same hard output budget. */
101
+ supplements?: readonly DeliverySupplement[];
102
+ /** Time-travel contexts intentionally include records that are retired at HEAD. */
103
+ historical?: boolean;
104
+ /** Injectable for deterministic tests. Omit to use the local Git graph. */
105
+ commitReachability?: (commit: string) => CommitReachability;
106
+ }
107
+ /** Validate the public receipt without trusting a caller-supplied identity. */
108
+ export declare function assertDeliveryEnvelope(envelope: DeliveryEnvelope): void;
109
+ /** Build the one envelope used by CLI, MCP, and the edit hook. */
110
+ export declare function buildDeliveryEnvelope(ctx: AssembledContext, options?: DeliveryOptions): DeliveryEnvelope;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Markdown topic anchors — decision-grounding for PROSE (the doc≠graph spoke,
3
+ * extended to the files the ecosystem already funnels team knowledge into:
4
+ * AGENTS.md, CLAUDE.md, docs/*.md).
5
+ *
6
+ * A tracked markdown file declares which decision topic a section describes:
7
+ *
8
+ * <!-- hunch:topic auth.session --> grounding only
9
+ * <!-- hunch:topic auth.session dec_a1b2c3d4e5 --> PINNED: prose written against that decision
10
+ *
11
+ * Deterministic by construction: drift fires ONLY on an explicit pin whose
12
+ * decision has been superseded — never on a semantic guess (the same philosophy
13
+ * as `anchor-stale` in drift.ts). Unpinned markers still ground the pre-edit
14
+ * hook but can never fire drift.
15
+ */
16
+ import type { Decision } from "./types.js";
17
+ export interface DocAnchor {
18
+ topic: string;
19
+ /** The decision id the prose was written against, or null for an unpinned marker. */
20
+ pin: string | null;
21
+ /** 1-based line of the marker in the document. */
22
+ line: number;
23
+ }
24
+ /** Parse every hunch:topic marker out of a markdown document. Markers inside
25
+ * fenced code blocks or inline code spans are examples, not declarations,
26
+ * and are skipped. */
27
+ export declare function parseDocAnchors(text: string): DocAnchor[];
28
+ /** Pre-edit grounding for a markdown document that carries topic anchors: the
29
+ * CURRENT decision per declared topic (graph over prose), what it rejected,
30
+ * and a stale-pin warning the editor can heal inline. Empty when no anchor
31
+ * resolves to a decision. */
32
+ export declare function renderDocGrounding(anchors: readonly DocAnchor[], decisions: readonly Decision[]): string;
@@ -0,0 +1,26 @@
1
+ import type { Decision } from "./types.js";
2
+ export declare const STALE_MARKER: RegExp;
3
+ export declare const SRC_REF: RegExp;
4
+ /** Bounded walk for repo markdown (root + docs/, depth-limited; heavy/irrelevant trees skipped). */
5
+ export declare function markdownDocs(root: string): Array<{
6
+ path: string;
7
+ rel: string;
8
+ }>;
9
+ export type DocStatus = "grounded" | "stale" | "unverified";
10
+ export interface RepoDoc {
11
+ /** repo-relative POSIX path. */
12
+ rel: string;
13
+ /** First `# ` heading, or the path when the doc has none. */
14
+ title: string;
15
+ /** Topics the doc declares via hunch:topic markers. */
16
+ topics: string[];
17
+ /** src/*.ts files the doc mentions (the component-association signal). */
18
+ srcRefs: string[];
19
+ status: DocStatus;
20
+ /** Human-readable reasons behind a "stale" grade (empty otherwise). */
21
+ issues: string[];
22
+ }
23
+ /** Grade every repo doc. GENERATED wiki pages (hunch:wiki header) are views of
24
+ * the graph, not specs — they are excluded here and freshness-gated by their
25
+ * own manifest hash instead. */
26
+ export declare function scanRepoDocs(decisions: readonly Decision[], root: string): RepoDoc[];
@@ -0,0 +1,13 @@
1
+ import type { HunchStore } from "../store/hunchStore.js";
2
+ export type DriftKind = "dead-ref" | "supersede" | "doc-stale" | "anchor-stale" | "doc-anchor-stale" | "doc-anchor-dangling" | "wiki-stale" | "finding-stale" | "premise-stale" | "commit-unresolvable" | "madr-stale" | "madr-edited" | "madr-orphan";
3
+ export interface DriftFinding {
4
+ kind: DriftKind;
5
+ id: string;
6
+ detail: string;
7
+ }
8
+ export interface DriftReport {
9
+ findings: DriftFinding[];
10
+ }
11
+ export declare function computeDrift(store: HunchStore, root: string, deps?: {
12
+ commitResolvable?: (sha: string) => boolean;
13
+ }): DriftReport;
@@ -26,7 +26,8 @@ import { parseDocAnchors } from "./docanchors.js";
26
26
  import { markdownDocs, STALE_MARKER, SRC_REF } from "./docscan.js";
27
27
  import { computeWikiDrift } from "../wiki/wiki.js";
28
28
  import { computeMadrDrift } from "../integrations/madrManifest.js";
29
- export function computeDrift(store, root) {
29
+ import { commitsExist, isGitRepo } from "../extractors/git.js";
30
+ export function computeDrift(store, root, deps = {}) {
30
31
  const findings = [];
31
32
  const decisions = store.recs("decisions");
32
33
  const byId = new Map(decisions.map((d) => [d.id, d]));
@@ -46,6 +47,25 @@ export function computeDrift(store, root) {
46
47
  return liveFiles.has(p) || liveDirs.some((dir) => p.startsWith(dir));
47
48
  };
48
49
  const premiseEnv = { now: new Date().toISOString(), exists: (p) => existsSync(join(root, p)) };
50
+ // A plain existence check is meaningless outside a git repo — computed once,
51
+ // not per decision, and never a false positive for a directory that merely
52
+ // happens to hold .hunch/ without being a git checkout. Injectable so tests
53
+ // (and callers with a cheaper oracle) never have to shell out per decision.
54
+ const gitRepo = isGitRepo(root);
55
+ // One batched `git cat-file --batch-check` for every commit-bearing decision,
56
+ // not one `rev-parse` per decision — skipped entirely when a predicate is
57
+ // injected (tests/callers with a cheaper oracle never pay for this at all).
58
+ const resolvableCommits = gitRepo && !deps.commitResolvable
59
+ ? commitsExist([...new Set(decisions.filter((d) => d.commit).map((d) => d.commit))], root)
60
+ : null;
61
+ const defaultCommitResolvable = (sha) => {
62
+ if (!gitRepo)
63
+ return true; // never flag outside a git repo
64
+ if (resolvableCommits === null)
65
+ return true; // the batch check itself failed, or was skipped — fail open
66
+ return resolvableCommits.has(sha);
67
+ };
68
+ const commitResolvable = deps.commitResolvable ?? defaultCommitResolvable;
49
69
  for (const d of decisions) {
50
70
  // 1. DEAD-REFERENCE — only for in-force decisions; a superseded one referencing
51
71
  // a since-deleted file is legitimate history, not drift.
@@ -58,6 +78,16 @@ export function computeDrift(store, root) {
58
78
  findings.push({ kind: "dead-ref", id: d.id, detail: `references missing file "${f}"` });
59
79
  }
60
80
  }
81
+ // 8. COMMIT-UNRESOLVABLE — an in-force decision's commit provenance no longer
82
+ // resolves at all (source branch gone + gc'd past recovery). The
83
+ // opportunistic post-merge repair (commitrepair.ts) is the fix path; this
84
+ // is purely the "nothing caught it" signal — deterministic, never auto-fixed.
85
+ // Mirrors repair.ts:59's live-records-only rule: `inForce` alone doesn't
86
+ // exclude a never-adopted "rejected" decision (superseded_by is null for
87
+ // those too), so exclude it explicitly here.
88
+ if (d.commit && d.status !== "rejected" && !commitResolvable(d.commit)) {
89
+ findings.push({ kind: "commit-unresolvable", id: d.id, detail: `commit ${d.commit} no longer resolves in this repository — provenance may need manual repair` });
90
+ }
61
91
  }
62
92
  // 2. SUPERSEDE-INTEGRITY — a contradiction class: A.supersedes = B, but B is
63
93
  // either gone or still in force (the private-supersede bug shape).
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Deterministic near-duplicate detection for auto-drafted decisions — hygiene,
3
+ * not judgment (the human vouch stays untouchable; dec_a466655539 doctrine).
4
+ *
5
+ * The duplicate factory: a human records a decision via MCP (commit: null),
6
+ * then commits the code — the post-commit hook synthesizes a SECOND record of
7
+ * the same choice under a commit-keyed id. Review triage showed 7 of 14 queued
8
+ * drafts were exactly this.
9
+ *
10
+ * Two layers, both model-free:
11
+ * - commitCoveredBy(): PRE-draft gate in syncCommit — a recent human-confirmed
12
+ * decision already claims this commit's files (+ subject terms) → skip the
13
+ * draft entirely (also saves the subscription call). Recency-windowed so an
14
+ * OLD decision on the same files can never suppress genuinely new work.
15
+ * - draftDuplicateOf(): review-time flag for drafts already in the store —
16
+ * full-text term overlap + file overlap against accepted records, so
17
+ * `hunch review` marks likely duplicates and can batch-reject them.
18
+ */
19
+ import type { Decision } from "./types.js";
20
+ /** Lowercased salient terms (≥4 chars, non-stopword) — deliberately simple and
21
+ * deterministic; shared by both layers so their notion of "similar" agrees. */
22
+ export declare function dupTerms(text: string): Set<string>;
23
+ export interface Coverage {
24
+ id: string;
25
+ title: string;
26
+ hoursAgo: number;
27
+ fileOverlapPct: number;
28
+ }
29
+ /** Does a RECENT human-confirmed live decision already claim this commit's
30
+ * files (and roughly its subject)? Deterministic pre-draft gate. */
31
+ export declare function commitCoveredBy(codeFiles: readonly string[], subject: string, existing: readonly Decision[], nowMs: number): Coverage | null;
32
+ export interface DupMatch {
33
+ of: Decision;
34
+ /** 0..1 combined similarity (term Jaccard, file-overlap boosted). */
35
+ score: number;
36
+ }
37
+ /** Only a finalized, still-live human decision can justify deleting a draft as
38
+ * redundant. Proposed records may resemble one another, but choosing which one
39
+ * survives is review judgment—not deterministic hygiene. */
40
+ export declare function isAcceptedDuplicateAnchor(d: Decision): boolean;
41
+ /** Is an existing DRAFT a near-duplicate of an accepted record? Review-time
42
+ * flag; threshold callers use 0.35 (batch-reject) — conservative on purpose. */
43
+ export declare function draftDuplicateOf(draft: Decision, existing: readonly Decision[]): DupMatch | null;
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Inline escalations — the "ask the human IN THE PROMPT, not in a background queue"
3
+ * half of the auto-trust model.
4
+ *
5
+ * Captured memory auto-trusts the moment it lands (status accepted, advisory), so
6
+ * there is no draft queue to drain. The only things that still need a human are the
7
+ * rare cases the graph genuinely CANNOT resolve on its own — and those are surfaced
8
+ * as a short, question-framed list the assistant raises in conversation at the
9
+ * moment, then normally EMPTY.
10
+ *
11
+ * Deterministic only. Memory questions include a topic conflict (>1 live decision for
12
+ * one topic — a git merge can create these; see topics.topicCollisions) and one
13
+ * exact imported ADR awaiting a hash-bound approve/decline answer. We do NOT
14
+ * guess semantically which un-anchored decisions "contradict" each other — that
15
+ * stays the assistant's judgment, asked in chat, never a machine verdict (same
16
+ * explicit-anchors-only ethos as the drift detector).
17
+ *
18
+ * Pure over a Decision[] — no store, no IO — so the CLI, the MCP read tool, and the
19
+ * session-start orientation all share one source of truth.
20
+ */
21
+ import type { Decision } from "./types.js";
22
+ import { type CommitRewrite } from "./commitrepair.js";
23
+ export type EscalationKind = "topic-conflict" | "imported-adr-review" | "policy-candidate" | "policy-proposal" | "policy-repaired" | "premise-stale" | "commit-repair-pending";
24
+ export interface Escalation {
25
+ kind: EscalationKind;
26
+ /** the topic (or other key) the conflict is about. */
27
+ topic: string;
28
+ /** the decisions the human must choose between. */
29
+ decisionIds: string[];
30
+ /** a one-line, human-facing question the assistant should raise in the prompt. */
31
+ question: string;
32
+ /** the supporting detail (ids + titles) for the question. */
33
+ detail: string;
34
+ /** the concrete resolution the human's answer maps to. */
35
+ resolution: string;
36
+ /** false ONLY for an entry whose own resolution requires acting on a
37
+ * DIFFERENT entry first (a duplicate-id queue's non-drop, non-apply
38
+ * follower) — it still surfaces, for transparency, but gating surfaces
39
+ * (CI exit code, "needs your call" tallies) must not count it: resolving
40
+ * the actionable entry ahead of it is what clears it, not anything a
41
+ * human can do to this row directly (#61). Omitted (undefined) means
42
+ * true — every other escalation kind is always directly actionable. */
43
+ actionable?: boolean;
44
+ }
45
+ /** Escalations gating surfaces (CI exit codes, "needs your call" counts/lists)
46
+ * should act on: everything except an entry explicitly marked
47
+ * actionable:false (#61). The full list — including non-actionable
48
+ * entries — still belongs in any transparency-facing output (e.g. --json). */
49
+ export declare function actionableEscalations(items: readonly Escalation[]): Escalation[];
50
+ export interface EscalationSummary {
51
+ /** the subset a gating surface should count/exit/ask on. */
52
+ actionable: Escalation[];
53
+ /** how many entries were filtered out — informational-only, shown for
54
+ * transparency but not itself a decision to raise. */
55
+ context: number;
56
+ }
57
+ /** One computation for every "N need your call (+M shown for context)"
58
+ * consumer (CLI `escalations`, SessionStart, the `hunch_now`/`hunch_escalations`
59
+ * MCP tools) — introduced alongside `actionable` (#61) specifically so a
60
+ * future consumer of Escalation[] can't repeat the mistake of hand-rolling
61
+ * the filter and forgetting it (the VS Code panel did, before this existed). */
62
+ export declare function summarizeEscalations(items: readonly Escalation[]): EscalationSummary;
63
+ /** "you" (the CLI, talking directly to the operator) vs "mcp" (an assistant
64
+ * relaying a question to the human, third person). */
65
+ export type EscalationAudience = "cli" | "mcp";
66
+ /** The ONE "N need your call (+M shown for context)" headline, shared by the
67
+ * CLI `escalations` command and the `hunch_escalations` MCP tool (#61) —
68
+ * including its own "nothing actionable, but N item(s) queued for context"
69
+ * fallback, so that unreachable-today prose exists in exactly one place
70
+ * instead of being hand-copied per consumer (the copy-paste is how the VS
71
+ * Code panel missed the filter entirely before `actionable` existed).
72
+ * Callers are expected to have already special-cased `items.length === 0`
73
+ * (a plainer "nothing needs your decision" message, no tally at all). */
74
+ export declare function escalationHeadline(items: readonly Escalation[], audience: EscalationAudience): string;
75
+ /** The decisions a human must make NOW, to be asked INLINE. Empty in a healthy graph. */
76
+ export declare function pendingEscalations(decisions: readonly Decision[]): Escalation[];
77
+ /** A commit-provenance repair the post-merge hook detected and queued
78
+ * (src/core/repairqueue.ts) but never applied — the match signal (related_files
79
+ * overlap) isn't strong enough to write unattended, so it's a question for the
80
+ * human, exactly like every other entry here, never a silent write.
81
+ *
82
+ * `decisions` is the caller's VISIBLE scope (supplies the title only) —
83
+ * MCP/SessionStart pass store.advisoryRecs(), which is public-only in
84
+ * private mode. `live` is the scope liveRewrites checks the repair against;
85
+ * it defaults to `decisions` but callers on an advisory scope must pass the
86
+ * FULL store (store.recs()) here, since repair-provenance itself reads the
87
+ * full store — an overlay decision's repair is fully answerable even where
88
+ * its title isn't visible, and must not go silent just because the title is
89
+ * private.
90
+ *
91
+ * `withheld` (from repairqueue.ts's withheldRewrites — a git-facing check
92
+ * this module deliberately stays free of, so the caller runs it and passes
93
+ * the result in) names entries whose proposed `to` doesn't resolve to a
94
+ * real commit here. `--apply --only <id>` can never resolve one of these —
95
+ * advertising it as the answer would be advice guaranteed to no-op
96
+ * forever, which is worse than not asking at all. Such an entry still
97
+ * needs a human (only `--drop` can retire it), so it still escalates, just
98
+ * with wording that doesn't promise `--apply` will help.
99
+ *
100
+ * Keyed by OBJECT, not by id, matching withheldForUnresolvableTo's own
101
+ * contract: a corrupted queue file can carry two entries sharing an id
102
+ * (one resolvable, one not) — an id-keyed set couldn't tell them apart and
103
+ * would wrongly tag the resolvable sibling as unresolvable too. Every
104
+ * caller of this function already passes the SAME `queued` array to both
105
+ * this function and withheldRewrites, so identity holds. */
106
+ export declare function commitRepairEscalations(queued: readonly CommitRewrite[], decisions: readonly Decision[], live?: readonly Decision[], withheld?: ReadonlySet<CommitRewrite>): Escalation[];
107
+ /** The minimal policy shape the escalation scan needs — a structural subset of
108
+ * constitution PolicySpec, so this module stays dependency-free of the
109
+ * Constitution schemas (core must not import constitution). */
110
+ export interface PolicyLite {
111
+ id: string;
112
+ state: string;
113
+ statement: string;
114
+ proof: string | null;
115
+ authority: unknown;
116
+ activation_gate?: {
117
+ kind: string;
118
+ status: string;
119
+ reason: string;
120
+ } | null;
121
+ /** the policy's most recent audit action, when the caller has it — lets the
122
+ * scan surface auto-repaired policies that need a fresh proof. */
123
+ last_action?: string | null;
124
+ }
125
+ /** The Constitution's genuine human moments (§59.5.3), framed as inline questions:
126
+ * a candidate awaiting review, and a proposed policy whose next step (prove, or
127
+ * accept/reject) is a human call. Machine conclusions never appear here as
128
+ * approvals — every entry is a QUESTION with its explicit resolution verb. */
129
+ export declare function policyEscalations(policies: readonly PolicyLite[]): Escalation[];