amsd-pipeline-shared 0.5.5 → 0.5.6
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/orchestrations/prompts/doctor-repair.md +1 -1
- package/orchestrations/scripts/lib/doctor/classify.js +13 -2
- package/orchestrations/scripts/lib/doctor/crash-record.js +1 -1
- package/orchestrations/scripts/lib/doctor/handle.js +3 -1
- package/orchestrations/scripts/lib/doctor/profile.js +2 -0
- package/package.json +1 -1
|
@@ -17,7 +17,7 @@ AGENTIC FIRST — decide this before anything else
|
|
|
17
17
|
- The agentic layer of {{component}} is: {{agenticDescription}}. It lives in: {{agenticDirs}}.
|
|
18
18
|
- If an agent caused it, repair the AGENTIC layer: sharpen the instruction, the answer schema and its field descriptions, the hand-off contract between the agents — so the agent is asked in a way that gets the right answer. Do NOT add deterministic code that tolerates, repairs or re-parses a wrong agent answer, and do not add a guard that hides an agent's behaviour.
|
|
19
19
|
- Only a clear and outright coding bug gets a deterministic fix.
|
|
20
|
-
- This abort was classified as: {{abortKind}} ({{layerHint}}). An agentic abort MUST be repaired agentically. For a crash,
|
|
20
|
+
- This abort was classified as: {{abortKind}} ({{layerHint}}). An agentic abort MUST be repaired agentically. For a crash or a fault (the leg failed without giving a verdict: a stage with no result, a session that answered an error), the layer is yours to find — look for the agentic cause first — and say which and why.
|
|
21
21
|
- An agentic repair is proven by REPLAY: replay the real reply or hand-off that failed — copy it into a fixture — against the schema, the contract or the rendered instruction in the RED test (it fails on the base, passes after), and assert on the rendered instruction or schema text that now prevents the abort.
|
|
22
22
|
|
|
23
23
|
HOW YOU WORK — in this order
|
|
@@ -23,7 +23,7 @@ function signaturesFor(runtime, injected) {
|
|
|
23
23
|
internalFrame: rxOf(s.internalFrame), dependencyDir: s.dependencyDir };
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
function classify({ profile, portRoot, res, crash, aborted, since, signatures }) {
|
|
26
|
+
function classify({ profile, portRoot, res, crash, aborted, since, signatures, evidence }) {
|
|
27
27
|
const sig = signaturesFor(profile.classify.runtime, signatures);
|
|
28
28
|
if (!res || typeof res !== 'object') return no('no-result', 'the leg gave no result');
|
|
29
29
|
if (aborted) return no('aborted', 'the operator or a watcher ended the leg');
|
|
@@ -33,7 +33,17 @@ function classify({ profile, portRoot, res, crash, aborted, since, signatures })
|
|
|
33
33
|
if (res.status === 'failed') {
|
|
34
34
|
const reason = typeof res.reason === 'string' ? res.reason : '';
|
|
35
35
|
const hit = reason && profile.agentic.abortSignatures.find((r) => r.test(reason));
|
|
36
|
-
if (!hit)
|
|
36
|
+
if (!hit) {
|
|
37
|
+
// A FAILED LEG THAT GAVE NO VERDICT (operator, 2026-10-20, after run 11 leg 3: "these are the types of bugs I need doctor to resolve during a run"): the machinery failed without throwing
|
|
38
|
+
// — a stage's result with no exit, a session that answered an error. Which lines of the leg's evidence say so is the pipeline's profile (classify.faultMarks); a lane's own verdict
|
|
39
|
+
// has a number and its reason and matches none. The marked line is still refused if it names the machine, the network, the model service or a kill.
|
|
40
|
+
const line = evidence && profile.classify.faultMarks.length ? String(evidence).split('\n').find((l) => profile.classify.faultMarks.some((r) => r.test(l))) : null;
|
|
41
|
+
if (line) {
|
|
42
|
+
if (sig.external.test(line)) return no('external', `the failing line also names the machine, the network, the model service or a kill — not the pipeline: ${line.slice(0, 160)}`);
|
|
43
|
+
return { call: true, kind: 'fault', layer: 'undecided', why: `the leg failed without a verdict: ${line.trim().slice(0, 200)}` };
|
|
44
|
+
}
|
|
45
|
+
return no('not-a-crash', 'the leg failed on a verdict that names no agent-caused message — reported, not repaired');
|
|
46
|
+
}
|
|
37
47
|
if (sig.external.test(reason)) return no('external', 'the agent-caused message also names the machine, the network, the model service or a kill — not the pipeline');
|
|
38
48
|
return { call: true, kind: 'agentic-abort', layer: 'agentic', why: `an agent caused the abort: ${reason.slice(0, 200)}` };
|
|
39
49
|
}
|
|
@@ -49,6 +59,7 @@ function classify({ profile, portRoot, res, crash, aborted, since, signatures })
|
|
|
49
59
|
const parts = rel.split(path.sep);
|
|
50
60
|
const inPort = !!portRoot && !rel.startsWith('..') && !path.isAbsolute(rel) && profile.scope.repairDirs.includes(parts[0]) && !parts.includes(sig.dependencyDir);
|
|
51
61
|
if (!inPort) return no('outside-port', `the throw site ${site.file}:${site.line} is not the component's own code`);
|
|
62
|
+
if (crash.fault === true) return { call: true, kind: 'fault', layer: 'undecided', why: `a fault the component raised: ${String(crash.message).slice(0, 160)} — at ${rel}:${site.line}${crash.step ? ` (step: ${crash.step})` : ''}` };
|
|
52
63
|
if (!sig.runtimeNames.has(crash.name) && !sig.runtimeMessage.test(crash.message || '')) return no('ambiguous', `an Error in ${rel}:${site.line} with no sign of a code defect — reported`);
|
|
53
64
|
return { call: true, kind: 'port-defect', layer: 'code', why: `${crash.name}: ${String(crash.message).slice(0, 160)} — thrown at ${rel}:${site.line}${crash.step ? ` (step: ${crash.step})` : ''}` };
|
|
54
65
|
}
|
|
@@ -27,7 +27,7 @@ function frames(stack) {
|
|
|
27
27
|
|
|
28
28
|
/** What was thrown, whatever it was: an Error, or anything a program may throw. */
|
|
29
29
|
function describe(e) {
|
|
30
|
-
if (e instanceof Error) return { name: e.name || 'Error', message: String(e.message), stack: String(e.stack || '') };
|
|
30
|
+
if (e instanceof Error) return { name: e.name || 'Error', message: String(e.message), stack: String(e.stack || ''), ...(e.fault === true ? { fault: true, evidence: Array.isArray(e.evidence) ? e.evidence.map(String) : [] } : {}) };
|
|
31
31
|
let text; try { text = typeof e === 'string' ? e : JSON.stringify(e); } catch { text = String(e); }
|
|
32
32
|
return { name: 'NonError', message: String(text), stack: '' };
|
|
33
33
|
}
|
|
@@ -29,7 +29,9 @@ async function handle(a) {
|
|
|
29
29
|
const d = open(runDir, cfg, profile);
|
|
30
30
|
const portRoot = path.join(install, profile.install.dest);
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
// the leg's evidence tail (the files the profile names), read BEFORE the decision: a failure that threw nothing is judged on what the run itself wrote
|
|
33
|
+
const evidence = profile.logs.evidence.map((f) => tail(path.join(runDir, f), profile.logs.evidenceTailLines)).join('\n');
|
|
34
|
+
const c = classify({ profile, portRoot, res, crash, aborted, since, evidence });
|
|
33
35
|
if (!c.call) { d.event('not-called', { kind: c.kind, why: c.why }); return { handled: false, kind: c.kind, why: c.why }; }
|
|
34
36
|
d.event('trigger', { kind: c.kind, layer: c.layer, why: c.why, step: (crash && crash.step) || '' });
|
|
35
37
|
|
|
@@ -77,6 +77,8 @@ function validate(input) {
|
|
|
77
77
|
out.classify = {};
|
|
78
78
|
if (need('classify', cl, 'runtime')) out.classify.runtime = str('classify.runtime', cl.runtime);
|
|
79
79
|
if (need('classify', cl, 'refusals')) out.classify.refusals = rxs('classify.refusals', cl.refusals);
|
|
80
|
+
// THE LINES THAT MEAN "THE MACHINERY GAVE NO VERDICT" (optional; none = a failed leg is never taken for a fault): a pipeline's own knowledge, matched against the leg's evidence tail
|
|
81
|
+
out.classify.faultMarks = cl.faultMarks === undefined ? [] : rxs('classify.faultMarks', cl.faultMarks);
|
|
80
82
|
}
|
|
81
83
|
|
|
82
84
|
const se = p.settings;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "amsd-pipeline-shared",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.6",
|
|
4
4
|
"description": "The AMSD pipeline's shared components, one source for the bash pipeline and its Claude workflows: the model-call gateway (llm-handler.sh — retry, ladder, self-heal, cost) and the libraries it runs.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"bin": {
|