@singi-labs/sifa-sdk 0.19.78 → 0.19.80
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/dist/{index-DAiJZvPg.d.ts → index-B0BDMGLm.d.ts} +8 -0
- package/dist/{index-k6tBrbEU.d.cts → index-BrWWVQLL.d.cts} +8 -0
- package/dist/index.cjs +7 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -7
- package/dist/index.d.ts +7 -7
- package/dist/index.js +1 -1
- package/dist/jev/issue.cjs +183 -0
- package/dist/jev/issue.cjs.map +1 -0
- package/dist/jev/issue.d.cts +119 -0
- package/dist/jev/issue.d.ts +119 -0
- package/dist/jev/issue.js +166 -0
- package/dist/jev/issue.js.map +1 -0
- package/dist/jsonld/index.cjs +11 -0
- package/dist/jsonld/index.cjs.map +1 -1
- package/dist/jsonld/index.d.cts +1 -1
- package/dist/jsonld/index.d.ts +1 -1
- package/dist/jsonld/terms.js +11 -0
- package/dist/jsonld/terms.js.map +1 -1
- package/dist/{network-map-D8JcKu28.d.ts → network-map-BEOM5v7g.d.ts} +3 -3
- package/dist/{network-map-Db_EPUDX.d.cts → network-map-DMDU4liU.d.cts} +3 -3
- package/dist/{profile-investment-Cn5b--EG.d.cts → profile-investment-QSwX2GL5.d.cts} +1 -0
- package/dist/{profile-investment-Cn5b--EG.d.ts → profile-investment-QSwX2GL5.d.ts} +1 -0
- package/dist/{profile-summary-PRDqxAQT.d.ts → profile-summary-1oXL1guc.d.ts} +1 -1
- package/dist/{profile-summary-BcbJrph1.d.cts → profile-summary-CpM9l8iq.d.cts} +1 -1
- package/dist/query/fetchers/index.cjs +2 -1
- package/dist/query/fetchers/index.cjs.map +1 -1
- package/dist/query/fetchers/index.d.cts +6 -6
- package/dist/query/fetchers/index.d.ts +6 -6
- package/dist/query/fetchers/profile-mutations.js.map +1 -1
- package/dist/query/hooks/index.cjs +24 -2
- package/dist/query/hooks/index.cjs.map +1 -1
- package/dist/query/hooks/index.d.cts +4 -4
- package/dist/query/hooks/index.d.ts +4 -4
- package/dist/query/hooks/index.js +2 -0
- package/dist/query/hooks/index.js.map +1 -1
- package/dist/query/hooks/use-rpg-status.js +19 -0
- package/dist/query/hooks/use-rpg-status.js.map +1 -0
- package/dist/query/index.cjs +11 -1
- package/dist/query/index.cjs.map +1 -1
- package/dist/query/index.d.cts +9 -9
- package/dist/query/index.d.ts +9 -9
- package/dist/query/index.js +2 -0
- package/dist/query/index.js.map +1 -1
- package/dist/query/keys.js +2 -1
- package/dist/query/keys.js.map +1 -1
- package/dist/resume/index.d.cts +1 -1
- package/dist/resume/index.d.ts +1 -1
- package/dist/rpg/avatar.js +6 -0
- package/dist/rpg/avatar.js.map +1 -0
- package/dist/rpg/index.cjs +4 -0
- package/dist/rpg/index.cjs.map +1 -1
- package/dist/rpg/index.d.cts +9 -1
- package/dist/rpg/index.d.ts +9 -1
- package/dist/rpg/index.js +2 -0
- package/dist/rpg/index.js.map +1 -1
- package/dist/schemas/index.cjs +6 -0
- package/dist/schemas/index.cjs.map +1 -1
- package/dist/schemas/index.d.cts +1 -1
- package/dist/schemas/index.d.ts +1 -1
- package/dist/schemas/profile-self.js +6 -0
- package/dist/schemas/profile-self.js.map +1 -1
- package/dist/schemas/write/index.cjs +13 -1
- package/dist/schemas/write/index.cjs.map +1 -1
- package/dist/schemas/write/index.d.cts +3 -0
- package/dist/schemas/write/index.d.ts +3 -0
- package/dist/schemas/write/profile-self.js +9 -1
- package/dist/schemas/write/profile-self.js.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/{types-CI24asgo.d.ts → types-DB7UkX43.d.ts} +1 -1
- package/dist/{types-qw55KvoV.d.cts → types-DQfWqSud.d.cts} +1 -1
- package/dist/{use-user-settings-fWHkdX3c.d.ts → use-user-settings-A_i6Nrj1.d.ts} +25 -4
- package/dist/{use-user-settings-DWj8BC5K.d.cts → use-user-settings-U-cIysUa.d.cts} +25 -4
- package/dist/{user-settings-nov4rgwR.d.ts → user-settings-CGJPdwTM.d.ts} +9 -3
- package/dist/{user-settings-qkxxTwFP.d.cts → user-settings-DdWaL2AG.d.cts} +9 -3
- package/package.json +11 -1
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
// src/jev/issue.ts
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import {
|
|
4
|
+
choiceAnswerSchema,
|
|
5
|
+
noulAnswerSchema,
|
|
6
|
+
pickChoiceAboveFloor
|
|
7
|
+
} from "./index.js";
|
|
8
|
+
var ISSUE_BODY_MAX_CHARS = 6e3;
|
|
9
|
+
function buildIssueTriageState(issue) {
|
|
10
|
+
const state = { repo: issue.repo, title: issue.title.trim() };
|
|
11
|
+
const body = issue.body?.trim();
|
|
12
|
+
if (body) {
|
|
13
|
+
if (body.length > ISSUE_BODY_MAX_CHARS) {
|
|
14
|
+
state.body = body.slice(0, ISSUE_BODY_MAX_CHARS);
|
|
15
|
+
state.bodyTruncated = true;
|
|
16
|
+
} else {
|
|
17
|
+
state.body = body;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
if (issue.existingLabels && issue.existingLabels.length > 0) {
|
|
21
|
+
state.existingLabels = issue.existingLabels;
|
|
22
|
+
}
|
|
23
|
+
return state;
|
|
24
|
+
}
|
|
25
|
+
var ISSUE_TYPE_TAXONOMY = {
|
|
26
|
+
bug: "Something that exists does not behave as documented or expected (error, crash, wrong output)",
|
|
27
|
+
feature: "A request for new behaviour or capability that does not exist yet",
|
|
28
|
+
question: "A question about how something works, with nothing to build or fix",
|
|
29
|
+
documentation: "Docs, README, comments, or examples are missing, wrong, or unclear",
|
|
30
|
+
"tech-debt": "Internal refactor, cleanup, dependency, or tooling work with no user-visible change",
|
|
31
|
+
spam: "Spam, gibberish, advertising, or a test submission",
|
|
32
|
+
unclear: "Not enough information to decide the type"
|
|
33
|
+
};
|
|
34
|
+
var ISSUE_STREAM_TAXONOMY = {
|
|
35
|
+
sifa: "The Sifa profile, activity stream, ingestion, search, or web app",
|
|
36
|
+
kootana: "Kootana: events, meetings, in-person connect, QR scan, organizer tools",
|
|
37
|
+
unclear: "Cannot tell from the issue"
|
|
38
|
+
};
|
|
39
|
+
var ISSUE_STREAM_LABELS = {
|
|
40
|
+
sifa: null,
|
|
41
|
+
kootana: "stream:kootana",
|
|
42
|
+
unclear: null
|
|
43
|
+
};
|
|
44
|
+
function choiceQuestion(instructions, criteria) {
|
|
45
|
+
return { type: "choice", instructions, criteria };
|
|
46
|
+
}
|
|
47
|
+
var ISSUE_TYPE_CHOICE_QUESTION = choiceQuestion(
|
|
48
|
+
"The state holds one GitHub issue (repo, title, body, existing labels). Which single type best describes it?",
|
|
49
|
+
ISSUE_TYPE_TAXONOMY
|
|
50
|
+
);
|
|
51
|
+
var ISSUE_STREAM_CHOICE_QUESTION = choiceQuestion(
|
|
52
|
+
"Which product stream does this issue concern?",
|
|
53
|
+
ISSUE_STREAM_TAXONOMY
|
|
54
|
+
);
|
|
55
|
+
var ISSUE_ACTIONABLE_NOUL_QUESTION = {
|
|
56
|
+
type: "noul",
|
|
57
|
+
instructions: "Does the issue contain enough information for a maintainer to act on it without asking the reporter anything?",
|
|
58
|
+
criteria: {
|
|
59
|
+
true: "For a bug: steps or a trigger, expected vs actual, and an error or location. For a feature: the problem, the desired outcome, and rough scope.",
|
|
60
|
+
false: "Essential details are missing: no way to reproduce, no expected behaviour, vague wish with no outcome, or a bare title."
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
var ISSUE_SECURITY_NOUL_QUESTION = {
|
|
64
|
+
type: "noul",
|
|
65
|
+
instructions: "Does the issue describe a security-relevant problem?",
|
|
66
|
+
criteria: {
|
|
67
|
+
true: "A vulnerability, auth or session flaw, data exposure, abuse or spam vector, secrets handling, or a dependency advisory.",
|
|
68
|
+
false: "An ordinary bug, feature, question, or docs issue with no security angle."
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
var ISSUE_REGRESSION_NOUL_QUESTION = {
|
|
72
|
+
type: "noul",
|
|
73
|
+
instructions: "Does the issue report that something which previously worked no longer works?",
|
|
74
|
+
criteria: {
|
|
75
|
+
true: "The reporter states or clearly implies the behaviour worked before a release, deploy, or change.",
|
|
76
|
+
false: "A new bug with no prior-working claim, a feature request, or a question."
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
var ISSUE_TRIAGE_QUESTION_IDS = {
|
|
80
|
+
type: "issueType",
|
|
81
|
+
stream: "issueStream",
|
|
82
|
+
actionable: "issueActionable",
|
|
83
|
+
security: "issueSecurity",
|
|
84
|
+
regression: "issueRegression"
|
|
85
|
+
};
|
|
86
|
+
function buildIssueTriageQuestions() {
|
|
87
|
+
return {
|
|
88
|
+
[ISSUE_TRIAGE_QUESTION_IDS.type]: ISSUE_TYPE_CHOICE_QUESTION,
|
|
89
|
+
[ISSUE_TRIAGE_QUESTION_IDS.stream]: ISSUE_STREAM_CHOICE_QUESTION,
|
|
90
|
+
[ISSUE_TRIAGE_QUESTION_IDS.actionable]: ISSUE_ACTIONABLE_NOUL_QUESTION,
|
|
91
|
+
[ISSUE_TRIAGE_QUESTION_IDS.security]: ISSUE_SECURITY_NOUL_QUESTION,
|
|
92
|
+
[ISSUE_TRIAGE_QUESTION_IDS.regression]: ISSUE_REGRESSION_NOUL_QUESTION
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
var issueTriageAnswersSchema = z.object({
|
|
96
|
+
[ISSUE_TRIAGE_QUESTION_IDS.type]: choiceAnswerSchema,
|
|
97
|
+
[ISSUE_TRIAGE_QUESTION_IDS.stream]: choiceAnswerSchema,
|
|
98
|
+
[ISSUE_TRIAGE_QUESTION_IDS.actionable]: noulAnswerSchema,
|
|
99
|
+
[ISSUE_TRIAGE_QUESTION_IDS.security]: noulAnswerSchema,
|
|
100
|
+
[ISSUE_TRIAGE_QUESTION_IDS.regression]: noulAnswerSchema
|
|
101
|
+
});
|
|
102
|
+
var ISSUE_TYPE_CONFIDENCE_FLOOR = 0.6;
|
|
103
|
+
var ISSUE_STREAM_CONFIDENCE_FLOOR = 0.7;
|
|
104
|
+
var ISSUE_NEEDS_INFO_MAX_ACTIONABLE = 0.35;
|
|
105
|
+
var ISSUE_ROUTING_THRESHOLD = 0.85;
|
|
106
|
+
function clearsNoul(answer, threshold) {
|
|
107
|
+
return answer.noul >= threshold;
|
|
108
|
+
}
|
|
109
|
+
function pickType(answer, floor) {
|
|
110
|
+
const choice = pickChoiceAboveFloor(answer, { floor, noMatch: "unclear" });
|
|
111
|
+
return choice !== null && choice in ISSUE_TYPE_TAXONOMY ? choice : null;
|
|
112
|
+
}
|
|
113
|
+
function pickStream(answer, floor) {
|
|
114
|
+
const choice = pickChoiceAboveFloor(answer, { floor, noMatch: "unclear" });
|
|
115
|
+
return choice !== null && choice in ISSUE_STREAM_TAXONOMY ? choice : null;
|
|
116
|
+
}
|
|
117
|
+
function issueLabelsFromAnswers(answers, opts = {}) {
|
|
118
|
+
const typeFloor = opts.typeFloor ?? ISSUE_TYPE_CONFIDENCE_FLOOR;
|
|
119
|
+
const streamFloor = opts.streamFloor ?? ISSUE_STREAM_CONFIDENCE_FLOOR;
|
|
120
|
+
const needsInfoMax = opts.needsInfoMaxActionable ?? ISSUE_NEEDS_INFO_MAX_ACTIONABLE;
|
|
121
|
+
const routing = opts.routingThreshold ?? ISSUE_ROUTING_THRESHOLD;
|
|
122
|
+
const type = pickType(answers[ISSUE_TRIAGE_QUESTION_IDS.type], typeFloor);
|
|
123
|
+
if (type === "spam") {
|
|
124
|
+
return {
|
|
125
|
+
labels: ["spam"],
|
|
126
|
+
type,
|
|
127
|
+
stream: null,
|
|
128
|
+
needsInfo: false,
|
|
129
|
+
security: false,
|
|
130
|
+
regression: false
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
const stream = pickStream(answers[ISSUE_TRIAGE_QUESTION_IDS.stream], streamFloor);
|
|
134
|
+
const needsInfo = answers[ISSUE_TRIAGE_QUESTION_IDS.actionable].noul < needsInfoMax;
|
|
135
|
+
const security = clearsNoul(answers[ISSUE_TRIAGE_QUESTION_IDS.security], routing);
|
|
136
|
+
const regression = clearsNoul(answers[ISSUE_TRIAGE_QUESTION_IDS.regression], routing);
|
|
137
|
+
const labels = [];
|
|
138
|
+
if (type !== null) labels.push(type);
|
|
139
|
+
if (security) labels.push("security");
|
|
140
|
+
if (regression) labels.push("regression");
|
|
141
|
+
const streamLabel = stream !== null ? ISSUE_STREAM_LABELS[stream] : null;
|
|
142
|
+
if (streamLabel) labels.push(streamLabel);
|
|
143
|
+
if (needsInfo) labels.push("needs-info");
|
|
144
|
+
return { labels, type, stream, needsInfo, security, regression };
|
|
145
|
+
}
|
|
146
|
+
export {
|
|
147
|
+
ISSUE_ACTIONABLE_NOUL_QUESTION,
|
|
148
|
+
ISSUE_BODY_MAX_CHARS,
|
|
149
|
+
ISSUE_NEEDS_INFO_MAX_ACTIONABLE,
|
|
150
|
+
ISSUE_REGRESSION_NOUL_QUESTION,
|
|
151
|
+
ISSUE_ROUTING_THRESHOLD,
|
|
152
|
+
ISSUE_SECURITY_NOUL_QUESTION,
|
|
153
|
+
ISSUE_STREAM_CHOICE_QUESTION,
|
|
154
|
+
ISSUE_STREAM_CONFIDENCE_FLOOR,
|
|
155
|
+
ISSUE_STREAM_LABELS,
|
|
156
|
+
ISSUE_STREAM_TAXONOMY,
|
|
157
|
+
ISSUE_TRIAGE_QUESTION_IDS,
|
|
158
|
+
ISSUE_TYPE_CHOICE_QUESTION,
|
|
159
|
+
ISSUE_TYPE_CONFIDENCE_FLOOR,
|
|
160
|
+
ISSUE_TYPE_TAXONOMY,
|
|
161
|
+
buildIssueTriageQuestions,
|
|
162
|
+
buildIssueTriageState,
|
|
163
|
+
issueLabelsFromAnswers,
|
|
164
|
+
issueTriageAnswersSchema
|
|
165
|
+
};
|
|
166
|
+
//# sourceMappingURL=issue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/jev/issue.ts"],"sourcesContent":["/**\n * Issue-triage judgments for the background-agent chores (sifa-workspace\n * decision 2026-10-05, background agents tier policy). Pure builders: the\n * typed questions to ask Jev about a GitHub issue, the label taxonomies, and\n * the thresholds that turn answers into label suggestions. No network, no key.\n *\n * Scope is deliberately T0 (read-only): the output is a list of label\n * suggestions a workflow may apply from an allowlist, never a code change.\n * Jev only sees public issue text. Exact signals (GlitchTip links, template\n * fields present) stay in code, not in a judgment.\n */\n\nimport { z } from 'zod';\n\nimport {\n choiceAnswerSchema,\n noulAnswerSchema,\n pickChoiceAboveFloor,\n type ChoiceAnswer,\n type ChoiceQuestion,\n type NoulAnswer,\n type NoulQuestion,\n} from './index.js';\n\n// ---------------------------------------------------------------------------\n// Input and state\n// ---------------------------------------------------------------------------\n\n/** Public, non-user fields of a GitHub issue that the judgment may see. */\nexport interface IssueInput {\n repo: string;\n title: string;\n body?: string;\n /** Labels already on the issue (e.g. set by a template). */\n existingLabels?: string[];\n}\n\n/** Longest issue body forwarded to Jev; keeps state bounded and cheap. */\nexport const ISSUE_BODY_MAX_CHARS = 6000;\n\nexport interface IssueTriageState {\n repo: string;\n title: string;\n body?: string;\n bodyTruncated?: true;\n existingLabels?: string[];\n}\n\n/** State for the issue questions. Absent and blank fields are dropped. */\nexport function buildIssueTriageState(issue: IssueInput): IssueTriageState {\n const state: IssueTriageState = { repo: issue.repo, title: issue.title.trim() };\n const body = issue.body?.trim();\n if (body) {\n if (body.length > ISSUE_BODY_MAX_CHARS) {\n state.body = body.slice(0, ISSUE_BODY_MAX_CHARS);\n state.bodyTruncated = true;\n } else {\n state.body = body;\n }\n }\n if (issue.existingLabels && issue.existingLabels.length > 0) {\n state.existingLabels = issue.existingLabels;\n }\n return state;\n}\n\n// ---------------------------------------------------------------------------\n// Taxonomies (keys double as label names where a label exists)\n// ---------------------------------------------------------------------------\n\n/** One type label per issue. `unclear` is the no-match option and never a label. */\nexport const ISSUE_TYPE_TAXONOMY: Record<string, string> = {\n bug: 'Something that exists does not behave as documented or expected (error, crash, wrong output)',\n feature: 'A request for new behaviour or capability that does not exist yet',\n question: 'A question about how something works, with nothing to build or fix',\n documentation: 'Docs, README, comments, or examples are missing, wrong, or unclear',\n 'tech-debt':\n 'Internal refactor, cleanup, dependency, or tooling work with no user-visible change',\n spam: 'Spam, gibberish, advertising, or a test submission',\n unclear: 'Not enough information to decide the type',\n};\n\n/** Which product stream an issue belongs to. `unclear` is the no-match option. */\nexport const ISSUE_STREAM_TAXONOMY: Record<string, string> = {\n sifa: 'The Sifa profile, activity stream, ingestion, search, or web app',\n kootana: 'Kootana: events, meetings, in-person connect, QR scan, organizer tools',\n unclear: 'Cannot tell from the issue',\n};\n\n/** Label applied for the Kootana stream; the Sifa stream carries no label. */\nexport const ISSUE_STREAM_LABELS: Readonly<Record<string, string | null>> = {\n sifa: null,\n kootana: 'stream:kootana',\n unclear: null,\n};\n\n// ---------------------------------------------------------------------------\n// Questions (asked together over one issue state)\n// ---------------------------------------------------------------------------\n\nfunction choiceQuestion(instructions: string, criteria: Record<string, string>): ChoiceQuestion {\n return { type: 'choice', instructions, criteria };\n}\n\nexport const ISSUE_TYPE_CHOICE_QUESTION = choiceQuestion(\n 'The state holds one GitHub issue (repo, title, body, existing labels). Which single type best describes it?',\n ISSUE_TYPE_TAXONOMY,\n);\n\nexport const ISSUE_STREAM_CHOICE_QUESTION = choiceQuestion(\n 'Which product stream does this issue concern?',\n ISSUE_STREAM_TAXONOMY,\n);\n\nexport const ISSUE_ACTIONABLE_NOUL_QUESTION: NoulQuestion = {\n type: 'noul',\n instructions:\n 'Does the issue contain enough information for a maintainer to act on it without asking the reporter anything?',\n criteria: {\n true: 'For a bug: steps or a trigger, expected vs actual, and an error or location. For a feature: the problem, the desired outcome, and rough scope.',\n false:\n 'Essential details are missing: no way to reproduce, no expected behaviour, vague wish with no outcome, or a bare title.',\n },\n};\n\nexport const ISSUE_SECURITY_NOUL_QUESTION: NoulQuestion = {\n type: 'noul',\n instructions: 'Does the issue describe a security-relevant problem?',\n criteria: {\n true: 'A vulnerability, auth or session flaw, data exposure, abuse or spam vector, secrets handling, or a dependency advisory.',\n false: 'An ordinary bug, feature, question, or docs issue with no security angle.',\n },\n};\n\nexport const ISSUE_REGRESSION_NOUL_QUESTION: NoulQuestion = {\n type: 'noul',\n instructions: 'Does the issue report that something which previously worked no longer works?',\n criteria: {\n true: 'The reporter states or clearly implies the behaviour worked before a release, deploy, or change.',\n false: 'A new bug with no prior-working claim, a feature request, or a question.',\n },\n};\n\n/** Stable question ids; the answer keys Jev returns. */\nexport const ISSUE_TRIAGE_QUESTION_IDS = {\n type: 'issueType',\n stream: 'issueStream',\n actionable: 'issueActionable',\n security: 'issueSecurity',\n regression: 'issueRegression',\n} as const;\n\n/** All issue questions, keyed by {@link ISSUE_TRIAGE_QUESTION_IDS}, for one batched call. */\nexport function buildIssueTriageQuestions(): Record<string, ChoiceQuestion | NoulQuestion> {\n return {\n [ISSUE_TRIAGE_QUESTION_IDS.type]: ISSUE_TYPE_CHOICE_QUESTION,\n [ISSUE_TRIAGE_QUESTION_IDS.stream]: ISSUE_STREAM_CHOICE_QUESTION,\n [ISSUE_TRIAGE_QUESTION_IDS.actionable]: ISSUE_ACTIONABLE_NOUL_QUESTION,\n [ISSUE_TRIAGE_QUESTION_IDS.security]: ISSUE_SECURITY_NOUL_QUESTION,\n [ISSUE_TRIAGE_QUESTION_IDS.regression]: ISSUE_REGRESSION_NOUL_QUESTION,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Answers -> label suggestions\n// ---------------------------------------------------------------------------\n\n/** Parsed answers for the batched issue call. */\nexport const issueTriageAnswersSchema = z.object({\n [ISSUE_TRIAGE_QUESTION_IDS.type]: choiceAnswerSchema,\n [ISSUE_TRIAGE_QUESTION_IDS.stream]: choiceAnswerSchema,\n [ISSUE_TRIAGE_QUESTION_IDS.actionable]: noulAnswerSchema,\n [ISSUE_TRIAGE_QUESTION_IDS.security]: noulAnswerSchema,\n [ISSUE_TRIAGE_QUESTION_IDS.regression]: noulAnswerSchema,\n});\nexport type IssueTriageAnswers = z.infer<typeof issueTriageAnswersSchema>;\n\n/**\n * Thresholds. Precision over recall: a wrong label costs a maintainer a click\n * and trains distrust; a missing label costs nothing. Validate on labelled\n * closed issues (sifa-api#1555) before widening.\n */\nexport const ISSUE_TYPE_CONFIDENCE_FLOOR = 0.6;\nexport const ISSUE_STREAM_CONFIDENCE_FLOOR = 0.7;\n/** Below this P(actionable) the issue gets `needs-info`. */\nexport const ISSUE_NEEDS_INFO_MAX_ACTIONABLE = 0.35;\n/** Routing labels (security, regression) need a confident yes. */\nexport const ISSUE_ROUTING_THRESHOLD = 0.85;\n\nexport interface IssueLabelSuggestions {\n /** Labels to apply, in a stable order, each guaranteed to be a real label name. */\n labels: string[];\n /** The type choice after the floor, or null when unset. */\n type: string | null;\n /** The stream choice after the floor, or null when unset. */\n stream: string | null;\n needsInfo: boolean;\n security: boolean;\n regression: boolean;\n}\n\nexport interface IssueLabelOptions {\n typeFloor?: number;\n streamFloor?: number;\n needsInfoMaxActionable?: number;\n routingThreshold?: number;\n}\n\nfunction clearsNoul(answer: NoulAnswer, threshold: number): boolean {\n return answer.noul >= threshold;\n}\n\nfunction pickType(answer: ChoiceAnswer, floor: number): string | null {\n const choice = pickChoiceAboveFloor(answer, { floor, noMatch: 'unclear' });\n return choice !== null && choice in ISSUE_TYPE_TAXONOMY ? choice : null;\n}\n\nfunction pickStream(answer: ChoiceAnswer, floor: number): string | null {\n const choice = pickChoiceAboveFloor(answer, { floor, noMatch: 'unclear' });\n return choice !== null && choice in ISSUE_STREAM_TAXONOMY ? choice : null;\n}\n\n/**\n * Turn validated answers into label suggestions. Spam short-circuits: a spam\n * issue gets only `spam`, no routing or needs-info. A choice outside the\n * taxonomy (Jev invented a key) is treated as unset.\n */\nexport function issueLabelsFromAnswers(\n answers: IssueTriageAnswers,\n opts: IssueLabelOptions = {},\n): IssueLabelSuggestions {\n const typeFloor = opts.typeFloor ?? ISSUE_TYPE_CONFIDENCE_FLOOR;\n const streamFloor = opts.streamFloor ?? ISSUE_STREAM_CONFIDENCE_FLOOR;\n const needsInfoMax = opts.needsInfoMaxActionable ?? ISSUE_NEEDS_INFO_MAX_ACTIONABLE;\n const routing = opts.routingThreshold ?? ISSUE_ROUTING_THRESHOLD;\n\n const type = pickType(answers[ISSUE_TRIAGE_QUESTION_IDS.type], typeFloor);\n if (type === 'spam') {\n return {\n labels: ['spam'],\n type,\n stream: null,\n needsInfo: false,\n security: false,\n regression: false,\n };\n }\n\n const stream = pickStream(answers[ISSUE_TRIAGE_QUESTION_IDS.stream], streamFloor);\n const needsInfo = answers[ISSUE_TRIAGE_QUESTION_IDS.actionable].noul < needsInfoMax;\n const security = clearsNoul(answers[ISSUE_TRIAGE_QUESTION_IDS.security], routing);\n const regression = clearsNoul(answers[ISSUE_TRIAGE_QUESTION_IDS.regression], routing);\n\n const labels: string[] = [];\n if (type !== null) labels.push(type);\n if (security) labels.push('security');\n if (regression) labels.push('regression');\n const streamLabel = stream !== null ? ISSUE_STREAM_LABELS[stream] : null;\n if (streamLabel) labels.push(streamLabel);\n if (needsInfo) labels.push('needs-info');\n\n return { labels, type, stream, needsInfo, security, regression };\n}\n"],"mappings":"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","names":[]}
|
package/dist/jsonld/index.cjs
CHANGED
|
@@ -273,6 +273,12 @@ var term_mappings_default = {
|
|
|
273
273
|
match: "exactMatch",
|
|
274
274
|
terms: ["schema:Project", "foaf:Project"]
|
|
275
275
|
},
|
|
276
|
+
{
|
|
277
|
+
lexicon: "id.sifa.profile.project",
|
|
278
|
+
field: "events",
|
|
279
|
+
match: "relatedMatch",
|
|
280
|
+
terms: ["schema:organizer"]
|
|
281
|
+
},
|
|
276
282
|
{
|
|
277
283
|
lexicon: "id.sifa.profile.publication",
|
|
278
284
|
match: "broadMatch",
|
|
@@ -412,6 +418,11 @@ var term_mappings_default = {
|
|
|
412
418
|
field: "discoverable",
|
|
413
419
|
reason: "Sifa indexing control, not a fact about the person."
|
|
414
420
|
},
|
|
421
|
+
{
|
|
422
|
+
lexicon: "id.sifa.profile.self",
|
|
423
|
+
field: "avatarSource",
|
|
424
|
+
reason: "Rendering instruction for apps, not a fact about the person."
|
|
425
|
+
},
|
|
415
426
|
{
|
|
416
427
|
lexicon: "id.sifa.profile.position",
|
|
417
428
|
field: "isPrimary",
|