mtech-ai-local-runner 0.1.92 → 0.1.94

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,3 +1,46 @@
1
+ ## Unreleased: bounded report drafting and offline preflight
2
+
3
+ The final writing guidance targets 1,200 UTF-16 code units in `report`, below
4
+ the unchanged 2,000-unit acceptance limit. Findings and uncertainty belong in
5
+ the short report; detailed citations belong in `evidence`. No automatic
6
+ truncation, content repair, model retry, new tool or launch permission is added.
7
+ Prompt guidance alone cannot guarantee model compliance: an oversized final
8
+ response still fails closed. These changes are source-only, not part of the
9
+ installed/reviewed 0.1.93 package.
10
+
11
+ From the `runners/local-agent` source checkout, before another live validation,
12
+ replay saved **final response text**, not a transcript or stream-JSON wrapper,
13
+ through the production completion validator (the script is a repository-only
14
+ rehearsal utility, not an installed Runner command):
15
+
16
+ ```sh
17
+ npm run build
18
+ node scripts/check-completion-report.mjs /absolute/path/to/final-response.txt
19
+ ```
20
+
21
+ This offline script reads a bounded UTF-8 file, emits only counts and fixed
22
+ diagnostics, and never rewrites the input, calls a model, accesses Gateway or
23
+ starts work. Exit 0 means valid transport (including a truthful `blocked`
24
+ report), 1 means rejected transport, and 2 means usage/read/encoding/input-size
25
+ failure. A reported `completed` status does not verify the investigation,
26
+ citations or Work Item completion. The exact 2026-11-05 failure is preserved as
27
+ an untrusted technical test fixture; its claims are not accepted as true.
28
+
29
+ No package publication, Gateway registration, Runner replacement or new live
30
+ execution has been performed for this source change. Those require separate
31
+ release review, exact hashes and execution approval.
32
+
33
+ ## 0.1.93: strict investigation JSON completion guidance
34
+
35
+ Claude uses native-stream progress guidance and receives scoped tool/correction
36
+ context before the final JSON completion contract. A draft for owner review
37
+ still returns the structured report to the Runner without answering the original
38
+ request. Markdown remains rejected; no repair call or automatic retry is added.
39
+ Source verification does not prove live model compliance. Existing attempts,
40
+ contracts, Loop limits and security policies are unchanged. Installation needs
41
+ freshly reviewed package/runtime hashes; Gateway deployment alone does not
42
+ replace an installed Runner.
43
+
1
44
  ## Unreleased: Gateway-managed verification budget (P3E)
2
45
 
3
46
  D6 owner revision `fbc30fbe-cac9-45d1-9eff-bccec6ee6a54` selects a separate
@@ -27,5 +27,18 @@ export function compilePrompt(taskPackage, options) {
27
27
  const { toolInventory = "local-tools-v1", ...brief } = options;
28
28
  localToolNames(toolInventory);
29
29
  const correction = renderBundleCorrectionBrief(taskPackage);
30
- return `${compileBrief(taskPackage, brief)}\n\n${repositoryScope(taskPackage)}\n\n${LOCAL_TOOL_GUIDANCE}\n\n${claudePathRules(toolInventory)}${correction}`;
30
+ // Claude progress is observed from its native stream, not model-authored lifecycle JSON.
31
+ // Keep the final report contract last, including after untrusted correction findings.
32
+ return compileBrief(taskPackage, { ...brief, progressReporting: "native_messages" }, [
33
+ repositoryScope(taskPackage),
34
+ LOCAL_TOOL_GUIDANCE,
35
+ `${claudePathRules(toolInventory)}${correction}`,
36
+ "## Investigation result and transport boundary\n" +
37
+ "Put concise findings in report and source citations in evidence, not a standalone Markdown report. " +
38
+ "A draft for owner review still requires this final JSON transport report; returning it to the Runner " +
39
+ "does not submit an answer to the original request or authorize external publication. " +
40
+ "Distinguish source inspection from tests actually executed; a successful read is not a passed test. " +
41
+ "Before finalizing, check the required keys, report/evidence size limits and accurate pending_work. " +
42
+ "If unfinished, return one blocked report; never invent evidence or claim completion to satisfy the format.",
43
+ ]);
31
44
  }
@@ -0,0 +1,20 @@
1
+ import { completionEnvelope, completionEvent, COMPLETION_REPORT_LIMITS } from './completion-report.js';
2
+ /** Offline diagnostics only: never rewrites output, creates evidence, or authorizes execution. */
3
+ export function completionReportPreflight(raw) {
4
+ const options = { earlierCodeBlocks: true };
5
+ const envelope = completionEnvelope(raw, options);
6
+ const event = completionEvent(raw, undefined, options);
7
+ const rejection = event.payload?.completion_rejection;
8
+ const valid = event.eventType === 'completed' || event.payload?.reason === 'executor_blocked';
9
+ return {
10
+ valid_transport: valid,
11
+ // This is transport status only, not independent review or Work Item completion.
12
+ completed: event.eventType === 'completed',
13
+ status: valid ? (event.eventType === 'completed' ? 'completed' : 'blocked') : 'rejected',
14
+ rejection_code: rejection?.code ?? null,
15
+ report_code_units: typeof envelope?.report === 'string' ? envelope.report.length : null,
16
+ report_limit: COMPLETION_REPORT_LIMITS.reportCodeUnits,
17
+ evidence_count: Array.isArray(envelope?.evidence) ? envelope.evidence.length : null,
18
+ pending_work_count: Array.isArray(envelope?.pending_work) ? envelope.pending_work.length : null,
19
+ };
20
+ }
@@ -22,6 +22,14 @@ export function reportRejectionCounts(value, total) {
22
22
  const MAX_EVIDENCE_ITEMS = 20;
23
23
  const MAX_EVIDENCE_CHARS = 500;
24
24
  const MAX_REPORT_ENVELOPE_CHARS = 16_000;
25
+ /** Construction/rehearsal hints; acceptance always goes through completionEvent. */
26
+ export const COMPLETION_REPORT_LIMITS = Object.freeze({
27
+ reportCodeUnits: MAX_EVENT_SUMMARY_CHARS,
28
+ targetReportCodeUnits: Math.min(1200, MAX_EVENT_SUMMARY_CHARS),
29
+ listItems: MAX_EVIDENCE_ITEMS,
30
+ itemCodeUnits: MAX_EVIDENCE_CHARS,
31
+ envelopeCodeUnits: MAX_REPORT_ENVELOPE_CHARS,
32
+ });
25
33
  const REPORT_FAILURE_CODES = ["CODEX_COMPLETION_REPORT_MISSING", "CODEX_COMPLETION_REPORT_INVALID", "CODEX_COMPLETION_REPORT_MULTIPLE", "CODEX_COMPLETION_REPORT_NOT_FINAL", "CODEX_TURN_INCOMPLETE"];
26
34
  const REPORT_DIAGNOSTIC_CODES = [...REPORT_FAILURE_CODES, "CODEX_COMPLETION_REPORT_BLOCKED"];
27
35
  /** Pair counts only; no item IDs, text, stable digests or arbitrary keys. */
@@ -68,6 +76,11 @@ export const COMPLETION_REPORT_NOTICE = "Do the assigned work yourself using the
68
76
  "Your final response must be one JSON object, without Markdown fences: " +
69
77
  '{"status":"completed","report":"actual findings and results","evidence":["file path and observed finding, or command and actual result"],"pending_work":[]}. ' +
70
78
  `The report must be nonempty and at most ${MAX_EVENT_SUMMARY_CHARS} characters. ` +
79
+ `Aim for at most ${COMPLETION_REPORT_LIMITS.targetReportCodeUnits} UTF-16 code units in the decoded report string; the hard limit remains ${MAX_EVENT_SUMMARY_CHARS}. ` +
80
+ "Count decoded string length, not tokens, words, UTF-8 bytes or JSON escape characters; an emoji can count as two units. " +
81
+ "Use short findings for the requested topics, then uncertainty and verification limits. Put detailed source citations in evidence instead of repeating them in report. " +
82
+ "Do not fill the available limit or duplicate a narrative before the JSON. Before sending your single final response, shorten your own draft to the target and recheck all fields. " +
83
+ "Never drop uncertainty or pending work to fit the report; use blocked and accurate pending_work when work is incomplete. " +
71
84
  `Include 1-${MAX_EVIDENCE_ITEMS} nonempty evidence strings, each at most ${MAX_EVIDENCE_CHARS} characters. ` +
72
85
  "Address the assigned objective and each applicable acceptance criterion with observed evidence, not a plan or promise. " +
73
86
  "Only attest to executor work you observed; Gateway records transport, completion, and review receipts separately. " +
@@ -120,7 +120,8 @@ function continuationContext(taskPackage) {
120
120
  + "Do not replay a completed side effect. Never answer a human-only question or approve on another actor's behalf. "
121
121
  + "Required review, completion and publication gates remain separate; report only observed work and evidence, not delivery or operational success inferred from a local result.";
122
122
  }
123
- export function compilePrompt(taskPackage, options) {
123
+ /** Adapter-owned context stays ahead of the final wire-format contract. */
124
+ export function compilePrompt(taskPackage, options, adapterSections = []) {
124
125
  const contract = record(taskPackage.contract);
125
126
  if (!contract) {
126
127
  throw new Error("task package is missing a contract");
@@ -167,6 +168,7 @@ export function compilePrompt(taskPackage, options) {
167
168
  options.progressReporting === "native_messages"
168
169
  ? `## Native progress and terminal reporting\n${NATIVE_PROGRESS_NOTICE}`
169
170
  : `## Event and checkpoint obligations\n${EVENT_SCHEMA_NOTICE}`,
171
+ ...adapterSections,
170
172
  `## Final completion report\n${COMPLETION_REPORT_NOTICE}`,
171
173
  ];
172
174
  return sections.join("\n\n");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mtech-ai-local-runner",
3
- "version": "0.1.92",
3
+ "version": "0.1.94",
4
4
  "private": false,
5
5
  "license": "UNLICENSED",
6
6
  "bin": {