ag08-selfcheck.
js
/**
* AG-08 Cost of Sales & Inventory self-check.
*
* Usage:
* node scripts/[Link] auto
*
* Verifies:
* 1) AG-08 is registered in the agent registry.
* 2) TB fetch returns only COS/inventory-category accounts
(filterAccountsForSection).
* 3) AG-03 PLANNING procedures for the COS & Inventory section are
loaded into context.
* 4) findings[] non-empty when section balances exist (fixture path in
dry-run).
* 5) [Link] emitted in eventsEmitted when all plan procedures
resolved.
* 6) Output envelope validates against AgentJobOutput Zod schema.
* 7) AGENTS_DRY_RUN=true returns a usable envelope without an upstream
call.
*/
const crypto = require('crypto');
const { PrismaClient, ProcedureType, ProcedureStatus } =
require('@prisma/client');
/** Mirrors SECTION_DEFINITIONS['cos-inventory'].keywords in
[Link] */
const COS_INVENTORY_KEYWORDS = [
'cost of sales',
'cogs',
'inventory',
'stock',
'purchases',
'opening stock',
'closing stock',
'direct cost',
'material',
'wip',
'work in progress',
'finished good',
];
async function main() {
[Link].AGENTS_ENABLED = [Link].AGENTS_ENABLED || 'true';
[Link].AGENTS_DRY_RUN = [Link].AGENTS_DRY_RUN || 'true';
const prisma = new PrismaClient();
const cleanup = { jobId: null, planningId: null, fakeAccountIds: [],
findingIds: [] };
try {
const arg = [Link][2];
let engagementId = arg && arg !== 'auto' ? arg : null;
if (!engagementId) {
const cycle = await [Link]({
where: { trialBalances: { some: { role: 'CURRENT' } } },
select: { engagementId: true },
});
if (!cycle?.engagementId) throw new Error('No engagement with
CURRENT TB found');
engagementId = [Link];
}
const cycle = await [Link]({
where: { engagementId },
select: {
id: true,
trialBalances: {
where: { role: 'CURRENT' },
orderBy: [{ year: 'desc' }, { version: 'desc' }, { createdAt:
'desc' }],
take: 1,
select: { id: true, accounts: { select: { id: true, accountName:
true } } },
},
},
});
const currentTbId = cycle?.trialBalances?.[0]?.id;
if (currentTbId) {
const codeBase = `AG08-${[Link]()}`;
const created = await prisma.$transaction([
[Link]({
data: {
trialBalanceId: currentTbId,
code: `${codeBase}-1`,
accountName: 'Cost of Sales - Raw Materials',
accountType: 'EXPENSE',
normalBalance: 'DEBIT',
amount: 620000,
},
select: { id: true },
}),
[Link]({
data: {
trialBalanceId: currentTbId,
code: `${codeBase}-2`,
accountName: 'Closing Stock',
accountType: 'ASSET',
normalBalance: 'DEBIT',
amount: 215000,
},
select: { id: true },
}),
[Link]({
data: {
trialBalanceId: currentTbId,
code: `${codeBase}-3`,
accountName: 'Purchases',
accountType: 'EXPENSE',
normalBalance: 'DEBIT',
amount: 410000,
},
select: { id: true },
}),
]);
[Link] = [Link]((c) => [Link]);
}
const planning = await [Link]({
data: {
auditCycleId: [Link],
type: [Link],
materialityValue: 5000,
status: ProcedureStatus.IN_PROGRESS,
documentPayload: {
generatedBy: 'AG-08-SELFCHECK',
materialityThreshold: 5000,
procedures: [
{
ref: 'CINV-STK-1',
section: 'Cost of Sales & Inventory',
description: 'Stock count agreement to TB',
riskBasis: 'Existence and completeness of inventory',
mandatory: true,
signedOff: false,
},
{
ref: 'CINV-NRV-1',
section: 'Cost of Sales & Inventory',
description: 'Inventory valuation lower of cost or NRV',
riskBasis: 'Inventory valuation risk',
mandatory: true,
signedOff: false,
},
],
},
},
select: { id: true },
});
[Link] = [Link];
const { bootstrapAgentRegistry } =
require('../dist/modules/agents/registry/bootstrap');
const { getAgentHandler } =
require('../dist/modules/agents/registry/agent-registry');
const { agentJobOutputSchema } =
require('../dist/modules/agents/contracts/envelope');
const { loadFieldworkContext } =
require('../dist/modules/agents/fieldwork/[Link]');
bootstrapAgentRegistry();
const ag08 = getAgentHandler('AG-08');
if (!ag08) throw new Error('AG-08 handler not in registry');
const ctx = await loadFieldworkContext(engagementId, 'cos-inventory');
if (!ctx) throw new Error('fieldwork context missing');
const ids = [Link]((a) => [Link]);
const fullRows = await [Link]({
where: { id: { in: ids } },
select: { accountName: true, group1: true, group2: true, group3:
true },
});
const offenders = [Link]((a) => {
const haystack = [[Link], a.group1, a.group2, a.group3]
.filter(Boolean)
.join(' ')
.toLowerCase();
return !COS_INVENTORY_KEYWORDS.some((kw) => [Link](kw));
});
if ([Link] > 0) {
throw new Error(
'TB filter leaked non-COS/inventory accounts: ' +
[Link]([Link]((a) => [Link]))
);
}
if ([Link] < 2) {
throw new Error(
'AG-03 plan procedures not loaded into context (got ' +
[Link] + ')'
);
}
const jobId = [Link]();
[Link] = jobId;
const input = {
jobId,
agentId: 'AG-08',
engagementId,
triggeredBy: 'selfcheck',
event: {
eventId: [Link](),
eventType: '[Link]',
timestamp: new Date().toISOString(),
payload: { section: 'cos-inventory' },
},
context: {},
};
await [Link]({
data: {
jobId,
engagementId,
agentId: 'AG-08',
status: 'in_progress',
inputEnvelope: input,
},
});
const output = await ag08(input);
const v = [Link](output);
if (![Link]) throw new Error('Envelope invalid: ' +
[Link]([Link]));
if ([Link] !== 'Cost of Sales & Inventory') {
throw new Error('section label mismatch: ' + [Link]);
}
if ([Link] === 0) {
throw new Error('findings[] is empty');
}
if ([Link]((f) => !['info', 'low', 'medium', 'high',
'critical'].includes([Link]))) {
throw new Error('finding severity invalid');
}
const sectionCompleteEvents = [Link]((e) =>
[Link] === '[Link]');
const allResolved =
[Link] + [Link]
>= [Link];
if (allResolved && [Link] === 0) {
throw new Error(
'all procedures resolved but [Link] not emitted: ' +
[Link]({ proc: [Link], blocked:
[Link] })
);
}
const findingRows = await [Link]({
where: { jobId },
select: { id: true, section: true, agentId: true },
});
[Link] = [Link]((f) => [Link]);
if ([Link] === 0) throw new Error('No AgentFinding rows
persisted');
if ([Link]((f) => [Link] !== 'cos-inventory')) {
throw new Error('[Link] not normalised to
cos-inventory');
}
[Link]('AG-08 self-check passed');
[Link](
[Link](
{
status: [Link],
section: [Link],
findings: [Link],
proceduresCompleted: [Link],
proceduresBlocked: [Link],
eventsEmitted: [Link]((e) => [Link]),
modelUsed: [Link],
providerUsed: [Link],
},
null,
2
)
);
} finally {
if ([Link]) {
await [Link]({ where: { id: { in:
[Link] } } }).catch(() => {});
}
if ([Link]) {
await [Link]({ where: { jobId: [Link] }
}).catch(() => {});
}
if ([Link]) {
await [Link]({ where: { id: [Link] }
}).catch(() => {});
}
if ([Link]) {
await [Link]
.deleteMany({ where: { id: { in: [Link] } } })
.catch(() => {});
}
await prisma.$disconnect();
}
}
main().catch((err) => {
[Link]('AG-08 self-check FAILED:', [Link] || String(err));
[Link](1);
});
[Link]
/**
* AG-11 Fixed Assets (PPE) self-check.
*
* Usage:
* node scripts/[Link] auto
*
* Verifies:
* 1) AG-11 is registered in the agent registry.
* 2) TB fetch returns only fixed-assets-category accounts
(filterAccountsForSection).
* 3) AG-03 PLANNING procedures for the Fixed Assets section are loaded
into context.
* 4) findings[] non-empty when section balances exist (fixture path in
dry-run).
* 5) [Link] emitted in eventsEmitted when all plan procedures
resolved.
* 6) Output envelope validates against AgentJobOutput Zod schema.
* 7) AGENTS_DRY_RUN=true returns a usable envelope without an upstream
call.
*/
const crypto = require('crypto');
const { PrismaClient, ProcedureType, ProcedureStatus } =
require('@prisma/client');
/** Mirrors SECTION_DEFINITIONS['fixed-assets'].keywords in
[Link] */
const FIXED_ASSETS_KEYWORDS = [
'fixed asset',
'fixed assets',
'ppe',
'property',
'plant',
'equipment',
'depreciation',
'accumulated depreciation',
'additions',
'disposals',
'leasehold improvements',
];
async function main() {
[Link].AGENTS_ENABLED = [Link].AGENTS_ENABLED || 'true';
[Link].AGENTS_DRY_RUN = [Link].AGENTS_DRY_RUN || 'true';
const prisma = new PrismaClient();
const cleanup = { jobId: null, planningId: null, fakeAccountIds: [],
findingIds: [] };
try {
const arg = [Link][2];
let engagementId = arg && arg !== 'auto' ? arg : null;
if (!engagementId) {
const cycle = await [Link]({
where: { trialBalances: { some: { role: 'CURRENT' } } },
select: { engagementId: true },
});
if (!cycle?.engagementId) throw new Error('No engagement with
CURRENT TB found');
engagementId = [Link];
}
const cycle = await [Link]({
where: { engagementId },
select: {
id: true,
trialBalances: {
where: { role: 'CURRENT' },
orderBy: [{ year: 'desc' }, { version: 'desc' }, { createdAt:
'desc' }],
take: 1,
select: { id: true, accounts: { select: { id: true, accountName:
true } } },
},
},
});
const currentTbId = cycle?.trialBalances?.[0]?.id;
if (currentTbId) {
const codeBase = `AG11-${[Link]()}`;
const created = await prisma.$transaction([
[Link]({
data: {
trialBalanceId: currentTbId,
code: `${codeBase}-1`,
accountName: 'Fixed Assets - Plant and Machinery',
accountType: 'ASSET',
normalBalance: 'DEBIT',
amount: 980000,
},
select: { id: true },
}),
[Link]({
data: {
trialBalanceId: currentTbId,
code: `${codeBase}-2`,
accountName: 'Accumulated Depreciation',
accountType: 'ASSET',
normalBalance: 'CREDIT',
amount: -240000,
},
select: { id: true },
}),
[Link]({
data: {
trialBalanceId: currentTbId,
code: `${codeBase}-3`,
accountName: 'Leasehold Improvements',
accountType: 'ASSET',
normalBalance: 'DEBIT',
amount: 145000,
},
select: { id: true },
}),
]);
[Link] = [Link]((c) => [Link]);
}
const planning = await [Link]({
data: {
auditCycleId: [Link],
type: [Link],
materialityValue: 5000,
status: ProcedureStatus.IN_PROGRESS,
documentPayload: {
generatedBy: 'AG-11-SELFCHECK',
materialityThreshold: 5000,
procedures: [
{
ref: 'PPE-MOV-1',
section: 'Fixed Assets',
description: 'PPE movement schedule build and agree',
riskBasis: 'Completeness of additions/disposals',
mandatory: true,
signedOff: false,
},
{
ref: 'PPE-DEP-1',
section: 'Fixed Assets',
description: 'Depreciation recalculation for all classes',
riskBasis: 'Valuation through depreciation policy',
mandatory: true,
signedOff: false,
},
],
},
},
select: { id: true },
});
[Link] = [Link];
const { bootstrapAgentRegistry } =
require('../dist/modules/agents/registry/bootstrap');
const { getAgentHandler } =
require('../dist/modules/agents/registry/agent-registry');
const { agentJobOutputSchema } =
require('../dist/modules/agents/contracts/envelope');
const { loadFieldworkContext } =
require('../dist/modules/agents/fieldwork/[Link]');
bootstrapAgentRegistry();
const ag11 = getAgentHandler('AG-11');
if (!ag11) throw new Error('AG-11 handler not in registry');
const ctx = await loadFieldworkContext(engagementId, 'fixed-assets');
if (!ctx) throw new Error('fieldwork context missing');
const ids = [Link]((a) => [Link]);
const fullRows = await [Link]({
where: { id: { in: ids } },
select: { accountName: true, group1: true, group2: true, group3:
true },
});
const offenders = [Link]((a) => {
const haystack = [[Link], a.group1, a.group2, a.group3]
.filter(Boolean)
.join(' ')
.toLowerCase();
return !FIXED_ASSETS_KEYWORDS.some((kw) => [Link](kw));
});
if ([Link] > 0) {
throw new Error(
'TB filter leaked non-fixed-assets accounts: ' +
[Link]([Link]((a) => [Link]))
);
}
if ([Link] < 2) {
throw new Error(
'AG-03 plan procedures not loaded into context (got ' +
[Link] + ')'
);
}
const jobId = [Link]();
[Link] = jobId;
const input = {
jobId,
agentId: 'AG-11',
engagementId,
triggeredBy: 'selfcheck',
event: {
eventId: [Link](),
eventType: '[Link]',
timestamp: new Date().toISOString(),
payload: { section: 'fixed-assets' },
},
context: {},
};
await [Link]({
data: {
jobId,
engagementId,
agentId: 'AG-11',
status: 'in_progress',
inputEnvelope: input,
},
});
const output = await ag11(input);
const v = [Link](output);
if (![Link]) throw new Error('Envelope invalid: ' +
[Link]([Link]));
if ([Link] !== 'Fixed Assets') {
throw new Error('section label mismatch: ' + [Link]);
}
if ([Link] === 0) {
throw new Error('findings[] is empty');
}
if ([Link]((f) => !['info', 'low', 'medium', 'high',
'critical'].includes([Link]))) {
throw new Error('finding severity invalid');
}
const sectionCompleteEvents = [Link]((e) =>
[Link] === '[Link]');
const allResolved =
[Link] + [Link]
>= [Link];
if (allResolved && [Link] === 0) {
throw new Error(
'all procedures resolved but [Link] not emitted: ' +
[Link]({ proc: [Link], blocked:
[Link] })
);
}
const findingRows = await [Link]({
where: { jobId },
select: { id: true, section: true, agentId: true },
});
[Link] = [Link]((f) => [Link]);
if ([Link] === 0) throw new Error('No AgentFinding rows
persisted');
if ([Link]((f) => [Link] !== 'fixed-assets')) {
throw new Error('[Link] not normalised to
fixed-assets');
}
[Link]('AG-11 self-check passed');
[Link](
[Link](
{
status: [Link],
section: [Link],
findings: [Link],
proceduresCompleted: [Link],
proceduresBlocked: [Link],
eventsEmitted: [Link]((e) => [Link]),
modelUsed: [Link],
providerUsed: [Link],
},
null,
2
)
);
} finally {
if ([Link]) {
await [Link]({ where: { id: { in:
[Link] } } }).catch(() => {});
}
if ([Link]) {
await [Link]({ where: { jobId: [Link] }
}).catch(() => {});
}
if ([Link]) {
await [Link]({ where: { id: [Link] }
}).catch(() => {});
}
if ([Link]) {
await [Link]
.deleteMany({ where: { id: { in: [Link] } } })
.catch(() => {});
}
await prisma.$disconnect();
}
}
main().catch((err) => {
[Link]('AG-11 self-check FAILED:', [Link] || String(err));
[Link](1);
});