{"version":3,"file":"progress.d.ts","sourceRoot":"","sources":["../../../../src/core/long-horizon/adaptive/progress.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtD,mEAAmE;AACnE,eAAO,MAAM,yBAAyB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAY5D,CAAC;AAEF,8DAA8D;AAC9D,eAAO,MAAM,uBAAuB,EAAE,WAAW,CAAC,MAAM,CAOtD,CAAC;AAEH,MAAM,WAAW,cAAc;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,cAAc;IAC9B,WAAW,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACxC,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,mBAAmB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,SAAS,mBAAmB,EAAE,CAAC;CAC7C;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,mBAAmB,CAE5E;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,mBAAmB,GAAG,MAAM,CAElE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,mBAAmB,EAAE,MAAM,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,GAAG,cAAc,CAuCpH;AAED,wBAAgB,iBAAiB,CAChC,GAAG,EAAE,mBAAmB,EACxB,WAAW,EAAE,mBAAmB,GAAG,IAAI,GACrC,mBAAmB,CAGrB;AAED,uEAAuE;AACvE,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAMvD","sourcesContent":["/**\n * Structured progress model.\n *\n * Progress is authoritative only when it corresponds to a verifiable structured\n * state change (new verified evidence, new source, new file-content hash, new\n * test result, new phase, resolved blocker, reduced failing-test count, ...).\n * Model prose, repeated identical reads/searches/commands, and reformatting are\n * NOT progress. Progress weights are deterministic and configurable — never\n * invented turn-by-turn by the model.\n */\n\nimport type { ProgressObservation } from \"./types.js\";\n\n/** Progress categories and their deterministic default weights. */\nexport const PROGRESS_CATEGORY_WEIGHTS: Record<string, number> = {\n\tnew_verified_evidence: 3,\n\tnew_source_fetched: 2,\n\tnew_file_content_hash: 2,\n\tnew_transaction_confirmed: 3,\n\tnew_test_result: 2,\n\tnew_diagnostics_delta: 1,\n\tnew_job_state: 1,\n\tnew_long_horizon_phase: 2,\n\tresolved_blocker: 3,\n\treduced_failing_test_count: 3,\n\tcompleted_acceptance_criterion: 3,\n};\n\n/** Categories that never constitute progress on their own. */\nexport const NON_PROGRESS_CATEGORIES: ReadonlySet<string> = new Set([\n\t\"model_prose\",\n\t\"repeated_search\",\n\t\"repeated_file_read\",\n\t\"repeated_failing_command\",\n\t\"reformatted_explanation\",\n\t\"job_poll_no_state_change\",\n]);\n\nexport interface ProgressParams {\n\tcategory: string;\n\tpreviousStateHash?: string;\n\tcurrentStateHash?: string;\n\tevidenceIds: string[];\n\tweights?: Record<string, number>;\n}\n\nexport interface ProgressResult {\n\tobservation: ProgressObservation | null;\n\tisProgress: boolean;\n\treason: string;\n\tweight: number;\n}\n\nexport interface ProgressAccumulator {\n\trunId: string;\n\tobservations: readonly ProgressObservation[];\n}\n\nexport function createProgressAccumulator(runId: string): ProgressAccumulator {\n\treturn { runId, observations: Object.freeze([]) };\n}\n\nexport function accumulatorWeight(acc: ProgressAccumulator): number {\n\treturn acc.observations.reduce((sum, o) => sum + o.progressWeight, 0);\n}\n\n/**\n * Evaluate a progress signal deterministically. Returns `null` observation when\n * the signal is not authoritative progress (prose, duplicate, no state change).\n */\nexport function observeProgress(acc: ProgressAccumulator, params: ProgressParams, recordedAt: string): ProgressResult {\n\tconst weights = params.weights ?? PROGRESS_CATEGORY_WEIGHTS;\n\n\tif (NON_PROGRESS_CATEGORIES.has(params.category)) {\n\t\treturn { observation: null, isProgress: false, reason: `NON_PROGRESS_CATEGORY:${params.category}`, weight: 0 };\n\t}\n\n\tconst weight = weights[params.category];\n\tif (weight === undefined || weight <= 0) {\n\t\treturn { observation: null, isProgress: false, reason: `UNKNOWN_OR_ZERO_WEIGHT:${params.category}`, weight: 0 };\n\t}\n\n\t// A state change must be present and must differ from the previous state.\n\tif (!params.currentStateHash) {\n\t\treturn { observation: null, isProgress: false, reason: \"NO_STATE_HASH\", weight: 0 };\n\t}\n\tif (params.previousStateHash && params.previousStateHash === params.currentStateHash && weight <= 1) {\n\t\treturn { observation: null, isProgress: false, reason: \"NO_STATE_CHANGE\", weight: 0 };\n\t}\n\n\t// Deduplicate identical evidence-backed observations for the same state.\n\tfor (const o of acc.observations) {\n\t\tif (o.category === params.category && o.currentStateHash === params.currentStateHash && o.phaseId === undefined) {\n\t\t\treturn { observation: null, isProgress: false, reason: `DUPLICATE_PROGRESS:${params.category}`, weight: 0 };\n\t\t}\n\t}\n\n\tconst observationId = `obs-${acc.observations.length + 1}-${recordedAt.length}-${params.category}`;\n\tconst observation: ProgressObservation = Object.freeze({\n\t\tobservationId,\n\t\trunId: acc.runId,\n\t\tcategory: params.category,\n\t\tpreviousStateHash: params.previousStateHash,\n\t\tcurrentStateHash: params.currentStateHash,\n\t\tevidenceIds: Object.freeze([...params.evidenceIds]),\n\t\tprogressWeight: weight,\n\t\trecordedAt,\n\t});\n\treturn { observation, isProgress: true, reason: \"STRUCTURED_PROGRESS\", weight };\n}\n\nexport function appendObservation(\n\tacc: ProgressAccumulator,\n\tobservation: ProgressObservation | null,\n): ProgressAccumulator {\n\tif (!observation) return acc;\n\treturn { runId: acc.runId, observations: Object.freeze([...acc.observations, observation]) };\n}\n\n/** Compute a short deterministic file-content state hash surrogate. */\nexport function fileContentHash(content: string): string {\n\tlet hash = 5381;\n\tfor (let i = 0; i < content.length; i += 1) {\n\t\thash = ((hash << 5) + hash + content.charCodeAt(i)) | 0;\n\t}\n\treturn `h${Math.abs(hash).toString(16)}`;\n}\n"]}