@davesheffer/hunch 1.22.1 → 1.22.3
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.
package/README.md
CHANGED
|
@@ -179,7 +179,7 @@ does not host that repository. Give teammates and CI normal Git access, keep cre
|
|
|
179
179
|
the Git credential helper, and have one maintainer connect it:
|
|
180
180
|
|
|
181
181
|
```bash
|
|
182
|
-
npm i -g @davesheffer/hunch@1.22.
|
|
182
|
+
npm i -g @davesheffer/hunch@1.22.3
|
|
183
183
|
hunch shared --repo git@github.com:acme/project-hunch-memory.git
|
|
184
184
|
git add .gitignore .hunch/team.json
|
|
185
185
|
git commit -m "chore: connect shared Hunch memory"
|
|
@@ -189,7 +189,7 @@ git push
|
|
|
189
189
|
Teammates then install the same version and run:
|
|
190
190
|
|
|
191
191
|
```bash
|
|
192
|
-
npm i -g @davesheffer/hunch@1.22.
|
|
192
|
+
npm i -g @davesheffer/hunch@1.22.3
|
|
193
193
|
git pull
|
|
194
194
|
hunch init
|
|
195
195
|
hunch doctor
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { type Finding } from "./types.js";
|
|
3
|
+
export declare const PROJECT_DNA_USEFULNESS_OBSERVATION_SCHEMA_VERSION: "hunch.project-dna-usefulness-observation/1";
|
|
4
|
+
export declare const PROJECT_DNA_USEFULNESS_SIGNALS: readonly ["used", "prevented", "near_miss", "contradicted", "stale", "unused", "unknown"];
|
|
5
|
+
export declare const PROJECT_DNA_USEFULNESS_EVIDENCE_KINDS: readonly ["explicit_human_observation", "independent_review"];
|
|
6
|
+
export declare const ProjectDnaUsefulnessObservationSchema: z.ZodObject<{
|
|
7
|
+
schema: z.ZodLiteral<"hunch.project-dna-usefulness-observation/1">;
|
|
8
|
+
observationId: z.ZodString;
|
|
9
|
+
episode: z.ZodObject<{
|
|
10
|
+
provider: z.ZodString;
|
|
11
|
+
schemaVersion: z.ZodString;
|
|
12
|
+
episodeId: z.ZodString;
|
|
13
|
+
episodeHash: z.ZodString;
|
|
14
|
+
terminalAt: z.ZodString;
|
|
15
|
+
result: z.ZodEnum<{
|
|
16
|
+
pass: "pass";
|
|
17
|
+
fail: "fail";
|
|
18
|
+
uncertain: "uncertain";
|
|
19
|
+
abandoned: "abandoned";
|
|
20
|
+
rolled_back: "rolled_back";
|
|
21
|
+
}>;
|
|
22
|
+
}, z.core.$strict>;
|
|
23
|
+
delivery: z.ZodObject<{
|
|
24
|
+
receiptRef: z.ZodString;
|
|
25
|
+
receiptHash: z.ZodString;
|
|
26
|
+
repositoryId: z.ZodString;
|
|
27
|
+
repositoryRevision: z.ZodString;
|
|
28
|
+
profileId: z.ZodString;
|
|
29
|
+
profileContentHash: z.ZodString;
|
|
30
|
+
snapshotHash: z.ZodString;
|
|
31
|
+
retrievalHash: z.ZodString;
|
|
32
|
+
}, z.core.$strict>;
|
|
33
|
+
projection: z.ZodObject<{
|
|
34
|
+
role: z.ZodString;
|
|
35
|
+
categories: z.ZodArray<z.ZodEnum<{
|
|
36
|
+
communication: "communication";
|
|
37
|
+
engineering: "engineering";
|
|
38
|
+
review: "review";
|
|
39
|
+
culture: "culture";
|
|
40
|
+
vocabulary: "vocabulary";
|
|
41
|
+
}>>;
|
|
42
|
+
traitIds: z.ZodArray<z.ZodString>;
|
|
43
|
+
evidenceHashes: z.ZodArray<z.ZodString>;
|
|
44
|
+
}, z.core.$strict>;
|
|
45
|
+
artifact: z.ZodObject<{
|
|
46
|
+
kind: z.ZodEnum<{
|
|
47
|
+
pull_request: "pull_request";
|
|
48
|
+
commit: "commit";
|
|
49
|
+
issue: "issue";
|
|
50
|
+
message: "message";
|
|
51
|
+
}>;
|
|
52
|
+
ref: z.ZodString;
|
|
53
|
+
contentHash: z.ZodString;
|
|
54
|
+
}, z.core.$strict>;
|
|
55
|
+
assessment: z.ZodObject<{
|
|
56
|
+
schemaVersion: z.ZodString;
|
|
57
|
+
assessmentId: z.ZodString;
|
|
58
|
+
contentHash: z.ZodString;
|
|
59
|
+
projectMatchClassification: z.ZodEnum<{
|
|
60
|
+
unassessable: "unassessable";
|
|
61
|
+
conformant: "conformant";
|
|
62
|
+
mixed: "mixed";
|
|
63
|
+
nonconformant: "nonconformant";
|
|
64
|
+
}>;
|
|
65
|
+
causalInterpretation: z.ZodLiteral<"project_match_is_non_causal">;
|
|
66
|
+
}, z.core.$strict>;
|
|
67
|
+
signal: z.ZodEnum<{
|
|
68
|
+
unknown: "unknown";
|
|
69
|
+
stale: "stale";
|
|
70
|
+
used: "used";
|
|
71
|
+
prevented: "prevented";
|
|
72
|
+
near_miss: "near_miss";
|
|
73
|
+
contradicted: "contradicted";
|
|
74
|
+
unused: "unused";
|
|
75
|
+
}>;
|
|
76
|
+
evidence: z.ZodArray<z.ZodObject<{
|
|
77
|
+
kind: z.ZodEnum<{
|
|
78
|
+
explicit_human_observation: "explicit_human_observation";
|
|
79
|
+
independent_review: "independent_review";
|
|
80
|
+
}>;
|
|
81
|
+
ref: z.ZodString;
|
|
82
|
+
hash: z.ZodString;
|
|
83
|
+
}, z.core.$strict>>;
|
|
84
|
+
observedAt: z.ZodString;
|
|
85
|
+
retainUntil: z.ZodString;
|
|
86
|
+
privacy: z.ZodObject<{
|
|
87
|
+
payloadMode: z.ZodLiteral<"references_hashes_only">;
|
|
88
|
+
rawArtifactIncluded: z.ZodLiteral<false>;
|
|
89
|
+
rawFeedbackIncluded: z.ZodLiteral<false>;
|
|
90
|
+
rawProfileIncluded: z.ZodLiteral<false>;
|
|
91
|
+
}, z.core.$strict>;
|
|
92
|
+
authority: z.ZodObject<{
|
|
93
|
+
behavioralEffect: z.ZodLiteral<"none">;
|
|
94
|
+
mayChangeRanking: z.ZodLiteral<false>;
|
|
95
|
+
mayPromoteKnowledge: z.ZodLiteral<false>;
|
|
96
|
+
mayGrantAuthority: z.ZodLiteral<false>;
|
|
97
|
+
}, z.core.$strict>;
|
|
98
|
+
contentHash: z.ZodString;
|
|
99
|
+
}, z.core.$strict>;
|
|
100
|
+
export type ProjectDnaUsefulnessObservation = z.infer<typeof ProjectDnaUsefulnessObservationSchema>;
|
|
101
|
+
export type CreateProjectDnaUsefulnessObservationInput = Omit<ProjectDnaUsefulnessObservation, "schema" | "observationId" | "authority" | "contentHash">;
|
|
102
|
+
export declare function createProjectDnaUsefulnessObservation(input: CreateProjectDnaUsefulnessObservationInput): ProjectDnaUsefulnessObservation;
|
|
103
|
+
export declare function assertProjectDnaUsefulnessObservation(value: unknown): asserts value is ProjectDnaUsefulnessObservation;
|
|
104
|
+
/** Contradiction and staleness create review work, never a profile mutation or policy. */
|
|
105
|
+
export declare function projectDnaUsefulnessObservationFinding(value: unknown): Finding | null;
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { findingId } from "./ids.js";
|
|
4
|
+
import { PROJECT_DNA_CATEGORIES, } from "./projectDna.js";
|
|
5
|
+
import { FindingSchema, isCredentialFreeText } from "./types.js";
|
|
6
|
+
export const PROJECT_DNA_USEFULNESS_OBSERVATION_SCHEMA_VERSION = "hunch.project-dna-usefulness-observation/1";
|
|
7
|
+
export const PROJECT_DNA_USEFULNESS_SIGNALS = [
|
|
8
|
+
"used",
|
|
9
|
+
"prevented",
|
|
10
|
+
"near_miss",
|
|
11
|
+
"contradicted",
|
|
12
|
+
"stale",
|
|
13
|
+
"unused",
|
|
14
|
+
"unknown",
|
|
15
|
+
];
|
|
16
|
+
export const PROJECT_DNA_USEFULNESS_EVIDENCE_KINDS = [
|
|
17
|
+
"explicit_human_observation",
|
|
18
|
+
"independent_review",
|
|
19
|
+
];
|
|
20
|
+
const SHA256 = /^sha256:[a-f0-9]{64}$/;
|
|
21
|
+
const GIT_OBJECT = /^[a-f0-9]{40,64}$/;
|
|
22
|
+
const RECEIPT_REF = /^hunch-memory:hmctx_[a-f0-9]{32}$/;
|
|
23
|
+
const REPOSITORY_ID = /^pdnar_[a-f0-9]{24}$/;
|
|
24
|
+
const PROFILE_ID = /^pdna_[a-f0-9]{24}$/;
|
|
25
|
+
const TRAIT_ID = /^pdnat_[a-f0-9]{20}$/;
|
|
26
|
+
const OBSERVATION_ID = /^pduo_[a-f0-9]{24}$/;
|
|
27
|
+
const MAX_RETENTION_MS = 365 * 24 * 60 * 60 * 1_000;
|
|
28
|
+
const ProjectDnaUsefulnessEvidenceSchema = z.object({
|
|
29
|
+
kind: z.enum(PROJECT_DNA_USEFULNESS_EVIDENCE_KINDS),
|
|
30
|
+
ref: z.string().min(1).max(512),
|
|
31
|
+
hash: z.string().regex(SHA256),
|
|
32
|
+
}).strict();
|
|
33
|
+
export const ProjectDnaUsefulnessObservationSchema = z.object({
|
|
34
|
+
schema: z.literal(PROJECT_DNA_USEFULNESS_OBSERVATION_SCHEMA_VERSION),
|
|
35
|
+
observationId: z.string().regex(OBSERVATION_ID),
|
|
36
|
+
episode: z.object({
|
|
37
|
+
provider: z.string().regex(/^[a-z][a-z0-9_-]{0,63}$/),
|
|
38
|
+
schemaVersion: z.string().min(3).max(128),
|
|
39
|
+
episodeId: z.string().min(3).max(256),
|
|
40
|
+
episodeHash: z.string().regex(SHA256),
|
|
41
|
+
terminalAt: z.string().min(1).max(64),
|
|
42
|
+
result: z.enum(["pass", "fail", "uncertain", "abandoned", "rolled_back"]),
|
|
43
|
+
}).strict(),
|
|
44
|
+
delivery: z.object({
|
|
45
|
+
receiptRef: z.string().regex(RECEIPT_REF),
|
|
46
|
+
receiptHash: z.string().regex(SHA256),
|
|
47
|
+
repositoryId: z.string().regex(REPOSITORY_ID),
|
|
48
|
+
repositoryRevision: z.string().regex(GIT_OBJECT),
|
|
49
|
+
profileId: z.string().regex(PROFILE_ID),
|
|
50
|
+
profileContentHash: z.string().regex(SHA256),
|
|
51
|
+
snapshotHash: z.string().regex(SHA256),
|
|
52
|
+
retrievalHash: z.string().regex(SHA256),
|
|
53
|
+
}).strict(),
|
|
54
|
+
projection: z.object({
|
|
55
|
+
role: z.string().regex(/^[a-z][a-z0-9_-]{0,63}$/),
|
|
56
|
+
categories: z.array(z.enum(PROJECT_DNA_CATEGORIES)).min(1).max(PROJECT_DNA_CATEGORIES.length),
|
|
57
|
+
traitIds: z.array(z.string().regex(TRAIT_ID)).min(1).max(64),
|
|
58
|
+
evidenceHashes: z.array(z.string().regex(SHA256)).min(1).max(512),
|
|
59
|
+
}).strict(),
|
|
60
|
+
artifact: z.object({
|
|
61
|
+
kind: z.enum(["commit", "pull_request", "issue", "message"]),
|
|
62
|
+
ref: z.string().min(3).max(512),
|
|
63
|
+
contentHash: z.string().regex(SHA256),
|
|
64
|
+
}).strict(),
|
|
65
|
+
assessment: z.object({
|
|
66
|
+
schemaVersion: z.string().min(3).max(128),
|
|
67
|
+
assessmentId: z.string().min(3).max(128),
|
|
68
|
+
contentHash: z.string().regex(SHA256),
|
|
69
|
+
projectMatchClassification: z.enum(["unassessable", "conformant", "mixed", "nonconformant"]),
|
|
70
|
+
causalInterpretation: z.literal("project_match_is_non_causal"),
|
|
71
|
+
}).strict(),
|
|
72
|
+
signal: z.enum(PROJECT_DNA_USEFULNESS_SIGNALS),
|
|
73
|
+
evidence: z.array(ProjectDnaUsefulnessEvidenceSchema).max(64),
|
|
74
|
+
observedAt: z.string().min(1).max(64),
|
|
75
|
+
retainUntil: z.string().min(1).max(64),
|
|
76
|
+
privacy: z.object({
|
|
77
|
+
payloadMode: z.literal("references_hashes_only"),
|
|
78
|
+
rawArtifactIncluded: z.literal(false),
|
|
79
|
+
rawFeedbackIncluded: z.literal(false),
|
|
80
|
+
rawProfileIncluded: z.literal(false),
|
|
81
|
+
}).strict(),
|
|
82
|
+
authority: z.object({
|
|
83
|
+
behavioralEffect: z.literal("none"),
|
|
84
|
+
mayChangeRanking: z.literal(false),
|
|
85
|
+
mayPromoteKnowledge: z.literal(false),
|
|
86
|
+
mayGrantAuthority: z.literal(false),
|
|
87
|
+
}).strict(),
|
|
88
|
+
contentHash: z.string().regex(SHA256),
|
|
89
|
+
}).strict().superRefine((observation, ctx) => {
|
|
90
|
+
for (const [path, value] of [
|
|
91
|
+
[["episode", "terminalAt"], observation.episode.terminalAt],
|
|
92
|
+
[["observedAt"], observation.observedAt],
|
|
93
|
+
[["retainUntil"], observation.retainUntil],
|
|
94
|
+
]) {
|
|
95
|
+
if (!Number.isFinite(Date.parse(value)) || new Date(value).toISOString() !== value) {
|
|
96
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, path: [...path], message: "Project DNA usefulness timestamp is invalid" });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const observedAt = Date.parse(observation.observedAt);
|
|
100
|
+
const terminalAt = Date.parse(observation.episode.terminalAt);
|
|
101
|
+
const retainUntil = Date.parse(observation.retainUntil);
|
|
102
|
+
if (Number.isFinite(observedAt) && Number.isFinite(terminalAt) && observedAt < terminalAt) {
|
|
103
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["observedAt"], message: "Project DNA usefulness cannot precede the terminal outcome" });
|
|
104
|
+
}
|
|
105
|
+
if (Number.isFinite(observedAt) && Number.isFinite(retainUntil)
|
|
106
|
+
&& (retainUntil <= observedAt || retainUntil - observedAt > MAX_RETENTION_MS)) {
|
|
107
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["retainUntil"], message: "Project DNA usefulness retention is invalid" });
|
|
108
|
+
}
|
|
109
|
+
if (observation.signal !== "unknown" && observation.evidence.length === 0) {
|
|
110
|
+
ctx.addIssue({
|
|
111
|
+
code: z.ZodIssueCode.custom,
|
|
112
|
+
path: ["evidence"],
|
|
113
|
+
message: "classified Project DNA usefulness requires explicit human or independent review evidence",
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
const identities = new Set();
|
|
117
|
+
for (const [index, evidence] of observation.evidence.entries()) {
|
|
118
|
+
const identity = `${evidence.kind}:${evidence.ref}:${evidence.hash}`;
|
|
119
|
+
if (identities.has(identity)) {
|
|
120
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["evidence", index], message: "Project DNA usefulness evidence is duplicated" });
|
|
121
|
+
}
|
|
122
|
+
identities.add(identity);
|
|
123
|
+
if (!isCredentialFreeText(evidence.ref)) {
|
|
124
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["evidence", index, "ref"], message: "Project DNA usefulness evidence contains credential material" });
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const categories = observation.projection.categories;
|
|
128
|
+
if (new Set(categories).size !== categories.length
|
|
129
|
+
|| new Set(observation.projection.traitIds).size !== observation.projection.traitIds.length
|
|
130
|
+
|| new Set(observation.projection.evidenceHashes).size !== observation.projection.evidenceHashes.length) {
|
|
131
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["projection"], message: "Project DNA usefulness projection contains duplicates" });
|
|
132
|
+
}
|
|
133
|
+
for (const [path, value] of [
|
|
134
|
+
[["episode", "schemaVersion"], observation.episode.schemaVersion],
|
|
135
|
+
[["episode", "episodeId"], observation.episode.episodeId],
|
|
136
|
+
[["projection", "role"], observation.projection.role],
|
|
137
|
+
[["artifact", "ref"], observation.artifact.ref],
|
|
138
|
+
[["assessment", "schemaVersion"], observation.assessment.schemaVersion],
|
|
139
|
+
[["assessment", "assessmentId"], observation.assessment.assessmentId],
|
|
140
|
+
]) {
|
|
141
|
+
if (!isCredentialFreeText(value)) {
|
|
142
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, path: [...path], message: "Project DNA usefulness identity contains credential material" });
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
const unsigned = projectDnaUsefulnessUnsigned(observation);
|
|
146
|
+
if (observation.contentHash !== projectDnaUsefulnessHash(unsigned)
|
|
147
|
+
|| observation.observationId !== projectDnaUsefulnessObservationId(observation)) {
|
|
148
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "Project DNA usefulness observation seal is invalid" });
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
function canonicalJson(value) {
|
|
152
|
+
if (Array.isArray(value))
|
|
153
|
+
return `[${value.map(canonicalJson).join(",")}]`;
|
|
154
|
+
if (value && typeof value === "object") {
|
|
155
|
+
return `{${Object.entries(value)
|
|
156
|
+
.sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0)
|
|
157
|
+
.map(([key, child]) => `${JSON.stringify(key)}:${canonicalJson(child)}`)
|
|
158
|
+
.join(",")}}`;
|
|
159
|
+
}
|
|
160
|
+
return JSON.stringify(value) ?? "null";
|
|
161
|
+
}
|
|
162
|
+
function projectDnaUsefulnessHash(value) {
|
|
163
|
+
return `sha256:${createHash("sha256").update(canonicalJson(value), "utf8").digest("hex")}`;
|
|
164
|
+
}
|
|
165
|
+
function projectDnaUsefulnessObservationId(observation) {
|
|
166
|
+
const identityHash = projectDnaUsefulnessHash({
|
|
167
|
+
episodeId: observation.episode.episodeId,
|
|
168
|
+
receiptRef: observation.delivery.receiptRef,
|
|
169
|
+
receiptHash: observation.delivery.receiptHash,
|
|
170
|
+
profileId: observation.delivery.profileId,
|
|
171
|
+
artifactRef: observation.artifact.ref,
|
|
172
|
+
artifactContentHash: observation.artifact.contentHash,
|
|
173
|
+
});
|
|
174
|
+
return `pduo_${identityHash.slice(7, 31)}`;
|
|
175
|
+
}
|
|
176
|
+
function projectDnaUsefulnessUnsigned(observation) {
|
|
177
|
+
return {
|
|
178
|
+
schema: observation.schema,
|
|
179
|
+
episode: { ...observation.episode },
|
|
180
|
+
delivery: { ...observation.delivery },
|
|
181
|
+
projection: {
|
|
182
|
+
role: observation.projection.role,
|
|
183
|
+
categories: [...observation.projection.categories],
|
|
184
|
+
traitIds: [...observation.projection.traitIds],
|
|
185
|
+
evidenceHashes: [...observation.projection.evidenceHashes],
|
|
186
|
+
},
|
|
187
|
+
artifact: { ...observation.artifact },
|
|
188
|
+
assessment: { ...observation.assessment },
|
|
189
|
+
signal: observation.signal,
|
|
190
|
+
evidence: observation.evidence.map((item) => ({ ...item })),
|
|
191
|
+
observedAt: observation.observedAt,
|
|
192
|
+
retainUntil: observation.retainUntil,
|
|
193
|
+
privacy: { ...observation.privacy },
|
|
194
|
+
authority: { ...observation.authority },
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
export function createProjectDnaUsefulnessObservation(input) {
|
|
198
|
+
const unsigned = projectDnaUsefulnessUnsigned({
|
|
199
|
+
schema: PROJECT_DNA_USEFULNESS_OBSERVATION_SCHEMA_VERSION,
|
|
200
|
+
episode: { ...input.episode },
|
|
201
|
+
delivery: { ...input.delivery },
|
|
202
|
+
projection: {
|
|
203
|
+
role: input.projection.role,
|
|
204
|
+
categories: [...input.projection.categories],
|
|
205
|
+
traitIds: [...input.projection.traitIds],
|
|
206
|
+
evidenceHashes: [...input.projection.evidenceHashes],
|
|
207
|
+
},
|
|
208
|
+
artifact: { ...input.artifact },
|
|
209
|
+
assessment: { ...input.assessment },
|
|
210
|
+
signal: input.signal,
|
|
211
|
+
evidence: input.evidence.map((item) => ({ ...item })),
|
|
212
|
+
observedAt: input.observedAt,
|
|
213
|
+
retainUntil: input.retainUntil,
|
|
214
|
+
privacy: { ...input.privacy },
|
|
215
|
+
authority: {
|
|
216
|
+
behavioralEffect: "none",
|
|
217
|
+
mayChangeRanking: false,
|
|
218
|
+
mayPromoteKnowledge: false,
|
|
219
|
+
mayGrantAuthority: false,
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
return ProjectDnaUsefulnessObservationSchema.parse({
|
|
223
|
+
...unsigned,
|
|
224
|
+
observationId: projectDnaUsefulnessObservationId(unsigned),
|
|
225
|
+
contentHash: projectDnaUsefulnessHash(unsigned),
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
export function assertProjectDnaUsefulnessObservation(value) {
|
|
229
|
+
ProjectDnaUsefulnessObservationSchema.parse(value);
|
|
230
|
+
}
|
|
231
|
+
/** Contradiction and staleness create review work, never a profile mutation or policy. */
|
|
232
|
+
export function projectDnaUsefulnessObservationFinding(value) {
|
|
233
|
+
const observation = ProjectDnaUsefulnessObservationSchema.parse(value);
|
|
234
|
+
if (observation.signal !== "contradicted" && observation.signal !== "stale")
|
|
235
|
+
return null;
|
|
236
|
+
const title = `Project DNA outcome ${observation.signal}: ${observation.delivery.profileId}`;
|
|
237
|
+
const evidence = [
|
|
238
|
+
`project-dna-usefulness:${observation.observationId}`,
|
|
239
|
+
`project-dna-usefulness-content:${observation.contentHash}`,
|
|
240
|
+
`episode:${observation.episode.episodeId}@${observation.episode.episodeHash}`,
|
|
241
|
+
`delivery:${observation.delivery.receiptRef}@${observation.delivery.receiptHash}`,
|
|
242
|
+
`profile:${observation.delivery.profileId}@${observation.delivery.profileContentHash}`,
|
|
243
|
+
`artifact:${observation.artifact.ref}@${observation.artifact.contentHash}`,
|
|
244
|
+
`assessment:${observation.assessment.assessmentId}@${observation.assessment.contentHash}`,
|
|
245
|
+
...observation.evidence.map((item) => `${item.kind}:${item.ref}@${item.hash}`),
|
|
246
|
+
];
|
|
247
|
+
return FindingSchema.parse({
|
|
248
|
+
id: findingId(title),
|
|
249
|
+
title,
|
|
250
|
+
observation: observation.signal === "contradicted"
|
|
251
|
+
? `Explicit outcome evidence may conflict with delivered Project DNA profile ${observation.delivery.profileId}; review the named traits and evidence before changing the profile.`
|
|
252
|
+
: `Explicit outcome evidence may show that delivered Project DNA profile ${observation.delivery.profileId} was stale; review currentness before changing the profile.`,
|
|
253
|
+
evidence,
|
|
254
|
+
method: null,
|
|
255
|
+
severity: observation.signal === "contradicted" ? "high" : "medium",
|
|
256
|
+
triage: "open",
|
|
257
|
+
affected_files: [],
|
|
258
|
+
affected_symbols: [...observation.projection.traitIds],
|
|
259
|
+
violates_constraint: null,
|
|
260
|
+
spawned_decision: null,
|
|
261
|
+
observed_at: observation.observedAt,
|
|
262
|
+
resolved_commit: null,
|
|
263
|
+
provenance: {
|
|
264
|
+
source: "project_dna_outcome_experience+candidate",
|
|
265
|
+
confidence: 0.75,
|
|
266
|
+
evidence,
|
|
267
|
+
last_verified: observation.observedAt,
|
|
268
|
+
},
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
//# sourceMappingURL=projectDnaOutcomeExperience.js.map
|
package/dist/extractors/git.js
CHANGED
|
@@ -707,17 +707,12 @@ export function commitAndPushHunch(hunchDir, message, opts) {
|
|
|
707
707
|
if (!contractReady(opts.remote)
|
|
708
708
|
|| mergeRemote(hunchDir, env, CAPTURE_REMOTE_TIMEOUT_MS, opts.remote) === "failed")
|
|
709
709
|
return "committed";
|
|
710
|
-
// Hooks are disabled in the merge seam, but another process can still
|
|
711
|
-
// rewrite Git configuration. Check once after merge and once at the
|
|
712
|
-
// actual push seam; either refusal leaves the private commit local.
|
|
713
|
-
if (unsafeOverlayPublication(hunchDir, opts.protectedRepoRoot) || !contractReady(opts.remote)) {
|
|
714
|
-
console.error(`hunch: private memory was committed locally, but the overlay publication boundary changed during sync. Nothing was pushed.`);
|
|
715
|
-
return "committed";
|
|
716
|
-
}
|
|
717
710
|
// Push tracked (not via run): a no-upstream/offline/rejected push must report
|
|
718
711
|
// "committed", not overclaim "pushed" — the next flush's merge+push retries.
|
|
719
|
-
|
|
720
|
-
|
|
712
|
+
// pushWithOneRemoteAdvanceRetry performs the publication and remote-contract
|
|
713
|
+
// proof immediately before its push seam. Repeating the same expensive proof
|
|
714
|
+
// twice here adds no intervening mutation boundary and materially slows large
|
|
715
|
+
// graph refreshes on process-spawn-sensitive platforms such as Windows.
|
|
721
716
|
if (pushWithOneRemoteAdvanceRetry(hunchDir, env, opts.protectedRepoRoot, CAPTURE_REMOTE_TIMEOUT_MS, opts.remote))
|
|
722
717
|
return "pushed";
|
|
723
718
|
}
|
package/dist/projectDna.d.ts
CHANGED
|
@@ -8,3 +8,4 @@ export { PROJECT_DNA_CATEGORIES, PROJECT_DNA_MATCH_SCHEMA_VERSION, PROJECT_DNA_S
|
|
|
8
8
|
export { PROJECT_DNA_HOST_EVIDENCE_AUTHOR_ROLES, PROJECT_DNA_HOST_EVIDENCE_DISPOSITIONS, PROJECT_DNA_HOST_EVIDENCE_KINDS, PROJECT_DNA_HOST_EVIDENCE_SCHEMA_VERSION, assertProjectDnaHostEvidence, sealProjectDnaHostEvidence, type ProjectDnaHostEvidence, type ProjectDnaHostEvidenceAuthorRole, type ProjectDnaHostEvidenceCandidate, type ProjectDnaHostEvidenceDisposition, type ProjectDnaHostEvidenceItem, type ProjectDnaHostEvidenceKind, } from "./core/projectDnaHostEvidence.js";
|
|
9
9
|
export { PROJECT_DNA_DELTA_SCHEMA_VERSION, assertProjectDnaDelta, diffProjectDna, type ProjectDnaChangeKind, type ProjectDnaDelta, type ProjectDnaTraitChange, } from "./core/projectDnaDelta.js";
|
|
10
10
|
export { PROJECT_DNA_SUPPLEMENT_KIND, projectDnaDeliverySupplement, type ProjectDnaDeliverySupplement, } from "./core/projectDnaDelivery.js";
|
|
11
|
+
export { PROJECT_DNA_USEFULNESS_EVIDENCE_KINDS, PROJECT_DNA_USEFULNESS_OBSERVATION_SCHEMA_VERSION, PROJECT_DNA_USEFULNESS_SIGNALS, ProjectDnaUsefulnessObservationSchema, assertProjectDnaUsefulnessObservation, createProjectDnaUsefulnessObservation, projectDnaUsefulnessObservationFinding, type CreateProjectDnaUsefulnessObservationInput, type ProjectDnaUsefulnessObservation, } from "./core/projectDnaOutcomeExperience.js";
|
package/dist/projectDna.js
CHANGED
|
@@ -8,4 +8,5 @@ export { PROJECT_DNA_CATEGORIES, PROJECT_DNA_MATCH_SCHEMA_VERSION, PROJECT_DNA_S
|
|
|
8
8
|
export { PROJECT_DNA_HOST_EVIDENCE_AUTHOR_ROLES, PROJECT_DNA_HOST_EVIDENCE_DISPOSITIONS, PROJECT_DNA_HOST_EVIDENCE_KINDS, PROJECT_DNA_HOST_EVIDENCE_SCHEMA_VERSION, assertProjectDnaHostEvidence, sealProjectDnaHostEvidence, } from "./core/projectDnaHostEvidence.js";
|
|
9
9
|
export { PROJECT_DNA_DELTA_SCHEMA_VERSION, assertProjectDnaDelta, diffProjectDna, } from "./core/projectDnaDelta.js";
|
|
10
10
|
export { PROJECT_DNA_SUPPLEMENT_KIND, projectDnaDeliverySupplement, } from "./core/projectDnaDelivery.js";
|
|
11
|
+
export { PROJECT_DNA_USEFULNESS_EVIDENCE_KINDS, PROJECT_DNA_USEFULNESS_OBSERVATION_SCHEMA_VERSION, PROJECT_DNA_USEFULNESS_SIGNALS, ProjectDnaUsefulnessObservationSchema, assertProjectDnaUsefulnessObservation, createProjectDnaUsefulnessObservation, projectDnaUsefulnessObservationFinding, } from "./core/projectDnaOutcomeExperience.js";
|
|
11
12
|
//# sourceMappingURL=projectDna.js.map
|
package/package.json
CHANGED
package/server.json
CHANGED
|
@@ -7,13 +7,13 @@
|
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
9
|
"websiteUrl": "https://hunch-pi.vercel.app",
|
|
10
|
-
"version": "1.22.
|
|
10
|
+
"version": "1.22.3",
|
|
11
11
|
"packages": [
|
|
12
12
|
{
|
|
13
13
|
"registryType": "npm",
|
|
14
14
|
"registryBaseUrl": "https://registry.npmjs.org",
|
|
15
15
|
"identifier": "@davesheffer/hunch",
|
|
16
|
-
"version": "1.22.
|
|
16
|
+
"version": "1.22.3",
|
|
17
17
|
"runtimeHint": "npx",
|
|
18
18
|
"packageArguments": [
|
|
19
19
|
{
|