amsd-pipeline-shared 0.5.38 → 0.5.39
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.
|
@@ -375,7 +375,8 @@ function setFidelityJudge({ install, env = process.env, logDir }) {
|
|
|
375
375
|
return async ({ prompt, schema, codeline }) => {
|
|
376
376
|
const seamEnv = seamInvocationEnv('prompt-review', path.join(orchOf(install), 'agents'));
|
|
377
377
|
if (seamEnv.EPAM_ALLOWED_TOOLS) seamEnv.AI_GATE_ALLOW_TOOLS = '1';
|
|
378
|
-
|
|
378
|
+
// the call runs AS the prompt-review seam (llm-handler resolves the seam by agent name); the ledger names the check
|
|
379
|
+
seamEnv.EPAM_AGENT_NAME = 'prompt-review';
|
|
379
380
|
seamEnv.EPAM_RESPONSE_SCHEMA = spec.schemaEnv({ name: 'set_fidelity', description: 'what is geared to the ticket', parameters: schema });
|
|
380
381
|
const text = await spec.runClaude(promptExec, prompt, path.join(logDir || os.tmpdir(), `set-fidelity-${codeline}.log`), seamEnv, { costAgent: 'set-fidelity' });
|
|
381
382
|
const m = String(text || '').match(/\{[\s\S]*\}/);
|
|
@@ -4470,13 +4470,29 @@ const TOOL_ROSTER_REVIEW = {
|
|
|
4470
4470
|
'checked with your tools. Do not answer in prose.',
|
|
4471
4471
|
parameters: {
|
|
4472
4472
|
type: 'object',
|
|
4473
|
-
required: ['verdict', 'findings'],
|
|
4473
|
+
required: ['verdict', 'findings', 'roles'],
|
|
4474
4474
|
properties: {
|
|
4475
4475
|
verdict: {
|
|
4476
4476
|
type: 'string',
|
|
4477
4477
|
enum: ['sound', 'defects_found', 'nothing_to_review'],
|
|
4478
4478
|
description: 'sound = every checkable claim held. defects_found = at least one did not.',
|
|
4479
4479
|
},
|
|
4480
|
+
// A ROLE OUTLIVES THE TICKET (operator, 2026-10-24): the roster is kept with its codelines and reused for every later story, so
|
|
4481
|
+
// every minted role is answered for, one by one — the rule in prose alone was answered "sound" on a roster whose every agent was
|
|
4482
|
+
// named after the ticket. A role that does not outlive the ticket becomes a blocking finding (rolesOutliveTicketFindings).
|
|
4483
|
+
roles: {
|
|
4484
|
+
type: 'array',
|
|
4485
|
+
description: 'One entry for EVERY minted role reviewed.',
|
|
4486
|
+
items: {
|
|
4487
|
+
type: 'object',
|
|
4488
|
+
required: ['name', 'outlivesTicket', 'why'],
|
|
4489
|
+
properties: {
|
|
4490
|
+
name: { type: 'string', description: 'The minted role, named exactly as in the roster.' },
|
|
4491
|
+
outlivesTicket: { type: 'boolean', description: 'true only when this role — its name and its brief — would serve a story on this codeline about something OTHER than the current ticket: named for the kind of engineer/investigator and the codeline, briefed on the codeline, not on this ticket\'s subject, components or files (except as marked examples).' },
|
|
4492
|
+
why: { type: 'string', description: 'Quote the words that gear the role to the ticket, or say what makes it the codeline\'s.' },
|
|
4493
|
+
},
|
|
4494
|
+
},
|
|
4495
|
+
},
|
|
4480
4496
|
findings: {
|
|
4481
4497
|
type: 'array',
|
|
4482
4498
|
items: {
|
|
@@ -4885,6 +4901,19 @@ function _readJsonOrNull(f) {
|
|
|
4885
4901
|
* Extracted and exported because it could not be tested otherwise: it sat inside the async function
|
|
4886
4902
|
* that also does the batching and makes the model calls, so exercising it meant paying for a run.
|
|
4887
4903
|
*/
|
|
4904
|
+
/** A ROLE THAT DOES NOT OUTLIVE THE TICKET IS A BLOCKING FINDING (operator, 2026-10-24): the review answers for every minted role
|
|
4905
|
+
* (TOOL_ROSTER_REVIEW.roles); one it marks outlivesTicket:false — named or briefed for the ticket in scope rather than the codeline —
|
|
4906
|
+
* is turned into the finding the mint's correction loop acts on. The reviewer's own words are the claim. */
|
|
4907
|
+
function rolesOutliveTicketFindings(part) {
|
|
4908
|
+
const roles = part && Array.isArray(part.roles) ? part.roles : [];
|
|
4909
|
+
return roles.filter((r) => r && r.name && r.outlivesTicket === false).map((r) => ({
|
|
4910
|
+
agent: String(r.name), severity: 'blocking', claim: String(r.why || '(the reviewer gave no words)'),
|
|
4911
|
+
checked: 'whether this role, as named and briefed, would serve a story on its codeline about something other than the current ticket',
|
|
4912
|
+
found: 'minted for the ticket in scope, not for the codeline it is kept with',
|
|
4913
|
+
remedy: 'a role named for its kind of work and its codeline, briefed on the codeline — its stack, conventions and how to verify there — naming the current ticket only as a marked example',
|
|
4914
|
+
}));
|
|
4915
|
+
}
|
|
4916
|
+
|
|
4888
4917
|
function aggregateRosterReview(results, legalVerdicts) {
|
|
4889
4918
|
const legal = Array.isArray(legalVerdicts) ? legalVerdicts : [];
|
|
4890
4919
|
const rows = Array.isArray(results) ? results : [];
|
|
@@ -4892,7 +4921,9 @@ function aggregateRosterReview(results, legalVerdicts) {
|
|
|
4892
4921
|
const unexamined = rows.filter((r) => !r || !r.part || typeof r.part !== 'object'
|
|
4893
4922
|
|| r.part.verdict === 'nothing_to_review' || !r.part.verdict || illegal(r.part.verdict));
|
|
4894
4923
|
const examined = rows.filter((r) => !unexamined.includes(r));
|
|
4895
|
-
|
|
4924
|
+
// a role an examined batch says does not outlive the ticket is a finding of that batch, whatever verdict it gave
|
|
4925
|
+
const roleFindings = examined.flatMap((r) => rolesOutliveTicketFindings(r.part));
|
|
4926
|
+
const findings = rows.flatMap((r) => (r && r.part && Array.isArray(r.part.findings) ? r.part.findings : [])).concat(roleFindings);
|
|
4896
4927
|
|
|
4897
4928
|
if (!examined.length) {
|
|
4898
4929
|
return {
|
|
@@ -4903,7 +4934,7 @@ function aggregateRosterReview(results, legalVerdicts) {
|
|
|
4903
4934
|
};
|
|
4904
4935
|
}
|
|
4905
4936
|
|
|
4906
|
-
const verdict = examined.some((r) => r.part.verdict === 'defects_found') ? 'defects_found' : 'sound';
|
|
4937
|
+
const verdict = (examined.some((r) => r.part.verdict === 'defects_found') || roleFindings.length) ? 'defects_found' : 'sound';
|
|
4907
4938
|
return {
|
|
4908
4939
|
verdict,
|
|
4909
4940
|
findings,
|
|
@@ -11107,7 +11138,7 @@ module.exports = {
|
|
|
11107
11138
|
storyAcsBlock,
|
|
11108
11139
|
specAgentContract,
|
|
11109
11140
|
rosterReviewVerdict,
|
|
11110
|
-
aggregateRosterReview,
|
|
11141
|
+
aggregateRosterReview, rolesOutliveTicketFindings,
|
|
11111
11142
|
reviewOutcomeKeepsChange,
|
|
11112
11143
|
// Exported so the brief lookup can be asserted without a run.
|
|
11113
11144
|
profilesWithProjectBriefs,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "amsd-pipeline-shared",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.39",
|
|
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": {
|