"use strict";
var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
var __values = (this && this.__values) || function(o) {
    var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
    if (m) return m.call(o);
    if (o && typeof o.length === "number") return {
        next: function () {
            if (o && i >= o.length) o = void 0;
            return { value: o && o[i++], done: !o };
        }
    };
    throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
var __read = (this && this.__read) || function (o, n) {
    var m = typeof Symbol === "function" && o[Symbol.iterator];
    if (!m) return o;
    var i = m.call(o), r, ar = [], e;
    try {
        while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
    }
    catch (error) { e = { error: error }; }
    finally {
        try {
            if (r && !r.done && (m = i["return"])) m.call(i);
        }
        finally { if (e) throw e.error; }
    }
    return ar;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
    if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
        if (ar || !(i in from)) {
            if (!ar) ar = Array.prototype.slice.call(from, 0, i);
            ar[i] = from[i];
        }
    }
    return to.concat(ar || Array.prototype.slice.call(from));
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.normalizeResolveIOQaPolicyOptions = normalizeResolveIOQaPolicyOptions;
exports.buildResolveIOQaPolicyRules = buildResolveIOQaPolicyRules;
exports.buildResolveIORunnerQaCoverageChecklist = buildResolveIORunnerQaCoverageChecklist;
exports.buildResolveIORunnerBasicsRules = buildResolveIORunnerBasicsRules;
exports.buildResolveIORunnerContract = buildResolveIORunnerContract;
exports.buildResolveIORunnerPromptLines = buildResolveIORunnerPromptLines;
exports.buildResolveIORunnerPromptBundle = buildResolveIORunnerPromptBundle;
exports.buildResolveIORunnerRepairPromptLines = buildResolveIORunnerRepairPromptLines;
exports.normalizeResolveIORunnerBlocker = normalizeResolveIORunnerBlocker;
exports.findRepeatedResolveIORunnerBlockers = findRepeatedResolveIORunnerBlockers;
exports.decideResolveIORunnerRepairContinuation = decideResolveIORunnerRepairContinuation;
exports.classifyResolveIORunnerBlocker = classifyResolveIORunnerBlocker;
exports.extractResolveIORunnerRepairLineHints = extractResolveIORunnerRepairLineHints;
exports.extractResolveIORunnerRepairTargetFiles = extractResolveIORunnerRepairTargetFiles;
exports.selectResolveIORunnerRepairTargetFiles = selectResolveIORunnerRepairTargetFiles;
exports.sanitizeResolveIORunnerRepairPlans = sanitizeResolveIORunnerRepairPlans;
exports.buildResolveIORunnerRepairPlans = buildResolveIORunnerRepairPlans;
function normalizeOptionalString(value) {
    return String(value || '').replace(/\s+/g, ' ').trim();
}
function normalizePositiveInteger(value, fallback, min, max) {
    var numeric = Number(value);
    if (!Number.isFinite(numeric)) {
        return fallback;
    }
    var rounded = Number(numeric.toFixed(0));
    return Math.max(min, Math.min(max, rounded));
}
function normalizeTextLine(value, maxChars) {
    return normalizeOptionalString(value).slice(0, maxChars).trim();
}
function normalizeTextList(values, limit, maxChars) {
    var e_1, _a;
    if (!Array.isArray(values)) {
        return [];
    }
    var result = [];
    try {
        for (var values_1 = __values(values), values_1_1 = values_1.next(); !values_1_1.done; values_1_1 = values_1.next()) {
            var value = values_1_1.value;
            var normalized = normalizeTextLine(value, maxChars);
            if (normalized && !result.includes(normalized)) {
                result.push(normalized);
            }
            if (result.length >= limit) {
                break;
            }
        }
    }
    catch (e_1_1) { e_1 = { error: e_1_1 }; }
    finally {
        try {
            if (values_1_1 && !values_1_1.done && (_a = values_1.return)) _a.call(values_1);
        }
        finally { if (e_1) throw e_1.error; }
    }
    return result;
}
function normalizeResolveIOQaPolicyOptions(options) {
    if (options === void 0) { options = {}; }
    return {
        context: options.context || 'general',
        includeDevServerRules: options.includeDevServerRules === true,
        qaRepairEnabled: options.qaRepairEnabled !== false,
        qaEvidenceRequired: options.qaEvidenceRequired !== false,
        qaDistinctScreenshotRequired: options.qaDistinctScreenshotRequired !== false,
        qaFailFastCompile: options.qaFailFastCompile !== false,
        qaLiveDataRequired: options.qaLiveDataRequired !== false,
        qaSelfRepairMaxWaves: normalizePositiveInteger(options.qaSelfRepairMaxWaves, 3, 1, 6),
        currentRoute: normalizeOptionalString(options.currentRoute),
        currentContextMode: normalizeOptionalString(options.currentContextMode),
        customInstructions: Array.isArray(options.customInstructions)
            ? options.customInstructions.map(normalizeOptionalString).filter(Boolean).slice(0, 12)
            : []
    };
}
function buildResolveIOQaPolicyRules(options) {
    if (options === void 0) { options = {}; }
    var policy = normalizeResolveIOQaPolicyOptions(options);
    var rules = [];
    if (policy.includeDevServerRules) {
        rules.push('When browser/localhost QA needs long-running commands like `npm run server`, `npm run client`, `npm run dev`, `ng serve`, `vite`, or `nodemon`, start them as managed background processes with log files and PIDs; do not leave foreground dev-server commands as the active shell tool.', 'Before localhost/browser QA, source `.resolveio-support-tools/env.sh` or `.resolveio-ai-runner-tools/env.sh` when present. It supplies shared EC2 browser cache settings, `PUPPETEER_EXECUTABLE_PATH`/`CHROME_BIN`, Mongo wrappers, and non-conflicting localhost QA ports/URLs.', 'For ResolveIO app login during browser QA, use the shared AI-runner auth bootstrap when staged: `node ./.resolveio-support-tools/qa-auth-bootstrap.js <project-root> /target-route`, `node ./.resolveio-ai-runner-tools/qa-auth-bootstrap.js <project-root> /target-route`, or the same command from an app root with `../`. It must use the exact localhost client origin, log out/clear stale browser credentials first, call `/login` then `/accessToken`, seed auth storage, repair the local QA user settings/tour flags if the app forces the post-login settings/tour gate, verify the browser reached the requested target route, and emit `qa-artifacts/auth-bootstrap-result.json`, `qa-artifacts/auth-bootstrap-storage-state.json`, plus a screenshot. For support-ticket QA, use Puppeteer first when `PUPPETEER_EXECUTABLE_PATH` or `CHROME_BIN` is set; `PLAYWRIGHT_MISSING` is not a blocker while that Puppeteer env exists. For every fresh Puppeteer/Playwright page, open the localhost origin, set localStorage from `auth-bootstrap-storage-state.json`, then navigate to the target route. The storage artifact may expose top-level object `localStorage`, array `localStorageEntries`, or Playwright-style `origins[].localStorage`; normalize all three shapes before setting storage (`Object.entries` for objects, `{key,value}` or `{name,value}` for arrays). Never run `for...of` directly on top-level `localStorage` unless it is already an array. A login-shell screenshot after bootstrap means the QA script failed to seed auth and must rerun the same row with storage seeded before returning needs-fix.', 'For support-ticket QA, run the browser as the ticket reporter whenever possible; if the ticket or latest customer response names another affected user, run as that affected user instead. Use `qa-live-data-seed-result.json.selected.qa_user_context` and `auth-bootstrap-result.json.user` to record the chosen user. Generic admin/dev QA is acceptable only when no reporter/affected user can be identified or copied into localhost QA; in that case the matrix must say why.', 'For ResolveIO browser checks, do not use Puppeteer/Playwright `networkidle0` or `networkidle2` as the page-ready condition; ResolveIO pages can keep background API/socket/polling activity open. Navigate with `domcontentloaded`, then wait for concrete route/workflow DOM text, buttons, table rows, dialogs, saved records, or persisted data assertions before screenshots.', 'Use browser API compatibility helpers instead of version-fragile calls: every row-level Puppeteer script must declare `const delay = ms => new Promise(resolve => setTimeout(resolve, ms));` before navigation and use `await delay(...)` for fixed waits. Do not use `page.$x`, `page.waitForTimeout`, `networkidle0`, or `networkidle2`. Use `page.evaluateHandle`/DOM traversal or Playwright `locator` when definitely using Playwright. If a browser helper call throws because the current runtime lacks that API, fix the QA script and rerun the same matrix row before marking it failed.', 'Browser click targeting must prefer exact interactive controls: `button`, `a[href]`, `[role="button"]`, `input[type="button"]`, `input[type="submit"]`, `select`, option/combobox controls, and app-specific clickable elements with a small visible bounding box. Do not include broad `div`, `span`, `body`, or `*` elements in click-by-text helpers; they often match whole-page containers and produce false progress. If a text match has a huge bounding box or contains unrelated page/navigation text, skip it and find a smaller descendant/control.', 'For QA row probes, use broad DOM text scans only for read-only diagnostics. Do not drive workflow clicks from broad `document.querySelectorAll("*")` or generic container matches. After at most two focused selector attempts on the seeded route/data, either capture the blocker screenshot and return `needs-fix`, or switch to persisted data assertions if the row can be proven without another UI click.', 'When launching Puppeteer on workers, pass `executablePath: process.env.PUPPETEER_EXECUTABLE_PATH || process.env.CHROME_BIN` if either env var is set. If either env var points to an executable, do not run `npx puppeteer browsers install`, `puppeteer browsers install`, Playwright install, or any browser download. Do not connect to `localhost:9223`, `/json/version`, or any Chrome remote-debug endpoint unless `RESOLVEIO_SUPPORT_QA_BROWSER_URL` or `RESOLVEIO_RUNNER_QA_BROWSER_URL` is explicitly set after sourcing the staged env and the endpoint responds; otherwise launch a scoped Puppeteer browser from the staged executable. If Playwright is missing but Puppeteer env exists, continue with Puppeteer instead of returning `PLAYWRIGHT_MISSING`. If the staged browser is missing or not executable, return one precise dependency blocker instead of downloading inside the QA owner turn.', 'Do not scan broad roots such as `/var/app/resolveio-ai-workspace`, `/tmp/resolveio-support-qa`, or `/var/lib/resolveio` to rediscover Puppeteer, Playwright, or Chromium. Source the staged env file and use its `PUPPETEER_EXECUTABLE_PATH`/`CHROME_BIN`; if the staged browser/runtime is missing, return a precise dependency blocker.', 'When the current directory is an app/project root, shared QA tools may be staged one directory up. Prefer `../.resolveio-support-tools/env.sh` or `../.resolveio-ai-runner-tools/env.sh` before writing custom browser code. Do not use bare `require("puppeteer")` from an app root until checking the project/server node_modules or the staged helper pattern.', 'Secret handling: never print, cat, paste, or summarize `.env`, `.env.runtime`, `.env.codex`, `settings.json`, `.mongo-runtime.json`, Mongo URLs, API keys, tokens, or passwords in command output, QA artifacts, screenshots, captions, or final notes. Source staged env files or read only the named QA artifacts; redact connection strings if a tool emits one.', 'For targeted QA row repair, read `qa-artifacts/qa-live-data-seed-result.json`, `qa-artifacts/auth-bootstrap-result.json`, `qa-artifacts/auth-bootstrap-storage-state.json`, and `qa-artifacts/qa-workflow-probe-result.json` before writing browser probes. Use seeded `selected` ids/names directly; do not guess customer filters, invoice numbers, or dropdown options when the seed artifact already provides the exact QA fixture. After route navigation, wait for concrete route/workflow DOM text or controls for up to the row timeout before calling a page shell-only; a 1-2 second fixed delay is not enough evidence that a ResolveIO route failed to hydrate.', 'When the live seed artifact contains `selected.truck_treating_bol_context`, use the seeded ids/statuses directly instead of guessing customer data. If `primary_bol_status` or `bol_statuses[]` says Delivered, the direct `browser_routes.delivery` URL is an action route that may correctly redirect with `BOL has already been delivered`; do not treat that alone as an application defect. For delivered BOLs, test the delivered Open File/detail/Deliveries evidence path, or create the smallest localhost-only deliverable fixture from the fetched live BOL/route/delivery/treatment-plan context and record the fixture ids in the matrix. If `route_hint_matched === false`, the source database disproved the ticket route-name hint; use the seeded BOL-linked `bol_ids`, `route_ids`, `truck_treating_route_ids`, `linked_truck_treating_routes`, and usable browser route/fixture as the QA target, record the route-name mismatch in the row caption/assertion, and do not block only because the original route label is not visible.', 'QA owner source-code boundary: browser QA may write only QA artifacts, screenshots, traces, captions, coverage matrices, temporary row probe scripts, and localhost-only fixture data. Do not edit application source files, generated wrappers, package files, migrations, or tests from the QA lane. If QA proves a code/data/publication defect, return `needs-fix` with the exact matrix row, screenshot/log/data evidence, suspected files, and smallest repair hint so the build lane can fix it.', 'For Billing Dashboard QA rows, use seeded `qa_billing_fixture.customerId`, `psoId`, `deliveryId`, `invoiceId`, and `itemId` to choose/filter/open the exact row. If the page hides seeded rows behind filters, the QA row script should select by the seeded customer/id or return a data-seed/filter blocker with a screenshot instead of cycling through generic dropdown options.', 'For invoice edit, saved invoice, and inventory side-effect QA rows, prefer direct navigation to `/invoice/edit/${qa_billing_fixture.invoiceId}` or open invoice detail and click the explicit Edit control. Do not use Billing Dashboard or invoice-list `Open Invoice` as proof of the edit workflow; in ResolveIO that action can open/generated-preview invoice output instead of the edit component. If direct edit route redirects to a list/shell, return one precise route/data blocker with screenshot instead of retrying the same Open Invoice path.', 'When updating `qa-artifacts/qa-coverage-matrix.json`, verify the target row index still matches the active workflow before writing. If the row at that index has a different workflow, locate the row by exact workflow text; if multiple rows share a workflow, update only the row whose route/assertion matches the active row. Never overwrite an unrelated passing row or create duplicate workflow rows to work around a cursor mismatch.', 'Use the managed-server pattern for localhost QA: `command > .build-output/<name>.log 2>&1 & PID=$!; trap "kill $PID 2>/dev/null || true" EXIT; wait for the port with curl; run browser checks; then kill/wait the PID`. Prefer `npm run client` or `./start_client.sh`; those scripts honor `RESOLVEIO_SUPPORT_QA_CLIENT_PORT` and `PORT`. Never run `ng serve ... | tee ...` or another dev server as a foreground command.');
        if (policy.context === 'support_ticket') {
            rules.push('For support-ticket QA validation, the manager normally runs compile/startup preflight and keeps the local harness alive before the QA owner starts. In that mode, the QA owner must not run `run-local-qa.sh`, `npm run server`, `npm run client`, `ng serve`, `mongod`, `gulp`, or compile/build commands again; probe the existing localhost URLs and proceed to auth/browser proof.', 'If the preflighted support-ticket harness is not reachable, return a precise blocked/needs-fix result with the probed URL, HTTP/socket error, and qa-artifacts log paths. Do not start a duplicate server, duplicate client, duplicate Mongo, or duplicate compile from inside the browser QA owner.');
        }
    }
    if (policy.qaFailFastCompile) {
        rules.push('Before browser QA, run the fastest compile/type/startup checks that can prove the app can load. Fix compile/startup failures before launching browser QA.');
    }
    if (policy.qaRepairEnabled) {
        rules.push("If compile, startup, browser, or live-data QA fails, run a targeted repair wave for the exact failing route/action/data state, then rerun that same failed step before continuing. Limit self-repair to ".concat(policy.qaSelfRepairMaxWaves, " focused waves before returning the precise blocker."));
        rules.push('QA findings are implementation blockers, not manual TODOs: when QA proves missing fields, wrong publication payloads, failed persistence, bad calculations, missing side effects, or incomplete workflow coverage, return a typed needs-fix blocker so the runner starts a focused repair wave and reruns the same QA coverage.');
    }
    if (policy.qaLiveDataRequired) {
        rules.push('For bug fixes and data/publication changes, test against available live app data or a faithful seeded record; do not rely only on static inspection when the user reported a runtime workflow problem.');
        rules.push('Local QA may create, update, or delete representative seed records only in the localhost QA Mongo/database started for the run. Production/live customer databases are read-only for QA unless explicit human approval is provided.');
        rules.push('If the localhost QA database has no records for the workflow under test, seed the smallest faithful record set needed to exercise the customer action and identify the seeded fixture IDs/names in the QA Coverage Matrix. Do not return blocked only because local QA data is empty.');
        rules.push('When a ticket or customer response names concrete entities such as users, units, assets, BOLs, invoices, chemicals, yards, customers, routes, or order numbers, live-data seeding must fetch those exact production records into localhost QA where possible. QA must prove every named entity or return a seed/query blocker; representative substitute records are not pass evidence for named-record bug reports.');
        rules.push('For import/export/form-submit/data workflows, QA must drive the actual customer action with representative data: capture the relevant starting state, the dialog/form/file selection or action state, and the submitted/resulting state with a row/count/value assertion that proves the bug or feature works.');
        rules.push('For file upload/import QA, write a checkpoint artifact before launch, after route load, after file selection/upload, after parsing, after clicking the import/submit action, and after the final result. If the browser page/frame/process dies during file selection or parse, mark the row failed with that exact upload-stage blocker; do not silently retry as a pass or count route-load screenshots as proof.');
        rules.push('A navigation-only screenshot of an empty page, shell, table header, or unchanged screen is not sufficient evidence for data workflow fixes. If the page has no records, seed or choose a faithful test record and identify the record or fixture used.');
        rules.push('For pricing import/upload tickets, validator scripts are not enough. Browser QA must use the Manage Pricing import UI with both blank and pre-populated templates when the ticket mentions both, click the import action, and prove persisted pricing row/count/value changes in localhost QA Mongo.');
        rules.push('For pricing import/upload tickets, expand the exact visible Ready accordion/control, then click the small enabled `Import Production Prices` button or equivalent submit control. Do not click broad page containers, nav/sidebar text, or generic div/span text matches. Do not treat static headings like `Production Prices With Errors`, `Ready For Import`, or unchanged table text as success or blocker evidence; wait for a real result dialog/message, button disabled/enabled state change, page error, or persisted Mongo row/count/value change.');
        rules.push('For asset location/current-yard rename tickets, browser QA must prove the exact asset/unit on list, detail, and edit/save screens, and must include a joined/canonical yard record assertion showing the new yard name is used and the stale old yard name is absent.');
        rules.push('For asset location/current-yard rename tickets that name multiple assets or units, QA must prove every named asset/unit, not one representative row. Captions/data assertions must name each requested unit number, its canonical joined yard, and the absence of each stale yard name before the row can pass.');
        rules.push('For Update Interchangeables or Mass Update chemical tickets, browser QA must select the real source and target chemicals, run the update action, and assert before/after treatment-plan/tank document counts or ids in localhost QA Mongo. Route load, visible controls, or selected dropdowns alone are not pass evidence.');
    }
    rules.push('Before passing QA, create a QA Coverage Matrix from the approved scope, changed files, generated/publication changes, and touched collections/models. Each matrix row must name the workflow, route/screen, data used, assertion, screenshot/trace artifact, and pass/fail result.');
    rules.push('When updating `qa-artifacts/qa-coverage-matrix.json`, support both matrix schemas: the file may be an array or an object with a `rows` array. Use `const rows = Array.isArray(matrix) ? matrix : matrix.rows` for row updates and preserve the original schema when writing it back. Never skip row updates because only `Array.isArray(matrix)` is false.');
    rules.push('When a QA Coverage Matrix row is marked `pass`, remove stale negative fields from that row before writing it: `blocker`, `failure`, `error`, `notes`, `next_actions`, `failed_reason`, and `blocked_reason`. Passed rows must not retain old blocker text from earlier retries.');
    rules.push('QA must cover the full suite of changed customer-facing and data behavior, not only one smoke path. If implementation touches create/edit/delete/reopen flows, each touched flow needs proof or an explicit ticket-backed not-applicable note.');
    rules.push('If the change touches invoices, billing, taxes, inventory, pricing, surcharges, imports/exports, reports, or publications, QA must include persisted data assertions and calculation/side-effect checks for every touched domain before returning pass.');
    rules.push('For invoice/billing/tax/inventory/surcharge work, the minimum QA Coverage Matrix must include service/misc item surcharge configuration, customer override/default surcharge precedence, invoice create/new with added line items, surcharge add/remove/default/override selection, taxable and non-taxable subtotal/tax/total assertions, saved invoice detail/list state, chemical inventory item handling, and persisted inventory transaction/location/quantity/value side effects. Missing any row is needs-fix, not pass.');
    rules.push('After localhost startup/auth succeeds, immediately drive the target customer workflow in the browser. Do not spend an open-ended reasoning pass after auth; create fresh feature screenshots/captions plus persisted row/count/value assertions, or return needs-fix with the exact blocker.');
    rules.push('After startup/auth succeeds, missing selectors, dropdowns, options, saved values, rows, disabled/enabled states, or customer workflow controls are product/data QA failures. Mark the matrix row failed and return `needs-fix` with the exact row blocker and artifact paths; reserve `blocked` for true external/manual blockers such as auth, startup, infrastructure, credentials, or unavailable third-party systems.');
    rules.push('Once any QA Coverage Matrix row is marked in_progress, finish that row promptly by marking it pass, failed, or blocked with screenshot/caption/assertion evidence. Leaving in_progress rows without workflow artifacts is a QA failure and should trigger a targeted repair wave.');
    rules.push('Use desktop screenshots at a wide/full-screen viewport by default: 1920x1080 or wider. Do not use narrow/tablet/mobile screenshots unless the approved ticket is specifically mobile/responsive.');
    rules.push('For desktop QA, verify the top navigation is in its normal desktop state and not wrapped, collapsed, open, or covering the workflow. For mobile-specific QA, explicitly use a mobile viewport and close the mobile menu unless the menu behavior itself is being proven.');
    rules.push('Before every screenshot, settle the ResolveIO shell: press Escape, blur active controls, move the mouse away from the top/side nav, wait at least 750ms, and verify the target row/control/value has a visible bounding box inside the viewport. If the target text exists in DOM but is covered by the menu, sidebar, header, or a dark overlay, close the overlay or adjust the QA user/menu setting and recapture; do not count the covered screenshot as proof.');
    rules.push('For table/list evidence, a pass screenshot must show the actual target row cells and the changed value in the same frame. Header-only, pagination-only, covered-row, or DOM-only proof can diagnose a failure, but cannot be used as customer-facing pass evidence.');
    rules.push('For select/dropdown/filter workflows, a pass screenshot must show the relevant control with a real non-placeholder selected value, an open dropdown with the specific live option used, or a resulting data row/action state caused by that selection. Screenshots where required controls still show only placeholders such as Select Chemical, Select Customer, Select Yard, or Select Treatment Plan Type are empty-state evidence and must be failed or recaptured before pass.');
    rules.push('A matrix shortcut may only pass after all row-specific evidence gates pass. If any row was rejected for shallow proof, missing selected values, missing persisted data, or stale/contradictory matrix data, keep the row failed and trigger a targeted repair/retest instead of marking the matrix complete.');
    rules.push('Route/screen screenshots are valid only when they show the specific workflow being tested. If a route redirects to a generic shell, default manage page, menu-only view, auth screen, or a different feature screen, mark that matrix row failed/blocked with the mismatch; never count that screenshot as pass evidence.');
    if (policy.qaDistinctScreenshotRequired) {
        rules.push('Capture one screenshot or trace for each distinct changed customer-facing feature, screen, workflow state, or data result. Do not repeat equivalent screenshots for multiple records unless record-specific behavior changed.');
    }
    rules.push('Every screenshot artifact must include a short customer-facing caption explaining what the screenshot proves. Captions should describe the workflow state, such as Before, Ready to import, Submitted result, or Mobile menu closed.');
    if (policy.qaEvidenceRequired) {
        rules.push('Final notes must list the exact QA command, route, account/data used, screenshot/trace/log paths, and result for each changed behavior; if browser QA is not applicable, say why and provide the compile/data proof used instead.');
    }
    if (policy.currentRoute) {
        rules.push("Current app context route from the AI terminal is ".concat(policy.currentRoute).concat(policy.currentContextMode ? " (".concat(policy.currentContextMode, ")") : '', "; start QA there when the request refers to this page or current screen."));
    }
    rules.push.apply(rules, __spreadArray([], __read(policy.customInstructions), false));
    return rules;
}
function buildResolveIORunnerQaCoverageChecklist(input) {
    if (input === void 0) { input = {}; }
    var text = "".concat(input.ticketText || '', "\n").concat((input.changedFiles || []).join('\n'));
    var rules = [
        'Build and include a QA Coverage Matrix: changed workflow, route/screen, data fixture/live record, before/action/after assertion, screenshot/trace artifact, caption, and result.',
        'Fail QA as needs-fix when coverage only proves navigation, headers, empty tables, or UI controls without exercising the changed behavior and persisted result.'
    ];
    if (/\b(invoice|billing|line item|surcharge|price|pricing|tax|sales tax)\b|(?:^|\/)(?:invoice|pricing|sales-tax|customer|item)(?:\/|-)/i.test(text)) {
        rules.push('Invoice/billing/tax coverage: test create/new and edit/reopen where touched; verify line-item persistence, surcharge add/remove/default/override selection, subtotal/tax/total calculations, taxable vs non-taxable behavior, and the saved invoice detail/list state.');
        rules.push('When invoice/billing/tax QA has no usable local records, seed a minimal localhost-only customer, job/order/delivery or treatment, taxable item, non-taxable/surcharge item, and inventory/location data needed to create and save the invoice workflow; record the fixture IDs/names and do not touch production data.');
        rules.push('For Billing Dashboard invoice QA, do not hardcode one accordion bucket such as Processing. Read the live bucket labels and counts from the page/probe, choose the relevant non-empty invoice bucket for the row (for example PSO Type Invoice Awaiting Invoices, Prepared, Processing, or Open Invoices), expand it, then use the visible workflow control or invoice row. A selector is blocked only when no relevant non-empty billing bucket or invoice control exists after waiting for async data.');
        rules.push('For invoice edit/reopen/inventory side-effect QA, use the seeded `qa_billing_fixture.invoiceId` on `/invoice/edit/<invoiceId>` or the invoice detail Edit control. Do not click `Open Invoice` to prove editing because that control can open invoice output/preview instead of the edit workflow.');
        rules.push('Invoice/billing/tax coverage must include at least one concrete row/value assertion from the saved document or UI after submit, not only pre-submit form screenshots.');
    }
    if (/\b(inventory|warehouse|stock|fifo|pick ticket|checkout|check out|transaction)\b|(?:^|\/)(?:inventory|part|chemical|production-location|yard)(?:\/|-)/i.test(text)) {
        rules.push('Inventory coverage: test the relevant source/destination location, transaction creation/reversal, FIFO or location selection when applicable, report/pick-ticket output when touched, and persisted inventory quantities/values after save/edit/delete.');
        rules.push('When inventory QA has no usable local records, seed the smallest localhost-only item/location/quantity/value fixture needed to prove quantity/value movement and identify that fixture in the evidence.');
    }
    if (/\b(report|export|csv|excel|xlsx|download|filter|total|grouping)\b|(?:^|\/)report(?:\/|-)/i.test(text)) {
        rules.push('Report/export coverage: verify rows, filters/date ranges, totals/grouping, download/export output, and at least one row/count/value assertion.');
    }
    if (/\b(publication|methods?\.ts|publications?\.ts|subscription|publish|payload|field projection)\b|(?:^|\/)server\/src\/publications\//i.test(text)) {
        rules.push('Publication/API coverage: verify the changed fields are returned to the UI or method caller that needs them, including list/detail projections and any generated wrapper/call-site behavior.');
    }
    if (/\b(import|upload|file|spreadsheet|template)\b/i.test(text)) {
        rules.push('Import/upload coverage: use a representative file/template, capture ready-to-upload and submitted states, and assert inserted/updated/skipped row counts plus visible result rows.');
    }
    return Array.from(new Set(rules));
}
function buildResolveIORunnerBasicsRules(options) {
    if (options === void 0) { options = {}; }
    return buildResolveIORunnerContract(options).rules;
}
function buildResolveIORunnerContract(options) {
    var _a;
    if (options === void 0) { options = {}; }
    var maxContextBullets = normalizePositiveInteger(options.maxContextBullets, 8, 3, 20);
    var maxRepairWaves = normalizePositiveInteger((_a = options.maxRepairWaves) !== null && _a !== void 0 ? _a : options.qaSelfRepairMaxWaves, 3, 1, 6);
    var context = options.context || 'general';
    var runnerBasics = [
        'Use repo-local patterns first: read the closest existing implementation, matching tests, model/schema, method/publication, and UI route before editing.',
        'Make the smallest complete change that satisfies the request; avoid broad refactors, config churn, dependency changes, and generated-file edits unless the workflow explicitly requires regeneration.',
        'Before returning, state what changed, how it was verified, remaining blockers, and exact artifact paths in final notes.'
    ];
    var tokenDiscipline = options.includeTokenDiscipline !== false
        ? [
            "Keep context lean: summarize prior history into at most ".concat(maxContextBullets, " bullets, retrieve specific files on demand, and do not paste full logs, lockfiles, generated files, or stale ticket/email chains unless they are the current blocker evidence."),
            'Prefer targeted search/read commands over loading broad directories. If a command returns noisy output, summarize the useful lines and continue with narrower reads.',
            'On retries, carry only the active blocker contract, changed-file list, relevant diff/evidence summary, and latest failing command output. Do not restart with a clean-slate mega prompt.',
            'Stop autonomous retries when the same normalized blocker repeats without meaningful diff or evidence improvement; park with a precise blocker instead of burning tokens.'
        ]
        : [];
    var dependencyBootstrap = options.includeDependencyBootstrap !== false
        ? [
            'Reuse existing dependency caches and hydrated node_modules when available. Prefer npm install --force with the configured npm cache; do not use npm ci unless the workflow explicitly requires it.',
            'Before reinstalling or downloading browsers, check the existing workspace cache, shared node_modules, PUPPETEER_EXECUTABLE_PATH, CHROME_BIN, PUPPETEER_CACHE_DIR, and project-provided bootstrap scripts.'
        ]
        : [];
    var repairLoop = options.includeRepairLoop !== false
        ? [
            "Use targeted repair waves: compile/startup blocker, browser route/action blocker, data/publication blocker, and review blocker each get a focused repair, then rerun the exact failed step. Limit this to ".concat(maxRepairWaves, " focused waves before returning a precise blocker."),
            'Repair all instances of a detected blocker class in the touched scope, not only the first occurrence.'
        ]
        : [];
    var qaPolicy = options.includeQaPolicy !== false
        ? buildResolveIOQaPolicyRules(__assign(__assign({}, options), { qaSelfRepairMaxWaves: maxRepairWaves }))
        : [];
    var evidenceContract = options.includeEvidenceContract !== false
        ? [
            'Evidence must be customer/workflow oriented: routes, buttons, pages, data states, screenshots/traces, command results, and assertions. Do not expose internal file names, backend paths, stack traces, or implementation chatter in customer-facing text.',
            'For UI-facing changes, capture one screenshot or trace per distinct changed feature/workflow; for data-only changes, provide live-data or seeded-data assertion proof.',
            'For import, upload, export, form submit, calculation, publication, or persistence fixes, proof must show the before/action/after workflow state and a concrete row/count/value assertion. Empty shell screenshots do not count as proof.',
            'Desktop proof screenshots must use a wide/full-screen viewport, normally 1920x1080 or wider, with navigation closed/unwrapped unless the ticket is specifically about mobile or menu behavior.',
            'Each screenshot must have a customer-facing caption that says what the image proves; these captions are used in validation emails.'
        ]
        : [];
    var finalNotes = [
        'Final notes must include: changed behavior, touched functional areas, exact commands run, exact QA route/data state, screenshot/trace/log paths, and remaining blockers if any.',
        'If work is parked, final notes must name the blocker class, last failing command/artifact, why another autonomous attempt would repeat, and the smallest manual action needed.'
    ];
    var sections = {
        runnerBasics: runnerBasics,
        tokenDiscipline: tokenDiscipline,
        dependencyBootstrap: dependencyBootstrap,
        repairLoop: repairLoop,
        qaPolicy: qaPolicy,
        evidenceContract: evidenceContract,
        finalNotes: finalNotes
    };
    var rules = __spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray([], __read(runnerBasics), false), __read(tokenDiscipline), false), __read(dependencyBootstrap), false), __read(repairLoop), false), __read(qaPolicy), false), __read(evidenceContract), false), __read(finalNotes), false);
    var promptLines = __spreadArray([
        "ResolveIO shared runner contract (".concat(context, "):")
    ], __read(rules.map(function (rule) { return "- ".concat(rule); })), false);
    return {
        context: context,
        sections: sections,
        rules: rules,
        promptLines: promptLines
    };
}
function buildResolveIORunnerPromptLines(options) {
    if (options === void 0) { options = {}; }
    return buildResolveIORunnerContract(options).promptLines;
}
function buildResolveIORunnerPromptBundle(input) {
    if (input === void 0) { input = {}; }
    var contract = buildResolveIORunnerContract(input);
    var maxTextChars = normalizePositiveInteger(input.maxTextChars, 900, 160, 2400);
    var objective = normalizeTextLine(input.objective, maxTextChars)
        || 'Complete the requested ResolveIO runner task with minimal, verified changes.';
    var priorSummary = normalizeTextLine(input.priorSummary, maxTextChars);
    var latestFailure = normalizeTextLine(input.latestFailure, maxTextChars);
    var blockers = normalizeTextList(input.blockers, normalizePositiveInteger(input.maxBlockers, 5, 1, 12), maxTextChars);
    var relevantFiles = normalizeTextList(input.relevantFiles, normalizePositiveInteger(input.maxFiles, 12, 1, 30), 260);
    var evidence = normalizeTextList(input.evidence, normalizePositiveInteger(input.maxEvidence, 8, 1, 20), maxTextChars);
    var contextLines = __spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray([
        "Objective: ".concat(objective)
    ], __read((priorSummary ? ["Prior summary: ".concat(priorSummary)] : [])), false), __read((latestFailure ? ["Latest failure: ".concat(latestFailure)] : [])), false), __read((blockers.length ? __spreadArray(['Active blockers:'], __read(blockers.map(function (line) { return "- ".concat(line); })), false) : [])), false), __read((relevantFiles.length ? __spreadArray(['Relevant files:'], __read(relevantFiles.map(function (line) { return "- ".concat(line); })), false) : [])), false), __read((evidence.length ? __spreadArray(['Known evidence:'], __read(evidence.map(function (line) { return "- ".concat(line); })), false) : [])), false);
    var repairLines = blockers.length
        ? [
            'Mandatory repair contract:',
            '- Address each active blocker before unrelated work.',
            '- For each blocker, mark resolved, proven false, or blocked.',
            '- Attach code, data, command, browser, screenshot, or trace proof for each blocker.',
            '- If a blocker repeats with no meaningful diff/evidence change, park instead of starting another broad attempt.'
        ]
        : [];
    var fullPromptLines = __spreadArray(__spreadArray(__spreadArray(__spreadArray([], __read(contract.promptLines), false), [
        '',
        'Runner task context:'
    ], false), __read(contextLines), false), __read((repairLines.length ? __spreadArray([''], __read(repairLines), false) : [])), false);
    return __assign(__assign({}, contract), { objective: objective, contextLines: contextLines, repairLines: repairLines, fullPromptLines: fullPromptLines });
}
function buildResolveIORunnerRepairPromptLines(input) {
    if (input === void 0) { input = {}; }
    return buildResolveIORunnerPromptBundle(input).repairLines;
}
function normalizeResolveIORunnerBlocker(entry) {
    return String(entry || '')
        .toLowerCase()
        .replace(/:[0-9]+(?=\b|[);,.\s])/g, ':#')
        .replace(/\bline\s+[0-9]+\b/g, 'line #')
        .replace(/\blines?\s+[0-9]+\s*[-–]\s*[0-9]+\b/g, 'lines #')
        .replace(/\battempt\s+[0-9]+\b/g, 'attempt #')
        .replace(/\s+/g, ' ')
        .trim();
}
function uniqueNormalizedResolveIORunnerBlockers(values) {
    if (!Array.isArray(values)) {
        return [];
    }
    return Array.from(new Set(values
        .map(function (entry) { return normalizeResolveIORunnerBlocker(String(entry || '')); })
        .filter(Boolean)));
}
function findRepeatedResolveIORunnerBlockers(previousBlockers, currentBlockers) {
    if (previousBlockers === void 0) { previousBlockers = []; }
    if (currentBlockers === void 0) { currentBlockers = []; }
    var previous = new Set(uniqueNormalizedResolveIORunnerBlockers(previousBlockers));
    if (!previous.size) {
        return [];
    }
    return Array.from(new Set((currentBlockers || [])
        .map(function (entry) { return String(entry || '').trim(); })
        .filter(function (entry) { return previous.has(normalizeResolveIORunnerBlocker(entry)); })));
}
function decideResolveIORunnerRepairContinuation(input) {
    if (input === void 0) { input = {}; }
    var currentBlockers = (input.currentBlockers || [])
        .map(function (entry) { return String(entry || '').trim(); })
        .filter(Boolean);
    var normalizedCurrentBlockers = uniqueNormalizedResolveIORunnerBlockers(currentBlockers);
    var previousBlockers = uniqueNormalizedResolveIORunnerBlockers(input.previousBlockers || []);
    var activeContractBlockers = uniqueNormalizedResolveIORunnerBlockers(input.activeContractBlockers || []);
    var priorBlockers = new Set(__spreadArray(__spreadArray([], __read(previousBlockers), false), __read(activeContractBlockers), false));
    var repeatedBlockers = findRepeatedResolveIORunnerBlockers(Array.from(priorBlockers), currentBlockers);
    var repeated = new Set(repeatedBlockers.map(function (entry) { return normalizeResolveIORunnerBlocker(entry); }));
    var newBlockers = currentBlockers.filter(function (entry) { return !repeated.has(normalizeResolveIORunnerBlocker(entry)); });
    var currentAttempt = normalizePositiveInteger(input.currentAttempt, 1, 1, 100);
    var maxAttempts = normalizePositiveInteger(input.maxAttempts, 3, 1, 100);
    var currentRepairWaveCount = normalizePositiveInteger(input.currentRepairWaveCount, 0, 0, 100);
    var maxRepairWaves = normalizePositiveInteger(input.maxRepairWaves, 3, 0, 100);
    var diffHash = normalizeOptionalString(input.diffHash);
    var evidenceHash = normalizeOptionalString(input.evidenceHash);
    var previousDiffHash = normalizeOptionalString(input.previousDiffHash);
    var previousEvidenceHash = normalizeOptionalString(input.previousEvidenceHash);
    var noProgress = !!previousDiffHash
        && !!previousEvidenceHash
        && previousDiffHash === diffHash
        && previousEvidenceHash === evidenceHash;
    var nextAttempt = currentAttempt + 1;
    var nextRepairWaveCount = currentRepairWaveCount + 1;
    if (noProgress) {
        return {
            action: 'park_no_progress',
            repeatedBlockers: repeatedBlockers,
            newBlockers: newBlockers,
            normalizedCurrentBlockers: normalizedCurrentBlockers,
            nextAttempt: nextAttempt,
            nextRepairWaveCount: nextRepairWaveCount,
            reason: 'Targeted repair made no meaningful diff or evidence progress.'
        };
    }
    if (repeatedBlockers.length) {
        return {
            action: 'park_repeated_blocker',
            repeatedBlockers: repeatedBlockers,
            newBlockers: newBlockers,
            normalizedCurrentBlockers: normalizedCurrentBlockers,
            nextAttempt: nextAttempt,
            nextRepairWaveCount: nextRepairWaveCount,
            reason: 'The same normalized blocker repeated after a targeted repair.'
        };
    }
    var shouldStartNewWave = currentBlockers.length > 0
        && (activeContractBlockers.length > 0
            || currentAttempt >= maxAttempts);
    if (shouldStartNewWave) {
        if (currentRepairWaveCount >= maxRepairWaves) {
            return {
                action: 'park_repair_wave_budget',
                repeatedBlockers: repeatedBlockers,
                newBlockers: newBlockers,
                normalizedCurrentBlockers: normalizedCurrentBlockers,
                nextAttempt: nextAttempt,
                nextRepairWaveCount: nextRepairWaveCount,
                reason: "Repair wave budget exhausted (".concat(currentRepairWaveCount, "/").concat(maxRepairWaves, ").")
            };
        }
        return {
            action: 'start_repair_wave',
            repeatedBlockers: repeatedBlockers,
            newBlockers: newBlockers,
            normalizedCurrentBlockers: normalizedCurrentBlockers,
            nextAttempt: 2,
            nextRepairWaveCount: nextRepairWaveCount,
            reason: 'A prior blocker was cleared and a new blocker appeared; start a focused repair wave instead of consuming the final attempt.'
        };
    }
    return {
        action: 'continue_attempt',
        repeatedBlockers: repeatedBlockers,
        newBlockers: newBlockers,
        normalizedCurrentBlockers: normalizedCurrentBlockers,
        nextAttempt: nextAttempt,
        nextRepairWaveCount: currentRepairWaveCount,
        reason: 'Continue with the next targeted attempt.'
    };
}
function classifyResolveIORunnerBlocker(blocker) {
    var text = String(blocker || '');
    if (/database call inside loop|findOne.*inside loop|query inside loop/i.test(text)) {
        return 'db_call_inside_loop';
    }
    if (/inventory transaction parity|inventory transactions? are correct|inventory transaction creation\/reversal|inventory drift|reverse(?:s| old).*inventory|custom chemical lines?/i.test(text)) {
        return 'inventory_transaction_parity';
    }
    if (/company\/global default line-item surcharge|customer surcharge override|surcharge override.*default|global\/company surcharge|fallback\/override|first active surcharge/i.test(text)) {
        return 'surcharge_default_precedence';
    }
    if (/\bTS\d{4}\b[\s\S]{0,220}\bExpected\s+0\s+arguments?\b[\s\S]{0,160}\bgot\s+1\b/i.test(text)
        && /\b(publication|publications\.ts|subscribe|user_specific|ForUser|yardsForUser|customerNotifications|notificationCenter)\b/i.test(text)) {
        return 'user_specific_publication_argument_mismatch';
    }
    if (/\b(publication signature mismatch|generated publication signature|publication wrapper)\b[\s\S]{0,220}\b(?:yardsForUser|[A-Za-z0-9_]*ForUser)\b[\s\S]{0,160}\bcompile errors?\b/i.test(text)
        || /\b(?:yardsForUser|[A-Za-z0-9_]*ForUser)\b[\s\S]{0,180}\bcompile errors?\b[\s\S]{0,180}\b(publication|publications\.ts|signature|wrapper)\b/i.test(text)) {
        return 'user_specific_publication_argument_mismatch';
    }
    if (/\b(user_specific|user-specific)\b[\s\S]{0,220}\b(Expected\s+0\s+arguments?|got\s+1|passes?\s+1\s+argument|publication wrapper)\b/i.test(text)) {
        return 'user_specific_publication_argument_mismatch';
    }
    if (/focused verification evidence|Behavior-level test\/QA evidence|browser QA|screenshot|trace artifacts?|Billing Dashboard.*create\/edit|server-side evidence|Validation evidence/i.test(text)) {
        return 'support_qa_evidence';
    }
    if (/Approved scope requirement is not covered|approved .* scope lacks/i.test(text)) {
        return 'approved_scope_missing';
    }
    if (/UI-facing ticket needs|browser\/localhost QA|local\/browser QA/i.test(text)) {
        return 'ui_qa_missing';
    }
    if (/Report\/export ticket needs|report rows|export behavior/i.test(text)) {
        return 'report_export_missing';
    }
    if (/QA coverage matrix|full suite|limited smoke|too limited|only proves navigation|empty table|header screenshot|pre-submit only|missing persisted result|missing tax|missing inventory|missing invoice edit|missing reopen/i.test(text)) {
        return 'qa_coverage_incomplete';
    }
    if (/Generated .* changed without a matching/i.test(text)) {
        return 'generated_file_mismatch';
    }
    if (/No repository files changed|no verifiable PR fix/i.test(text)) {
        return 'no_repo_diff';
    }
    if (/QA compile preflight|ng serve failed|Angular ng serve failed|Completion build verification failed|build failed|TypeScript check failed|TypeScript compile|lint failed|TS\d{4}|Cannot find module/i.test(text)) {
        return 'completion_build_failed';
    }
    return 'reviewer_blocker';
}
function extractResolveIORunnerRepairLineHints(blocker) {
    var hints = [];
    var lineMatch = String(blocker || '').match(/(?:line\s+|:)([0-9]+)\b/i);
    if (lineMatch) {
        hints.push("line ".concat(lineMatch[1]));
    }
    var loopMatch = String(blocker || '').match(/loop starts near line\s+([0-9]+)/i);
    if (loopMatch) {
        hints.push("loop starts near line ".concat(loopMatch[1]));
    }
    return Array.from(new Set(hints));
}
function extractResolveIORunnerRepairTargetFiles(blocker, changedFiles) {
    var e_2, _a;
    if (changedFiles === void 0) { changedFiles = []; }
    var files = new Set();
    var text = String(blocker || '');
    var pathPattern = /(?:^|\s)([A-Za-z0-9_.-]+(?:\/[A-Za-z0-9_.-]+)+\.(?:ts|tsx|js|jsx|html|scss|css|json|md))/g;
    var match;
    while ((match = pathPattern.exec(text))) {
        files.add(match[1].replace(/\\/g, '/'));
    }
    try {
        for (var _b = __values(changedFiles || []), _c = _b.next(); !_c.done; _c = _b.next()) {
            var filePath = _c.value;
            var normalized = String(filePath || '').trim().replace(/\\/g, '/');
            if (normalized && (text.includes(normalized) || text.includes(normalized.replace(/^[^/]+\//, '')))) {
                files.add(normalized);
            }
        }
    }
    catch (e_2_1) { e_2 = { error: e_2_1 }; }
    finally {
        try {
            if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
        }
        finally { if (e_2) throw e_2.error; }
    }
    return Array.from(files).slice(0, 8);
}
function selectResolveIORunnerRepairTargetFiles(changedFiles, preferredSuffixes, fallbackFiles) {
    var e_3, _a;
    if (changedFiles === void 0) { changedFiles = []; }
    if (preferredSuffixes === void 0) { preferredSuffixes = []; }
    if (fallbackFiles === void 0) { fallbackFiles = []; }
    var suffixes = (preferredSuffixes || [])
        .map(function (entry) { return String(entry || '').trim().replace(/\\/g, '/').replace(/^\/+/, ''); })
        .filter(Boolean);
    var matched = new Set();
    var _loop_1 = function (filePath) {
        var normalized = String(filePath || '').trim().replace(/\\/g, '/');
        if (normalized && suffixes.some(function (suffix) { return normalized === suffix || normalized.endsWith("/".concat(suffix)); })) {
            matched.add(normalized);
        }
    };
    try {
        for (var _b = __values(changedFiles || []), _c = _b.next(); !_c.done; _c = _b.next()) {
            var filePath = _c.value;
            _loop_1(filePath);
        }
    }
    catch (e_3_1) { e_3 = { error: e_3_1 }; }
    finally {
        try {
            if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
        }
        finally { if (e_3) throw e_3.error; }
    }
    return (matched.size
        ? Array.from(matched)
        : fallbackFiles.map(function (entry) { return String(entry || '').trim().replace(/\\/g, '/'); }).filter(Boolean)).slice(0, 12);
}
function sanitizeResolveIORunnerRepairPlans(value) {
    return Array.isArray(value)
        ? value.map(function (entry) { return ({
            blockerClass: String((entry === null || entry === void 0 ? void 0 : entry.blockerClass) || '').trim(),
            sourceGate: String((entry === null || entry === void 0 ? void 0 : entry.sourceGate) || '').trim(),
            targetFiles: Array.isArray(entry === null || entry === void 0 ? void 0 : entry.targetFiles) ? entry.targetFiles.map(function (item) { return String(item || '').trim(); }).filter(Boolean).slice(0, 20) : [],
            lineHints: Array.isArray(entry === null || entry === void 0 ? void 0 : entry.lineHints) ? entry.lineHints.map(function (item) { return String(item || '').trim(); }).filter(Boolean).slice(0, 20) : [],
            failureEvidence: Array.isArray(entry === null || entry === void 0 ? void 0 : entry.failureEvidence) ? entry.failureEvidence.map(function (item) { return String(item || '').trim(); }).filter(Boolean).slice(0, 20) : [],
            requiredProof: Array.isArray(entry === null || entry === void 0 ? void 0 : entry.requiredProof) ? entry.requiredProof.map(function (item) { return String(item || '').trim(); }).filter(Boolean).slice(0, 20) : [],
            repairRecipe: Array.isArray(entry === null || entry === void 0 ? void 0 : entry.repairRecipe) ? entry.repairRecipe.map(function (item) { return String(item || '').trim(); }).filter(Boolean).slice(0, 20) : [],
            selfGateCommands: Array.isArray(entry === null || entry === void 0 ? void 0 : entry.selfGateCommands) ? entry.selfGateCommands.map(function (item) { return String(item || '').trim(); }).filter(Boolean).slice(0, 20) : [],
            passingCondition: String((entry === null || entry === void 0 ? void 0 : entry.passingCondition) || '').trim()
        }); }).filter(function (entry) { return entry.blockerClass || entry.failureEvidence.length; })
        : [];
}
function getResolveIORunnerRepairTargetOverride(options, blockerClass) {
    var _a;
    var override = (_a = options.targetFileOverrides) === null || _a === void 0 ? void 0 : _a[blockerClass];
    if (!override) {
        return null;
    }
    return {
        preferredSuffixes: Array.isArray(override.preferredSuffixes) ? override.preferredSuffixes : [],
        fallbackFiles: Array.isArray(override.fallbackFiles) ? override.fallbackFiles : []
    };
}
function applyResolveIORunnerRepairTargetOverride(plan, options, blockerClass) {
    var override = getResolveIORunnerRepairTargetOverride(options, blockerClass);
    if (!override || plan.targetFiles.length) {
        return plan;
    }
    return __assign(__assign({}, plan), { targetFiles: selectResolveIORunnerRepairTargetFiles(options.changedFiles || [], override.preferredSuffixes || [], override.fallbackFiles || []) });
}
function buildResolveIORunnerRepairPlans(input) {
    if (input === void 0) { input = {}; }
    var changedFiles = Array.isArray(input.changedFiles) ? input.changedFiles : [];
    var sourceGate = String(input.gateSource || 'pre_review_or_reviewer').trim() || 'pre_review_or_reviewer';
    var qaRules = buildResolveIORunnerBasicsRules(__assign(__assign({}, input), { context: input.context || 'general', includeDevServerRules: input.includeDevServerRules === true, maxContextBullets: input.maxContextBullets || 8 }));
    return Array.from(new Set((input.blockers || []).map(function (entry) { return String(entry || '').trim(); }).filter(Boolean))).map(function (blocker) {
        var _a;
        var blockerClass = classifyResolveIORunnerBlocker(blocker);
        var base = {
            blockerClass: blockerClass,
            sourceGate: sourceGate,
            targetFiles: extractResolveIORunnerRepairTargetFiles(blocker, changedFiles),
            lineHints: extractResolveIORunnerRepairLineHints(blocker),
            failureEvidence: [blocker].filter(Boolean).slice(0, 8),
            requiredProof: [],
            repairRecipe: [],
            selfGateCommands: [],
            passingCondition: ''
        };
        if (blockerClass === 'db_call_inside_loop') {
            return applyResolveIORunnerRepairTargetOverride(__assign(__assign({}, base), { requiredProof: [
                    'Show the database lookup is batched before the loop, or prove the flagged call is not a database collection call.',
                    'Cite the exact file/function and before-vs-after loop/query shape in Repair Execution Notes.',
                    'Confirm the changed diff no longer has any per-item database collection call in any loop body in the touched/target server files.'
                ], repairRecipe: [
                    'Inspect every loop in the touched/target server files and identify all database collection calls inside those loops.',
                    'Move collection reads before loops using batched `$in` queries, map results by id/key, then use the map inside loops.',
                    'Move writes out of loops using batched `bulkWrite`/multi-update operations prepared inside the loop and executed after the loop.',
                    'If the call is a local array/helper and not a database call, prove that with the declaration/import path and leave the code unchanged.',
                    'Keep the behavior identical except for eliminating every per-item database call.'
                ], selfGateCommands: [
                    'git diff HEAD -- <target file>',
                    'rg -n "for .*\\{|\\.forEach|for \\(" <target file>',
                    'rg -n "\\.(find|findOne|findOneAsync|count|countDocuments|update|updateOne|updateMany|insert|insertOne|bulkWrite|remove|deleteOne|deleteMany)\\(" <target file>'
                ], passingCondition: 'No loop in the touched/target server files has a database collection call in its body, or final notes prove each flagged call is not a database call.' }), input, blockerClass);
        }
        if (blockerClass === 'report_export_missing') {
            return applyResolveIORunnerRepairTargetOverride(__assign(__assign({}, base), { requiredProof: ['Prove report rows, filters, totals/grouping, and export behavior, or cite ticket evidence that export is out of scope.'], repairRecipe: ['Exercise the report/export path and record evidence for each report dimension requested by the ticket.'], selfGateCommands: ['Run the report/export verification command or browser flow for the ticket.'], passingCondition: 'Final notes prove rows, filters, totals/grouping, and export behavior or a ticket-backed out-of-scope decision.' }), input, blockerClass);
        }
        if (blockerClass === 'inventory_transaction_parity') {
            return applyResolveIORunnerRepairTargetOverride(__assign(__assign({}, base), { requiredProof: [
                    'Prove non-Manual Delivery and Truck Treat custom chemical lines create inventory relief transactions on invoice create.',
                    'Prove invoice edit reverses old custom chemical effects and applies the new custom chemical effects.',
                    'Prove invoice remove/delete reverses the same non-Manual custom chemical inventory effects.'
                ], repairRecipe: [
                    'Start in server/src/methods/invoices.ts and trace Manual inventory behavior before changing the non-Manual path.',
                    'Reuse the existing inventory transaction helper shape instead of creating a parallel inventory writer.',
                    'Handle all custom chemical lines in one sweep: create, edit, and remove for Delivery and Truck Treat invoices.',
                    'Do not stop after fixing only create; the reviewer blocker includes edit and remove reversal.'
                ], selfGateCommands: [
                    'git diff HEAD -- server/src/methods/invoices.ts server/src/methods/inventory-transactions.ts',
                    'rg -n "is_custom_line_item|addInventoryTransaction|removeInvoice|editInvoice|custom chemical" server/src/methods/invoices.ts',
                    'Run or add a focused server/data assertion covering create, edit, and remove inventory transactions for non-Manual custom chemical lines.'
                ], passingCondition: 'Create, edit, and remove paths for non-Manual custom chemical invoice lines all have inventory transaction proof.' }), input, blockerClass);
        }
        if (blockerClass === 'surcharge_default_precedence') {
            return applyResolveIORunnerRepairTargetOverride(__assign(__assign({}, base), { requiredProof: [
                    'Show the persisted company/global default surcharge owner, not just the first active surcharge item.',
                    'Show precedence is customer override when active, then company/global default when active, then empty/none when inactive or unset.',
                    'Show at least one override customer and one default customer path in verification evidence.'
                ], repairRecipe: [
                    'Find the surcharge default selector and replace any first-active-item fallback with an explicit persisted default setting.',
                    'Keep customer override storage separate from the company/global default setting.',
                    'Reject inactive surcharge items during both override and default fallback.',
                    'Cover unset and inactive settings with safe empty/none behavior.'
                ], selfGateCommands: [
                    'git diff HEAD -- angular/app/manage/item angular/app/widgets/dialog/dialog.adjust-customer.content.ts server/src/collections server/src/models',
                    'rg -n "line_item_surcharge|surcharge|id_line_item_surcharge_override|default" angular/app server/src',
                    'Run or add a focused fallback/override assertion for active override, active company default, inactive override/default, and unset default.'
                ], passingCondition: 'Customer override -> company/global default -> none precedence is persisted and verified.' }), input, blockerClass);
        }
        if (blockerClass === 'support_qa_evidence') {
            return applyResolveIORunnerRepairTargetOverride(__assign(__assign({}, base), { requiredProof: [
                    'Include browser route and screenshot/trace artifact paths for each distinct changed customer-facing feature or workflow state.',
                    'Do not duplicate screenshots across multiple customers unless the customer-specific override/fallback behavior is the feature being proven.',
                    'Include data/assertion evidence for requested persistence, calculations, and side effects.',
                    'Include a QA Coverage Matrix row for every approved scope item and every touched workflow/domain.',
                    'For import/export/form-submit/data workflow fixes, include before/action/after screenshots or trace steps plus the exact row/count/value assertion proving the submitted data changed as expected.',
                    'Reject empty page/table/header screenshots as insufficient unless the approved requirement is explicitly an empty-state UI.',
                    'Use a 1920x1080-or-wider desktop viewport for screenshots unless the ticket explicitly requests mobile/responsive behavior; desktop nav must be closed and not wrapped over the workflow.',
                    'Before pass, prove each cited screenshot visibly contains the target row/control/value and is not covered by the ResolveIO menu/sidebar/header overlay. If DOM text passes but screenshot is covered, recapture after closing/settling the shell.',
                    'Provide a customer-facing caption for each screenshot that explains the workflow state and proof shown.',
                    'If browser QA cannot start, include the exact startup blocker and the compile/preflight command output.'
                ], repairRecipe: __spreadArray(__spreadArray(__spreadArray([], __read(qaRules), false), __read(buildResolveIORunnerQaCoverageChecklist({
                    ticketText: ((_a = input.blockers) === null || _a === void 0 ? void 0 : _a.join('\n')) || '',
                    changedFiles: changedFiles
                })), false), [
                    'Upload or preserve screenshots/trace paths so the PR and support ticket can reference them.'
                ], false), selfGateCommands: [
                    'Run the support QA compile/startup preflight.',
                    'Run the ticket-specific browser QA click-through and capture screenshots/trace artifacts.',
                    'Record artifact paths and data assertions in final notes.'
                ], passingCondition: 'Final notes include one QA screenshot/trace path per distinct changed feature plus data assertions for the approved scope.' }), input, blockerClass);
        }
        if (blockerClass === 'qa_coverage_incomplete') {
            return applyResolveIORunnerRepairTargetOverride(__assign(__assign({}, base), { requiredProof: [
                    'Provide a QA Coverage Matrix that covers every changed workflow/domain from the approved scope and diff.',
                    'For invoice/billing/tax/inventory changes, include create/edit/reopen/delete or not-applicable coverage plus persisted row/value assertions.',
                    'Show fresh screenshots/traces with customer-facing captions for each distinct changed workflow state.'
                ], repairRecipe: __spreadArray(__spreadArray([
                    'Read the approved scope, BUILD_PLAN, changed files, and prior QA evidence; identify every workflow/domain touched by the implementation.'
                ], __read(buildResolveIORunnerQaCoverageChecklist({
                    ticketText: blocker,
                    changedFiles: changedFiles
                })), false), [
                    'If localhost QA has no usable records for a required workflow, seed a minimal faithful fixture in the local QA database and cite the fixture IDs/names in the matrix; production data stays read-only.',
                    'If QA finds a product defect while covering the matrix, fix that defect in a targeted repair wave, rerun compile/startup preflight, then rerun the failed matrix row before continuing.',
                    'Return pass only after the matrix is complete; otherwise return needs-fix with the exact missing matrix row.'
                ], false), selfGateCommands: [
                    'Run compile/startup preflight before browser QA.',
                    'Run the ticket-specific browser/data QA flow for every QA Coverage Matrix row.',
                    'Record artifact paths, captions, and persisted row/count/value assertions in final notes.'
                ], passingCondition: 'Every QA Coverage Matrix row has a pass result with screenshot/trace/data proof, or the job returns a precise needs-fix blocker that seeds the next repair wave.' }), input, blockerClass);
        }
        if (blockerClass === 'approved_scope_missing') {
            return applyResolveIORunnerRepairTargetOverride(__assign(__assign({}, base), { requiredProof: ['Add one Self-Review Checklist bullet for the exact missing approved requirement with code/data/browser proof.'], repairRecipe: ['Verify the missing approved requirement, then implement or document done/not applicable/blocked with proof.'], selfGateCommands: ['Review final notes for exact approved requirement text and proof artifact.'], passingCondition: 'Every missing approved requirement is explicitly mapped to done/not applicable/blocked with proof.' }), input, blockerClass);
        }
        if (blockerClass === 'ui_qa_missing') {
            return applyResolveIORunnerRepairTargetOverride(__assign(__assign({}, base), { requiredProof: ['Provide browser route plus screenshot/trace/video path, or a precise LOCALHOST_QA_PLAYBOOK startup/access blocker.'], repairRecipe: ['Run local/browser QA for the failing UI route after the fix, or document the exact startup/access blocker.'], selfGateCommands: ['source .resolveio-support-tools/env.sh if present', 'Run the ticket-specific localhost/browser QA command or capture blocker.'], passingCondition: 'Final notes contain browser QA artifact evidence or a concrete local startup/access blocker.' }), input, blockerClass);
        }
        if (blockerClass === 'generated_file_mismatch') {
            return applyResolveIORunnerRepairTargetOverride(__assign(__assign({}, base), { requiredProof: ['Show generated client file changes correspond to matching server method/publication source changes.'], repairRecipe: ['Either update the server owner and regenerate the companion file, or revert the orphan generated file change.'], selfGateCommands: ['git diff HEAD -- angular/app/methods.ts angular/app/publications.ts server/src/methods server/src/publications'], passingCondition: 'No generated client file is changed without its source server owner change.' }), input, blockerClass);
        }
        if (blockerClass === 'user_specific_publication_argument_mismatch') {
            return applyResolveIORunnerRepairTargetOverride(__assign(__assign({}, base), { requiredProof: [
                    'List every failing call site and show each one was fixed, not just the first TypeScript error.',
                    'Show whether each call needs the current logged-in user or an explicit other user/driver id.',
                    'Show generated angular/app/publications.ts came from server/src/publications source and was not hand-edited as the behavioral fix.'
                ], repairRecipe: [
                    'user_specific publications inject the logged-in socket user as the first server parameter; generated client wrappers should remove only that injected parameter.',
                    'Before changing call sites, inspect the source publication signature. If a client can pass a target user/driver, make the source explicit as function(id_current_user: string, id_user?: string) and regenerate.',
                    'Only remove a client argument when the publication truly uses the injected current user only; otherwise preserve explicit target-user/driver calls such as yardsForUser(id_driver).',
                    'Do not hand-edit generated angular/app/publications.ts to accept the injected id_user again; fix source publications/call sites, then regenerate.',
                    'Search the whole app for the failing wrapper name and repair all argument-passing calls in the same pass.'
                ], selfGateCommands: [
                    'rg -n "\\b[A-Za-z0-9_]*ForUser\\s*\\([^)]+" angular/app server/src',
                    'rg -n "\\byardsForUser\\s*\\([^)]+" angular/app server/src',
                    'Run the method/publication generator if server publication source changed.',
                    'Rerun the exact TypeScript/Angular compile command that failed.'
                ], passingCondition: 'Generated user_specific wrappers strip only the injected current-user parameter, explicit target-user arguments still compile where required, and the exact compile command exits 0.' }), input, blockerClass);
        }
        if (blockerClass === 'completion_build_failed') {
            return applyResolveIORunnerRepairTargetOverride(__assign(__assign({}, base), { requiredProof: ['Include the failing command, root cause, fix, and passing rerun output.'], repairRecipe: ['Fix the compile/test failure directly, then rerun the exact failing command.'], selfGateCommands: ['Rerun the exact completion/build command shown in the blocker.'], passingCondition: 'The exact previously failing build/test command passes or is blocked with concrete environment evidence.' }), input, blockerClass);
        }
        return applyResolveIORunnerRepairTargetOverride(__assign(__assign({}, base), { requiredProof: ['Resolve, prove false, or block this reviewer/gate blocker with concrete code/data/browser proof.'], repairRecipe: ['Inspect the cited file/evidence, make the smallest supported fix, and cite before-vs-after proof.'], selfGateCommands: ['git diff HEAD --stat', 'Run the ticket-specific verification for this blocker.'], passingCondition: 'The blocker text no longer applies and final notes include concrete proof.' }), input, blockerClass);
    });
}

//# sourceMappingURL=ai-qa-policy.js.map
