@llblab/pi-actors 0.57.0 → 0.57.1

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/AGENTS.md CHANGED
@@ -91,7 +91,7 @@ For ordinary Run-file investigation, follow the accepted [same-session research
91
91
  - `inspector.ts`: owned-Run evidence and exact-session/generation-fenced actions through injected canonical control dependencies. `inspector-overlay.ts` and `inspector-command.ts` retain UI/navigation and host command wiring separately. **Actor Inspector** remains the product and command name, not a separate domain.
92
92
  - `pi.ts`: Pi SDK envelope boundary. AX completion fallback identity comes from the closed terminal marker for new records or the original headers for retained captures when private details are stripped; keep the original legacy RegExp coercion order, reject noncanonical/indented/broken markers and never acknowledge by body equality; never let authored body labels or Unicode line separators override it. Preserve older header recognition and detailed-envelope precedence. Parsed ids remain hints until exact owned-journal/content admission; they grant no recipient, source or native authority.
93
93
  - `observability.ts`, `run-ui-runtime.ts`: Trace attention, terminal reconciliation and Pi delivery. Fresh urgent-steer admission uses formatRunSteerMessage's single canonical AX layout only after the retained run/generation/directory/event lookup. Envelope.content is already frozen presentation: replay it directly without a new journal aspect, source refresh or reformatting. Attention and steer have no presentation selector or alternate new-message formatter; deliverRunAttentionNotifications uses the same canonical AX primitives for new notify/followup output. Saved envelope.content remains the compatibility boundary. The two AX checkpoint/reference helpers now have real ordinary/urgent reuse inside observability; keep ordinary first-eight coverage independent of steer's shared16KiB reservation/refusal loop. No ambient ordinary byte cap, event/detail copy, wake change or regeneration of committed content follows. Fresh attention uses shallow typed block-YAML metadata, bare without a body and delimited before an opaque zero-added-indent body. Preserve scalar-aligned500UTF-16 legacy previews, existing ellipsis and unknown local/upstream loss, original stringify/getter faults, whole reference sequences and first-eight slots before malformed filtering. Ordinary notify/followup remains unbounded; urgent steer validates raw essentials before reference reads and fits the complete final YAML/body with later-group omission coverage under16KiB. Serialization stays local to observability, not a new global formatter allowance; selection/read/acceptance authority stays here. Fresh urgent diagnostics also reuse its opaque field primitive: event/attention/stage records distinguish retryable admission, failed send request with unconfirmed delivery/presentation, and queued recovery with its exact evidence status/reason. Do not infer no effect from an exception or turn checkpoint retry into workload replay. Diagnostic display keeps only240pair-aligned raw message units and authored Markdown, with boundary U+2026/[omitted: unknown] for loss and unavailable for malformed text. This current UI projection is separate from unchanged whitespace-normalized/trimmed4096-unit last_error, original Error/cause and frozen envelope.content; create no saved format/aspect, reader, recovery loop or extra source permission. Fresh locally owned runtime notices use tools-response.ts:formatYamlNotice, a UI-only flat-field serializer without the model byte/depth ceilings: retain full well-formed fields, withhold malformed selected text explicitly, and keep existing diagnostic-preview bounds. Callback failure preserves the original onCallbackError value and opaque diagnostic; completion recovery preserves evidence status/pending phase/reason with no forced send; idle completion delivery is labeled accepted only after the original durable acceptance; teardown counts/whole literal summary path are explicitly report data, not scope closure. Watcher/retirement messages are forwarded unchanged from observability's new AX producer formatting. Watcher messages reuse the already captured detail/recovery strings: never read Error.message twice, add primitive-error coercion, change raw signatures/IDs/ts/dedup/32suffix/rearm policy or regenerate older diagnostic text. Paths stay whole dynamic literals. Retirement notices preserve optional-notify argument short-circuiting, exact error-message observations, attempted/sendStop/cancel/result/failure behavior including notifier throws, and unconfirmed closure. Stop returned and cancellation reported are not native success; fallback reason is stop path failed because the path also contains notifier execution. Do not repair already-discarded lower causes or rewrite result errors from the display. No new clipping, identities, state reads, notifier timing/levels/dedup, retries, error wrappers or native authority. Fresh completion admission creates canonical AX only after existing owner/location rechecks; an already-admitted batch returns untouched, including every older presentation format. Keep active/idle timing, acceptance, exact generation and source admission authority unchanged; fresh completion-prefix allocation follows the run-delivery contract below. Color terminal status only in `ctx.mode === "tui"`; JSON/print/RPC status must not require an initialized terminal theme or disable mandatory completion delivery. Shared ready-forest selection and ambient candidate checks are metadata-only for primary sources. Read/verify a selected primary source only when collecting eligible completion members, retaining exact source owner/generation and refusing capture promotion or lost-source stdout substitution. Unsupported complete raw-stream selections remain explicit or legacy diagnostics, never fabricated primary output; separately admitted executor-final-response text is not complete raw-stream selection.
94
- - `run-delivery.ts`: owner-scoped durable packet/phase persistence and bounded projections. Fresh ordinary source admission captures presentation_format=ax_records, own-data result_layout=completion_yaml_core_v1 and frozen text_budget, with no presentation selector/excerpt_format; direct and ordinary UI admission share this path. The separate inactive numbered-stream capture still inherits frontmatter_v2; do not change the private default globally or relabel retained captures. Preserve all stored encodings/absence and exact replay bytes/hints, including headings_shared_kinds and frontmatter_v1/v2; reject mixed/unknown aspects without invoking accessors. Journals store snapshots, not complete text, so neither an unreleased version nor a schema fix permits rewriting old codecs. The second frontmatter capture layout quotes unknown index as YAML "?"; the first keeps its original bytes, including unquoted ?. Fresh headers begin index, run, state, then admitted kind:primary/diagnostic; meaningful metadata and whole source/generation/location references follow. Display index is not member_index or native identity. Raw admitted Markdown follows the closed YAML at the left margin, without #N heading, result:/preview: wrapper, structural list indentation or whole-body literal fence. Known display loss is [N characters omitted] at the cut; no added ellipsis or body clipping flags/counts in YAML. Preserve structured original coverage facts and unknown upstream/fallback completeness/privacy outside metadata; fallback has no primary kind. Visible text is admitted output/final Actor response or error/failure diagnostics, never command metadata or copied command excerpts. Source text_basis remains technical. No routine group windows/status copies, members wrapper, outer counters, Batch caption or standing full-map instruction appears in new model content; captured facts remain journal data. Material whole-result/reference omission, non-done omitted states and a whole inventory reference remain explicit. A single shown row keeps the same shape even when other results were omitted. Complete model content includes all exact references and only the necessary YAML-core packet identity/relative body-marker lengths, without fresh compiler HTML tails, under49152UTF-8 bytes for up to64candidate rows/256captured members. Equal scalar/CRLF-safe text-prefix shares freeze at admission, including service overhead; no redistribution, fixed16KiB result/2KiB preview cap, source recapture or later reallocation. Preserve every saved16KiB/48KiB allowance. Prefix admission must consider full-list/decimal discontinuities rather than miss fitting rows when omission scaffolding shrinks. Whole text has no display-cut marker when complete; known upstream clipping still forbids a full-original-output claim. The source reader selects at most48KiB from the same verified postprivacy observation; source-binding previews stay160code points. Retain chosen packet prefixes, not64independent48KiB copies. Unfit metadata rows keep bounded inventory recovery. Curate/copy/freeze members, arrays, artifacts and bindings; schema DTOs grant no publication permission and phase changes do not mutate member facts. Preserve generation/parent/source identities, exact ranges/hashes and whole references. The completion-only TUI uses independent native Markdown body components and literal Text header/marker/service components, with no global Markdown patch, source/native IO or scheduling authority. Validated compiler header rows alone may hide whole reference/location data in compact view; authored body lookalikes never disappear. Fresh ordinary hints use completion_yaml_core_v1 plus a whole-content digest; validated core lengths derive block positions. Retained completion_frontmatter_v1 hints keep their SHA-256-bound UTF-16 header/body/marker/service blocks and original compiler frames, dense ordered coverage and scalar/CRLF-safe endpoints. Invalid/missing hints and expansion reveal original full Text. These are display/correlation consistency, not authentication/read/action/acceptance/native authority. Malformed frontmatter-shaped stripped history cannot regain identity from a body Batch label or become absence/retry permission; ordinary thematic-break prose retains its legacy path. Retained pre-record codecs keep host rendering; older record/literal codecs keep exact original hints, dynamic fences, count spelling and separators. Fresh ordinary indices remain packet-local; no default stream activation follows. Fresh UI member locations are observed before journal locks after actual current-session selection/recheck, with captured_file_locations and frozen file_navigation. Data-only decoding does not grant current body/source visibility. Location snapshots retain16KiB, outcomes outrank lower-priority references, and each shown record has a whole location row or explicit omission; wholly omitted records stay inventory-covered. Reload/render/phase recovery never refreshes sources or frozen availability. Old absent/current_session_request captures keep their bytes, and optional full-map research stays a separate current-session action. Source/package checks do not prove the loaded host was reloaded.
94
+ - `run-delivery.ts`: owner-scoped durable packet/phase persistence and bounded projections. Fresh ordinary source admission captures presentation_format=ax_records, own-data result_layout=completion_yaml_files_v1 and frozen text_budget, with no presentation selector/excerpt_format; direct and ordinary UI admission share this path. The separate inactive numbered-stream capture still inherits frontmatter_v2; do not change the private default globally or relabel retained captures. Preserve all stored encodings/absence and exact replay bytes/hints, including headings_shared_kinds and frontmatter_v1/v2; reject mixed/unknown aspects without invoking accessors. Journals store snapshots, not complete text, so neither an unreleased version nor a schema fix permits rewriting old codecs. The second frontmatter capture layout quotes unknown index as YAML "?"; the first keeps its original bytes, including unquoted ?. Fresh headers begin index, run, state, then admitted kind:primary/diagnostic; meaningful metadata and whole source/generation/location references follow. Display index is not member_index or native identity. Raw admitted Markdown follows the closed YAML at the left margin, without #N heading, result:/preview: wrapper, structural list indentation or whole-body literal fence. Known display loss is [N characters omitted] at the cut; no added ellipsis or body clipping flags/counts in YAML. Fresh rooted captures keep unknown upstream/fallback completeness/privacy warnings in header text_warnings; only an exact known character-omission marker follows a cut body. Fallback has no primary kind. Retained layouts keep their original marker placement. Visible text is admitted output/final Actor response or error/failure diagnostics, never command metadata or copied command excerpts. Source text_basis remains technical. No routine group windows/status copies, members wrapper, outer counters, Batch caption or standing full-map instruction appears in new model content; captured facts remain journal data. Material whole-result/reference omission, non-done omitted states and a whole inventory reference remain explicit. A single shown row keeps the same shape even when other results were omitted. Complete model content includes all exact references and only the necessary YAML-core packet identity/relative body-marker lengths, without fresh compiler HTML tails, under49152UTF-8 bytes for up to64candidate rows/256captured members. Equal scalar/CRLF-safe text-prefix shares freeze at admission, including service overhead; no redistribution, fixed16KiB result/2KiB preview cap, source recapture or later reallocation. Preserve every saved16KiB/48KiB allowance. Prefix admission must consider full-list/decimal discontinuities rather than miss fitting rows when omission scaffolding shrinks. Whole text has no display-cut marker when complete; known upstream clipping still forbids a full-original-output claim. The source reader selects at most48KiB from the same verified postprivacy observation; source-binding previews stay160code points. Retain chosen packet prefixes, not64independent48KiB copies. Unfit metadata rows keep bounded inventory recovery. Curate/copy/freeze members, arrays, artifacts and bindings; schema DTOs grant no publication permission and phase changes do not mutate member facts. Preserve generation/parent/source identities, exact ranges/hashes and whole references. The completion-only TUI uses independent native Markdown body components and literal Text header/marker/service components, with no global Markdown patch, source/native IO or scheduling authority. New rooted captures expose files.groups in the header: one literal root per group, relative entry paths, English role/purpose and read_first group/entry indices. Reconstruct original selected references exactly; never normalize dot/symlink routes, guess cwd or treat declared targets as produced. Unresolved paths retain path_basis=as_recorded/base_unavailable with a null root and no recommendation. Observation.group binds its original mutable Run-directory facts. All packet/inventory/whole-row omission metadata renders in the first header, not a service footer; no runtime text follows the last body except its known cut marker. Retained core-v1 captures keep their original references/locations and compact hiding rules; authored body lookalikes never disappear. Fresh ordinary hints use completion_yaml_core_v1 plus a whole-content digest; validated core lengths derive block positions. Retained completion_frontmatter_v1 hints keep their SHA-256-bound UTF-16 header/body/marker/service blocks and original compiler frames, dense ordered coverage and scalar/CRLF-safe endpoints. Invalid/missing hints and expansion reveal original full Text. These are display/correlation consistency, not authentication/read/action/acceptance/native authority. Malformed frontmatter-shaped stripped history cannot regain identity from a body Batch label or become absence/retry permission; ordinary thematic-break prose retains its legacy path. Retained pre-record codecs keep host rendering; older record/literal codecs keep exact original hints, dynamic fences, count spelling and separators. Fresh ordinary indices remain packet-local; no default stream activation follows. Fresh UI member locations are observed before journal locks after actual current-session selection/recheck, with captured_file_locations and frozen file_navigation. Data-only decoding does not grant current body/source visibility. Location snapshots retain16KiB, outcomes outrank lower-priority references, and each shown record has a whole location row or explicit omission; wholly omitted records stay inventory-covered. Reload/render/phase recovery never refreshes sources or frozen availability. Old absent/current_session_request captures keep their bytes, and optional full-map research stays a separate current-session action. Source/package checks do not prove the loaded host was reloaded.
95
95
  - automatic draft/tool review domains: structurally redacted model review, journaled mutation, lineage, recovery, and explicit retry/reset safety.
96
96
 
97
97
  The bundled Skill Recipe dependency DAG is `artifacts → actors, swarm` and `project-work → actors, artifacts, swarm`; `actors`, `music-player`, `swarm`, and `recipe-memory` have no cross-Skill Recipe dependencies.
package/BACKLOG.md CHANGED
@@ -18,7 +18,7 @@ Outcome: JSON structured inputs, block-YAML runtime-output metadata and unchange
18
18
 
19
19
  Exit: New owned runtime projections use YAML without pseudo-records or serialized JSON objects: bare when metadata-only, `---`-delimited headers only when a separate text body follows. Literal content, meaning, source/privacy bounds and saved messages remain intact. Service-carrier adoption has its own evidence gate; do not delete current framing to simulate completion.
20
20
 
21
- - [ ] **F1.7 — Accept the rollout on a loaded host.** Source/headless audit is done: one shared framing owner keeps exactly one host-separation blank line on migrated paths, no runtime-authored object dump or pseudo-record remains in the migrated set, history/literal bodies are unchanged, and source/compiled/package parity passes. Remainder is the permitted loaded terminal/phone observation of one rollout candidate, which needs the same separate authorization as U1; keep capture codecs and live claims distinct and claim no automatic default activation.
21
+ - [ ] **F1.7 — Accept the rollout on a loaded host.** Source/headless audit is done: one shared framing owner keeps exactly one host-separation blank line on migrated paths, no runtime-authored object dump or pseudo-record remains in the migrated set, history/literal bodies are unchanged, and source/compiled/package parity passes. Remainder is the permitted loaded terminal/phone observation of one rollout candidate, including rooted completion headers, English read-first guidance and no post-Markdown runtime footer, which needs the same separate authorization as U1; keep capture codecs and live claims distinct and claim no automatic default activation.
22
22
 
23
23
  ### U1 — Loaded UI/AX acceptance
24
24
 
package/CHANGELOG.md CHANGED
@@ -4,6 +4,10 @@
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## 0.57.1: Rooted Completion Headers
8
+
9
+ - `Completion Headers`: New captures keep all runtime metadata above the Actor Markdown, with no service/file footer. File references share literal roots with relative entries, English purposes and a read-first pointer. External roots and unresolved bases stay explicit; declarations do not prove production. Known cut counts remain at the cut. Original Markdown, source/generation/privacy fences, shared budgets and exact historical replay are preserved.
10
+
7
11
  ## 0.57.0: YAML Runtime Output
8
12
 
9
13
  - `Control and Inspection`: Compact Control receipts and inspect views/refusals use block YAML with native lists, whole-value omissions and conservative delivery/handling facts. Generated tool schemas use YAML when renderable, retaining the legacy JSON fallback and explicit verbose JSON. Recipe view=registry aliases summary. Large argument groups and next actions stay bounded without breaking verbose inspection.
package/README.md CHANGED
@@ -228,6 +228,8 @@ Core files:
228
228
 
229
229
  The runtime preserves owner filtering, process-identity verification, lifecycle locking, shutdown kill independent of actor-local Control capacity, terminal reconciliation, bounded captures, owned Pi sessions, path containment, and redaction. Trace/Control quotas do not constrain user-declared artifacts, repositories, media sources, complete captures, or actor-owned workload state. Restart clears generation-local Trace, Control, endpoint, execution, and terminal evidence; archive preserves the bounded tree, while prune preserves only requested artifacts.
230
230
 
231
+ New completion captures in 0.57.1 keep runtime metadata above the Actor Markdown, with no service/file footer. [Rooted completion files](docs/agent-experience.md#rooted-completion-files) show one explicit path base per group, relative entries, English purpose labels and a read-first pointer. External paths have separate roots; unresolved bases stay explicit. Existing captured messages keep their original layout.
232
+
231
233
  ## Actor Inspector
232
234
 
233
235
  Open the owner-filtered TUI:
@@ -66,7 +66,7 @@ export interface RunCompletionBatch {
66
66
  /** Retained singleton capture; absence preserves older indexed bytes. Never a new-capture selector. */
67
67
  readonly single_result?: true;
68
68
  /** Captured record-list shape; no public format/version choice or source authority. */
69
- readonly result_layout?: "records" | "run_headers" | "headings" | "headings_flat_omissions" | "headings_outcomes" | "headings_shared_results" | "headings_shared_kinds" | "frontmatter_v1" | "frontmatter_v2" | "completion_yaml_core_v1";
69
+ readonly result_layout?: "records" | "run_headers" | "headings" | "headings_flat_omissions" | "headings_outcomes" | "headings_shared_results" | "headings_shared_kinds" | "frontmatter_v1" | "frontmatter_v2" | "completion_yaml_core_v1" | "completion_yaml_files_v1";
70
70
  /** Immutable scope/order/range data, not a caller-selected format or allocation authority. */
71
71
  readonly numbering?: RunCompletionNumbering;
72
72
  /** Formatting version/data only; no recipient ownership, read or publication capability. */
@@ -278,8 +278,11 @@ function parseInventorySource(value, batch) {
278
278
  function isFrontmatterCompletionLayout(layout) {
279
279
  return layout === "frontmatter_v1" || layout === "frontmatter_v2";
280
280
  }
281
+ function isYamlCompletionLayout(layout) {
282
+ return layout === "completion_yaml_core_v1" || layout === "completion_yaml_files_v1";
283
+ }
281
284
  function isSharedCompletionLayout(layout) {
282
- return layout === "headings_shared_results" || layout === "headings_shared_kinds" || layout === "completion_yaml_core_v1" || isFrontmatterCompletionLayout(layout);
285
+ return layout === "headings_shared_results" || layout === "headings_shared_kinds" || isYamlCompletionLayout(layout) || isFrontmatterCompletionLayout(layout);
283
286
  }
284
287
  function parseBatch(value) {
285
288
  const record = asRecord(value, "Completion batch");
@@ -322,7 +325,7 @@ function parseBatch(value) {
322
325
  throw new Error("Completion shared text budget is invalid");
323
326
  }
324
327
  const numberingDescriptor = Object.getOwnPropertyDescriptor(record, "numbering");
325
- if (numberingDescriptor && (resultLayout === "completion_yaml_core_v1" || !Object.hasOwn(numberingDescriptor, "value") || presentationFormat !== "ax_records" || (resultLayout !== "headings" && resultLayout !== "headings_flat_omissions" && resultLayout !== "headings_outcomes" && !isSharedCompletionLayout(resultLayout)))) {
328
+ if (numberingDescriptor && (isYamlCompletionLayout(resultLayout) || !Object.hasOwn(numberingDescriptor, "value") || presentationFormat !== "ax_records" || (resultLayout !== "headings" && resultLayout !== "headings_flat_omissions" && resultLayout !== "headings_outcomes" && !isSharedCompletionLayout(resultLayout)))) {
326
329
  throw new Error("Completion numbering requires a canonical captured heading layout");
327
330
  }
328
331
  const numbering = numberingDescriptor ? parseCompletionNumbering(numberingDescriptor.value, members.length) : undefined;
@@ -685,7 +688,7 @@ export function requestRunCompletionStream(input) {
685
688
  });
686
689
  }
687
690
  export function admitRunCompletionBatch(input) {
688
- return captureCompletionBatch(input, false, "completion_yaml_core_v1");
691
+ return captureCompletionBatch(input, false, "completion_yaml_files_v1");
689
692
  }
690
693
  /** Kernel-only opt-in; ordinary Pi capture stays fenced until session/lifecycle integration is admitted. */
691
694
  export function captureRunCompletionStreamBatch(input) {
@@ -693,7 +696,7 @@ export function captureRunCompletionStreamBatch(input) {
693
696
  }
694
697
  /** Private ordinary candidate composition; stream capture retains its separately gated codec. */
695
698
  export function captureRunCompletionYamlCandidateBatch(input) {
696
- return captureCompletionBatch(input, false, "completion_yaml_core_v1");
699
+ return captureCompletionBatch(input, false, "completion_yaml_files_v1");
697
700
  }
698
701
  function captureCompletionBatch(input, numbered, layout = "frontmatter_v2") {
699
702
  const now = (input.now ?? new Date()).toISOString();
@@ -710,7 +713,7 @@ function captureCompletionBatch(input, numbered, layout = "frontmatter_v2") {
710
713
  members: input.members,
711
714
  phase: "pending",
712
715
  });
713
- const draft = layout === "completion_yaml_core_v1"
716
+ const draft = isYamlCompletionLayout(layout)
714
717
  ? parseBatch({ ...captured, result_layout: layout }) : { ...captured, result_layout: layout };
715
718
  return mutateJournal(input.tempDir, input.ownerId, (journal) => {
716
719
  let batch = draft;
@@ -741,10 +744,10 @@ function captureCompletionBatch(input, numbered, layout = "frontmatter_v2") {
741
744
  else if (journal.completion_stream) {
742
745
  throw new Error("Completion stream capture requires the numbered kernel path; stream state is retained");
743
746
  }
744
- if (layout !== "completion_yaml_core_v1")
747
+ if (!isYamlCompletionLayout(layout))
745
748
  batch = retainSharedCompletionTexts(batch);
746
749
  if (projectCompletionBatchMessage(batch).membersShown === batch.members.length) {
747
- if (layout === "completion_yaml_core_v1")
750
+ if (isYamlCompletionLayout(layout))
748
751
  batch = retainSharedCompletionTexts(batch);
749
752
  journal.completion_batch = batch;
750
753
  return batch;
@@ -1281,7 +1284,7 @@ function isRoutineCompletionSummary(member) {
1281
1284
  return member.summary === (member.status === "done" ? "Run completed." : `Run ${member.status}.`);
1282
1285
  }
1283
1286
  function completionRecordRow(member, index, byIdentity, flat = false, layout, textBudget) {
1284
- const frontmatter = isFrontmatterCompletionLayout(layout) || layout === "completion_yaml_core_v1";
1287
+ const frontmatter = isFrontmatterCompletionLayout(layout) || isYamlCompletionLayout(layout);
1285
1288
  const simpleKinds = frontmatter || layout === "headings_shared_kinds", shared = isSharedCompletionLayout(layout);
1286
1289
  const outcomes = shared || layout === "headings_outcomes", directOmission = outcomes || layout === "headings_flat_omissions";
1287
1290
  const run = member.run.startsWith("run:") ? member.run.slice(4) : member.run;
@@ -1604,8 +1607,97 @@ function completionYamlReferences(row) {
1604
1607
  })) };
1605
1608
  return technical;
1606
1609
  }
1610
+ /** Split selected paths without normalize/resolve/relative: dot and symlink routes must not be rewritten. */
1611
+ function rootedCompletionPath(path, runRoot) {
1612
+ if (typeof path !== "string" || !path.isWellFormed())
1613
+ return undefined;
1614
+ const windows = /^(?:[A-Za-z]:[\\/]|\\\\[^\\/]+[\\/][^\\/]+[\\/])/u.test(path);
1615
+ const separator = windows ? /[\\/]/u : /\//u;
1616
+ if (!windows && !path.startsWith("/"))
1617
+ return undefined;
1618
+ if (path.split(separator).some(part => part === "." || part === ".."))
1619
+ return undefined;
1620
+ if (runRoot && path.startsWith(runRoot)) {
1621
+ const tail = path.slice(runRoot.length);
1622
+ if (separator.test(runRoot.slice(-1)) ? tail.length > 0 : separator.test(tail[0] ?? "")) {
1623
+ const relative = separator.test(runRoot.slice(-1)) ? tail : tail.slice(1);
1624
+ if (relative && !separator.test(relative[0]))
1625
+ return { root: runRoot, path: relative };
1626
+ }
1627
+ }
1628
+ let split = -1;
1629
+ for (let i = 0; i < path.length; i++)
1630
+ if (separator.test(path[i]))
1631
+ split = i;
1632
+ if (split < 0 || split === path.length - 1)
1633
+ return undefined;
1634
+ const end = split === 0 || (windows && split === 2 && path[1] === ":") ? split + 1 : split;
1635
+ return { root: path.slice(0, end), path: path.slice(split + 1) };
1636
+ }
1637
+ /** Body-free, read-free navigation over already selected references. Roots are presentation bases, not containment proof. */
1638
+ function completionRootedFiles(row, member, locations) {
1639
+ const technical = completionYamlReferences(row), files = {};
1640
+ const groups = [];
1641
+ const runRoot = locations?.state === "available" ? locations.directory : undefined;
1642
+ const group = (root) => {
1643
+ const found = groups.findIndex(item => item.root === root);
1644
+ if (found >= 0)
1645
+ return found;
1646
+ groups.push({ root, entries: [] });
1647
+ return groups.length - 1;
1648
+ };
1649
+ let priority = Infinity;
1650
+ const add = (path, entry, rank = Infinity, base) => {
1651
+ const selected = rootedCompletionPath(path, runRoot);
1652
+ const index = group(selected?.root ?? (base === undefined ? null : completionYamlString(base)));
1653
+ const selectedPath = selected?.path ?? path;
1654
+ groups[index].entries.push({ ...entry, path: selectedPath,
1655
+ ...(!selected && base === undefined ? { path_basis: "as_recorded", base_unavailable: true } : {}) });
1656
+ if (selected && rank < priority) {
1657
+ priority = rank;
1658
+ files.read_first = { group: index, entry: groups[index].entries.length - 1 };
1659
+ }
1660
+ };
1661
+ for (const [role, purpose, rank] of [
1662
+ ["primary", "Full result text", 0], ["diagnostic_metadata", "Recorded error and command metadata", 1],
1663
+ ["artifact_inventory", "Declared artifact inventory; target availability unproven", 2],
1664
+ ]) {
1665
+ const detail = technical[role];
1666
+ if (!detail)
1667
+ continue;
1668
+ const { source: rawSource, ...facts } = detail;
1669
+ const { path, ...binding } = rawSource;
1670
+ add(path, { role, purpose, ...facts, source: binding }, rank);
1671
+ delete technical[role];
1672
+ }
1673
+ const artifacts = technical.artifacts;
1674
+ if (artifacts) {
1675
+ for (const item of artifacts.declarations)
1676
+ add(item.path, { role: "artifact", purpose: "Declared artifact", name: item.name, scope: artifacts.scope, state: "declared" });
1677
+ delete technical.artifacts;
1678
+ }
1679
+ if (locations?.state === "available") {
1680
+ const { directory, files: selectedFiles, ...observation } = locations;
1681
+ files.observation = { ...observation, run: completionYamlString(locations.run), run_instance_id: completionYamlString(locations.run_instance_id),
1682
+ group: group(completionYamlString(directory)) };
1683
+ for (const item of selectedFiles) {
1684
+ const { path, ...facts } = item;
1685
+ const purpose = item.role === "result" ? "Recorded result metadata" : item.role === "execution" ? "Recorded execution and capture locations" : "Recorded Run file";
1686
+ add(typeof path === "string" ? completionYamlString(path) : null, { ...facts, purpose }, item.state === "present" && item.role === "result" ? 3 : item.state === "present" && item.role === "execution" ? 4 : Infinity, directory);
1687
+ }
1688
+ }
1689
+ else if (locations)
1690
+ files.observation = { ...locations, run: completionYamlString(member.run), run_instance_id: completionYamlString(member.run_instance_id) };
1691
+ if (groups.length) {
1692
+ files.groups = groups;
1693
+ }
1694
+ if (Object.keys(technical).length)
1695
+ files.notes = technical;
1696
+ return files;
1697
+ }
1607
1698
  function prepareCompletionYamlProjection(safe, candidates, references, ordered) {
1608
1699
  const packet = { batchId: safe.batch_id, records: [] };
1700
+ const rooted = safe.result_layout === "completion_yaml_files_v1";
1609
1701
  if (!safe.batch_id.isWellFormed())
1610
1702
  return { state: "unsupported" };
1611
1703
  for (const [index, { row, location }] of candidates.entries()) {
@@ -1630,18 +1722,24 @@ function prepareCompletionYamlProjection(safe, candidates, references, ordered)
1630
1722
  else
1631
1723
  metadata[key] = completionYamlString(value);
1632
1724
  }
1633
- const technical = completionYamlReferences(row);
1634
- if (Object.keys(technical).length)
1635
- metadata.references = technical;
1636
- if (references.has(index) && location) {
1637
- const navigation = safe.file_navigation.find(item => safe.members[item.member_index] === member);
1638
- // Navigation is already decoded native data, not the JSON display field.
1639
- const locations = navigation.locations;
1640
- metadata.run_files = { run: completionYamlString(member.run), run_instance_id: completionYamlString(member.run_instance_id),
1641
- locations: locations.state === "available" ? { ...locations, run: completionYamlString(locations.run),
1642
- run_instance_id: completionYamlString(locations.run_instance_id), directory: completionYamlString(locations.directory),
1643
- files: locations.files.map(file => ({ ...file, ...(typeof file.path === "string" ? { path: completionYamlString(file.path) } : {}) })) }
1644
- : { ...locations } };
1725
+ const navigation = references.has(index) && location
1726
+ ? safe.file_navigation.find(item => safe.members[item.member_index] === member).locations : undefined;
1727
+ if (rooted) {
1728
+ const files = completionRootedFiles(row, member, navigation);
1729
+ if (Object.keys(files).length)
1730
+ metadata.files = files;
1731
+ }
1732
+ else {
1733
+ const technical = completionYamlReferences(row);
1734
+ if (Object.keys(technical).length)
1735
+ metadata.references = technical;
1736
+ if (navigation) {
1737
+ metadata.run_files = { run: completionYamlString(member.run), run_instance_id: completionYamlString(member.run_instance_id),
1738
+ locations: navigation.state === "available" ? { ...navigation, run: completionYamlString(navigation.run),
1739
+ run_instance_id: completionYamlString(navigation.run_instance_id), directory: completionYamlString(navigation.directory),
1740
+ files: navigation.files.map(file => ({ ...file, ...(typeof file.path === "string" ? { path: completionYamlString(file.path) } : {}) })) }
1741
+ : { ...navigation } };
1742
+ }
1645
1743
  }
1646
1744
  const parts = [];
1647
1745
  const add = (part) => { if (parts.length)
@@ -1650,13 +1748,22 @@ function prepareCompletionYamlProjection(safe, candidates, references, ordered)
1650
1748
  if (piece.block) {
1651
1749
  if (!piece.text.isWellFormed())
1652
1750
  return { state: "unsupported" };
1653
- add(piece.block === "body" ? { body: piece.text } : { marker: piece.text });
1751
+ if (rooted && piece.block === "marker" && !/^\[[0-9]+ characters omitted\]$/u.test(piece.text)) {
1752
+ metadata.text_warnings ??= [];
1753
+ metadata.text_warnings.push(piece.text);
1754
+ }
1755
+ else
1756
+ add(piece.block === "body" ? { body: piece.text } : { marker: piece.text });
1654
1757
  }
1655
- if (safe.file_navigation !== undefined && !references.has(index))
1656
- add({ marker: "Run-file reference omitted (packet byte limit)." });
1758
+ if (safe.file_navigation !== undefined && !references.has(index)) {
1759
+ if (rooted)
1760
+ metadata.run_files_omission = { reason: "packet_byte_limit", shown: 0, omitted: 1, total: 1 };
1761
+ else
1762
+ add({ marker: "Run-file reference omitted (packet byte limit)." });
1763
+ }
1657
1764
  packet.records.push({ metadata, parts });
1658
1765
  }
1659
- const service = {};
1766
+ const service = rooted ? { header_layout: "rooted_files_v1" } : {};
1660
1767
  const omitted = safe.members.length - candidates.length;
1661
1768
  if (omitted) {
1662
1769
  service.omitted_results = omitted;
@@ -1676,8 +1783,11 @@ function prepareCompletionYamlProjection(safe, candidates, references, ordered)
1676
1783
  if (safe.numbering.kind === "unavailable")
1677
1784
  service.numbering_unavailable = safe.numbering.reason;
1678
1785
  }
1679
- if (safe.inventory_source)
1680
- service.result_inventory = { ...safe.inventory_source, path: completionYamlString(safe.inventory_source.path) };
1786
+ if (safe.inventory_source) {
1787
+ const path = rooted ? rootedCompletionPath(safe.inventory_source.path) : undefined;
1788
+ service.result_inventory = { ...safe.inventory_source,
1789
+ ...(path ? { root: path.root, path: path.path } : { path: completionYamlString(safe.inventory_source.path) }) };
1790
+ }
1681
1791
  if (Object.keys(service).length)
1682
1792
  packet.service = service;
1683
1793
  const chunks = [];
@@ -1737,7 +1847,7 @@ export function projectRunCompletionYamlPrototype(batch) {
1737
1847
  throw error;
1738
1848
  }
1739
1849
  }
1740
- function projectCompletionRecords(safe, assembler = safe.result_layout === "completion_yaml_core_v1" ? "yaml" : "legacy") {
1850
+ function projectCompletionRecords(safe, assembler = isYamlCompletionLayout(safe.result_layout) ? "yaml" : "legacy") {
1741
1851
  const frontmatter = isFrontmatterCompletionLayout(safe.result_layout) || assembler === "yaml";
1742
1852
  const shared = isSharedCompletionLayout(safe.result_layout);
1743
1853
  const maxBytes = shared ? Limits.RUN_COMPLETION_MODEL_MAX_BYTES : Limits.RUN_DELIVERY_MODEL_MAX_BYTES;
@@ -2024,7 +2134,7 @@ export function projectRunCompletionBatchPresentation(batch) {
2024
2134
  if (safe.presentation_format !== "ax_records" && safe.presentation_format !== "ax_records_v3")
2025
2135
  return { content: projectCompletionBatchMessage(safe).message };
2026
2136
  const result = safe.result_layout !== undefined ? projectCompletionRecords(safe) : projectRetainedRecordCompletionBatch(safe);
2027
- if (safe.result_layout === "completion_yaml_core_v1")
2137
+ if (isYamlCompletionLayout(safe.result_layout))
2028
2138
  return { content: result.message, presentation: Object.freeze({
2029
2139
  format: "completion_yaml_core_v1", content_sha256: createHash("sha256").update(result.message).digest("hex"),
2030
2140
  }) };
@@ -2192,10 +2302,14 @@ export function readRunCompletionPresentation(content, value) {
2192
2302
  hint.content_sha256 !== createHash("sha256").update(content).digest("hex"))
2193
2303
  return full;
2194
2304
  const segments = [];
2305
+ const rooted = core.packet.service?.header_layout === "rooted_files_v1";
2306
+ const facts = Object.fromEntries(Object.entries(core.packet.service ?? {}).filter(([key]) => key !== "header_layout"));
2195
2307
  for (const [index, record] of core.packet.records.entries()) {
2196
2308
  if (index)
2197
2309
  segments.push({ kind: "separator", text: "\n" });
2198
- const metadata = Object.fromEntries(Object.entries(record.metadata).filter(([key]) => key !== "references" && key !== "run_files"));
2310
+ const metadata = Object.fromEntries(Object.entries(record.metadata).filter(([key]) => rooted || (key !== "references" && key !== "run_files")));
2311
+ if (rooted && index === 0 && Object.keys(facts).length)
2312
+ metadata.delivery = facts;
2199
2313
  const header = renderYamlMetadata(metadata, completionYamlMaxBytes);
2200
2314
  if (header.state !== "available")
2201
2315
  return full;
@@ -2203,13 +2317,13 @@ export function readRunCompletionPresentation(content, value) {
2203
2317
  for (const part of record.parts)
2204
2318
  segments.push("body" in part ? { kind: "body", text: part.body } : { kind: "marker", text: part.marker });
2205
2319
  }
2206
- if (core.packet.service) {
2207
- const service = renderYamlMetadata(core.packet.service, completionYamlMaxBytes);
2320
+ if (core.packet.service && (!rooted || !core.packet.records.length)) {
2321
+ const service = renderYamlMetadata(rooted ? facts : core.packet.service, completionYamlMaxBytes);
2208
2322
  if (service.state !== "available")
2209
2323
  return full;
2210
2324
  if (segments.length)
2211
2325
  segments.push({ kind: "separator", text: "\n" });
2212
- segments.push({ kind: "service", text: service.text.replace(/\n$/u, "") });
2326
+ segments.push({ kind: rooted ? "header" : "service", text: service.text.replace(/\n$/u, "") });
2213
2327
  }
2214
2328
  return { text: segments.map(segment => segment.text).join("\n"), compact: true, records: true, yaml: true,
2215
2329
  segments: Object.freeze(segments.map(segment => Object.freeze(segment))) };
@@ -151,7 +151,7 @@ Run = Recipe + Trace + Control
151
151
  5. Send `message` only for an action declared and consumed by that controlled Recipe.
152
152
  6. Use terminal state, result, declared artifacts, and execution evidence to prove completion. When an outcome includes a retained primary-source, declaration-inventory or diagnostic-metadata reference, use that exact reference for further reading, not guessed captures or sibling files. Literal previews may be clipped; their field/range/counts describe what was shown. Diagnostic sources contain recorded command/error/failure-reason metadata only, not complete primary output; other recorded fields may be referenced without being shown. Artifact inventories list declarations only: they do not assert that target files exist or were produced, or grant body-read permission. Explicit unavailability has no guessed legacy body/path fallback.
153
153
 
154
- Compact launch receipts include `run_files` as nested block YAML containing the exact selected observed location values, labeled observed locations/mutable for the exact launched Run generation when the current session and physical identity agree; otherwise they report unavailability or whole-row omission. Machine `file_navigation` details stay JSON-compatible; saved terminal messages retain their own original encodings. Selectively ordinary-read those starting locations when needed; layout/size hints are not body, privacy, terminal or native proof. No evidence bodies or session-wide catalog map are read to build this row. New terminal packets also freeze bounded location rows for captured completion members at fresh current-session admission. Each shown result keeps its whole Run-file row or explicit per-record omission; wholly omitted results stay covered by result omission/inventory. This describes Run-row coverage, not a complete file/tree inventory. Older captured formats retain their original shown/omitted/total counters; unavailability remains explicit. Ordinary-read selected paths only when needed. Packet reload/render never refreshes sources, and old absent/request-only formats keep their text. Source/npm SDK verifies an explicitly requested ordinary read from a delivered terminal result path; this is research, never routine completion polling or new primary/privacy/clock/native authority. Use the request only for file investigation, not routine completion/status polling. Copied locations/hints remain data, never transferred scope; older batches keep their original text.
154
+ Compact launch receipts include `run_files` as nested block YAML containing the exact selected observed location values, labeled observed locations/mutable for the exact launched Run generation when the current session and physical identity agree; otherwise they report unavailability or whole-row omission. Machine `file_navigation` details stay JSON-compatible; saved terminal messages retain their own original encodings. Selectively ordinary-read those starting locations when needed; layout/size hints are not body, privacy, terminal or native proof. No evidence bodies or session-wide catalog map are read to build this row. New terminal packets also freeze bounded location rows for captured completion members at fresh current-session admission. Fresh rooted completion headers group paths under literal roots with relative entries, English purposes and a read_first group/entry pointer; no cwd guess, source refresh or automatic read follows. Unknown bases stay explicit. Runtime navigation/omission/inventory facts remain above the Actor Markdown, not in a footer; retained packets keep their original projection. Each shown result keeps its whole Run-file row or explicit per-record omission; wholly omitted results stay covered by result omission/inventory. This describes Run-row coverage, not a complete file/tree inventory. Older captured formats retain their original shown/omitted/total counters; unavailability remains explicit. Ordinary-read selected paths only when needed. Packet reload/render never refreshes sources, and old absent/request-only formats keep their text. Source/npm SDK verifies an explicitly requested ordinary read from a delivered terminal result path; this is research, never routine completion polling or new primary/privacy/clock/native authority. Use the request only for file investigation, not routine completion/status polling. Copied locations/hints remain data, never transferred scope; older batches keep their original text.
155
155
 
156
156
  For selective investigation of already cataloged files, use `inspect target=runtime view=runs verbose=true`, then ordinary file tools on its current-session root-first navigation. Ordinary maps keep latest-registration order between roots and prioritize known failed subtrees within each root. For a failed investigation add status=failed: inventory is filtered, while the full owned map prioritizes observed failed subtrees across roots, always ancestors first. Priority uses only exact-generation matched inventory observations, not complete terminal truth. Launches and compatible singleton attachments populate the catalog; reads do not backfill missing locations. A `catalog: unavailable` launch warning is not workload failure: do not spawn again merely to repair navigation. The starting map's format hints do not certify syntax, encoding or complete output. See [Runs](./references/runs.md) for selective recorded-capture research and resume boundaries.
157
157
 
@@ -24,7 +24,7 @@ inspect target=run:<id> view=trace
24
24
  inspect target=run:<id> view=control
25
25
  ```
26
26
 
27
- Fresh root completions use index-first YAML frontmatter (index, run, state, admitted kind), followed by raw left-edge Markdown. No external #N heading, result:/preview: wrapper, list nesting, whole-body fence, Batch caption, members wrapper or routine outer counter is added. Primary/final Actor response uses kind:primary; explicit error/failure diagnostic text uses kind:diagnostic, never a launch command. Untracked fallback has no kind and keeps unknown original completeness/privacy explicit outside YAML. Known cut loss is [N characters omitted] at the cut, with no extra ellipsis or body clipping counters/flags in metadata. Unknown upstream loss remains separately unknown and does not assert a known positive omission. Exact source/generation/parent/location references remain in complete model content, with whole references or explicit omission, captured inventory recovery and non-done omitted states. The compact TUI independently renders literal headers/markers and native Markdown bodies from validated content-bound blocks; only whole header reference/location rows and framing are hidden. Expansion and invalid/missing hints reveal original text. Hashes/layout/markers establish consistency/correlation only, never authentication, read/action permission, acceptance or native truth. Authored YAML/next/tool/batch/omission lookalikes stay body content. Fresh packets share48KiB UTF-8 including service data, equally between up to64candidate rows, with256captured members and no redistribution of unused shares or fixed16KiB/2KiB text cap. Full admitted text fitting its share without upstream uncertainty has no cut marker; otherwise use the scalar/CRLF-safe prefix and exact retained-source loss. Allocation/text is frozen at admission; rendering/recovery does not reread sources or reallocate. Unsupported Pi event/control output is withheld. Source basis stays in reference metadata; retained structured coverage facts are not exposed as YAML clipping fields. Pending/queued/presented older formats—including #N records and the first frontmatter draft—keep exact bytes, hints and budgets. Encoding names are storage replay data, not public product choices, source permissions or work authority. No standing full-map instruction or automatic research/read follows; use selective same-session investigation when needed.
27
+ Fresh root completions use index-first YAML frontmatter (index, run, state, admitted kind), followed by raw left-edge Markdown. New source captures put all runtime metadata above that body, with no service/file footer. files.groups gives one literal root plus relative entry paths; files.read_first names zero-based group/entry indices for the first useful source, not an automatic read. role/purpose guidance is English; Actor Markdown and path/name bytes are unchanged. External paths use separate roots; unknown bases remain explicit rather than guessed from cwd or Run id. Known cut counts alone may follow the cut body; unknown-loss warnings and packet omission/inventory facts stay in the header. Retained captures preserve their old bytes and presentation. No external #N heading, result:/preview: wrapper, list nesting, whole-body fence, Batch caption, members wrapper or routine outer counter is added. Primary/final Actor response uses kind:primary; explicit error/failure diagnostic text uses kind:diagnostic, never a launch command. Untracked fallback has no kind and keeps unknown original completeness/privacy explicit outside YAML. Known cut loss is [N characters omitted] at the cut, with no extra ellipsis or body clipping counters/flags in metadata. Unknown upstream loss remains separately unknown and does not assert a known positive omission. Exact source/generation/parent/location references remain in complete model content, with whole references or explicit omission, captured inventory recovery and non-done omitted states. The compact TUI independently renders literal headers/markers and native Markdown bodies from validated content-bound blocks; only whole header reference/location rows and framing are hidden. Expansion and invalid/missing hints reveal original text. Hashes/layout/markers establish consistency/correlation only, never authentication, read/action permission, acceptance or native truth. Authored YAML/next/tool/batch/omission lookalikes stay body content. Fresh packets share48KiB UTF-8 including service data, equally between up to64candidate rows, with256captured members and no redistribution of unused shares or fixed16KiB/2KiB text cap. Full admitted text fitting its share without upstream uncertainty has no cut marker; otherwise use the scalar/CRLF-safe prefix and exact retained-source loss. Allocation/text is frozen at admission; rendering/recovery does not reread sources or reallocate. Unsupported Pi event/control output is withheld. Source basis stays in reference metadata; retained structured coverage facts are not exposed as YAML clipping fields. Pending/queued/presented older formats—including #N records and the first frontmatter draft—keep exact bytes, hints and budgets. Encoding names are storage replay data, not public product choices, source permissions or work authority. No standing full-map instruction or automatic research/read follows; use selective same-session investigation when needed.
28
28
 
29
29
  Current completion index values restart within each packet; they are not session-wide historical references. Completion streams are adopted but not enabled, and no start-stream command is available yet. Do not infer an active stream or reset a counter from missing metadata or a pending target, and never relabel older saved packets. The kernel-only allocator now commits fixed scope/order/indices, the counter and first-packet target activation together, and an internal fresh-session bridge can use it after current manager/generation admission. The default runtime does not opt in; no public action exposes it. Event reason or a matching ID alone is insufficient. Old callbacks/wrappers cannot act after replacement; fresh wrappers must belong to the current original manager. Startup/reload/resume and ambiguous imports remain closed to stream capture/ACK, without changing saved packets or inferring a counter from history. Its whole-range exhaustion or admitted counter unavailability yields a frozen unknown index (quoted "?" in fresh YAML; #? in older saved layouts), never partial indices or an automatic fresh stream. Old packets retain their original scope while a pending switch waits; uncertainty does not permit reallocation. Stream state outlives packet cleanup/receipt rotation. Malformed/missing state remains refused, not a zero counter or proof of non-connection.
30
30
 
@@ -4,9 +4,9 @@ Status: Adopted project-wide design standard. The operator has selected **JSON i
4
4
 
5
5
  ## One first AX contract
6
6
 
7
- AX is one canonical Agent Experience being prepared for its first release, not a product family of numbered drafts or user/model-selectable formats. The selected target is YAML metadata plus optional opaque authored content; the former Markdown-list key/value grammar is an implemented pre-unification layout, not another target to preserve for new output. Ordinary source and normally built package Batch admission now capture ax_records/completion_yaml_core_v1, and fresh attention/steer use typed block-YAML metadata plus opaque raw body text. The inactive numbered-stream path and saved frontmatter_v1/v2 retain their older layouts. Bounded source/compiled/actual-default accepted-path evidence exists; it does not establish default-disk, global lifetime-policy or loaded-host acceptance. Remaining rollout is tracked in [BACKLOG.md](../BACKLOG.md).
7
+ AX is one canonical Agent Experience being prepared for its first release, not a product family of numbered drafts or user/model-selectable formats. The selected target is YAML metadata plus optional opaque authored content; the former Markdown-list key/value grammar is an implemented pre-unification layout, not another target to preserve for new output. Ordinary source and normally built package Batch admission now capture ax_records/completion_yaml_files_v1 over the unchanged completion_yaml_core_v1 carrier, and fresh attention/steer use typed block-YAML metadata plus opaque raw body text. The inactive numbered-stream path and saved frontmatter_v1/v2 retain their older layouts. Bounded source/compiled/actual-default accepted-path evidence exists; it does not establish default-disk, global lifetime-policy or loaded-host acceptance. Remaining rollout is tracked in [BACKLOG.md](../BACKLOG.md).
8
8
 
9
- A completion group is the result sequence itself, not a container with members. Each result's YAML metadata begins index, run, state, then kind:primary for admitted primary text/final Actor response or kind:diagnostic for explicit diagnostics. The admitted Markdown follows from the left margin, outside metadata, with no #N heading, result:/preview: wrapper or whole-body literal fence. One blank separator distinguishes records. Known display loss appears only at the cut as [N characters omitted], counting Unicode scalar characters of the admitted retained source; no extra truncation ellipsis or body clipping flags/counters appear in YAML. Unknown upstream completeness/privacy remains explicit at the body boundary without inventing a count or claiming a known positive loss. Untracked fallback has no primary kind. Missing text stays explicit; a checkpoint retains its Actor-authored notification body. Successful automatic delivery has no extra receipt, routine outer counters, members wrapper, Batch caption, time window, status-summary copies or standing full-map instruction; real failures stay reportable. Exact source/generation/location references remain in complete model content, with whole-reference/result omission and non-done omitted states explicit. A group with one visible row stays a group. Fresh ordinary packets put minimal packet identity and relative body/marker lengths in YAML metadata, without compiler HTML tails. Older saved layouts retain their original compiler boundary/correlation framing; neither encoding grants authenticity, read permission or acceptance. Their compatibility boundary is governed separately below; never strip required historical framing. This is one new-capture contract, not a selectable AX product version.
9
+ A completion group is the result sequence itself, not a container with members. Each result's YAML metadata begins index, run, state, then kind:primary for admitted primary text/final Actor response or kind:diagnostic for explicit diagnostics. The admitted Markdown follows from the left margin, outside metadata, with no #N heading, result:/preview: wrapper or whole-body literal fence. One blank separator distinguishes records. Known display loss appears only at the cut as [N characters omitted], counting Unicode scalar characters of the admitted retained source; no extra truncation ellipsis or body clipping flags/counters appear in YAML. New rooted captures keep unknown upstream completeness/privacy in header text_warnings without inventing a count or claiming a known positive loss. Retained captures preserve their original body-boundary warnings. Untracked fallback has no primary kind. Missing text stays explicit; a checkpoint retains its Actor-authored notification body. Successful automatic delivery has no extra receipt, routine outer counters, members wrapper, Batch caption, time window, status-summary copies or standing full-map instruction; real failures stay reportable. Exact source/generation/location references remain in complete model content, with whole-reference/result omission and non-done omitted states explicit. A group with one visible row stays a group. Fresh ordinary packets put minimal packet identity and relative body/marker lengths in YAML metadata, without compiler HTML tails. Older saved layouts retain their original compiler boundary/correlation framing; neither encoding grants authenticity, read permission or acceptance. Their compatibility boundary is governed separately below; never strip required historical framing. This is one new-capture contract, not a selectable AX product version.
10
10
 
11
11
  Illustrative compact completion shape (not actual Run data):
12
12
 
@@ -31,10 +31,49 @@ Module was not found.
31
31
  [120 characters omitted]
32
32
  ```
33
33
 
34
- An only item uses the same first block, not a second format. Full text has no cut marker; an unavailable index is the YAML string "?", never a fabricated zero. The compact TUI renders compiler headers and markers as literal Text and each body as independent native Markdown, so an unfinished fence/list/quote cannot consume another block. Only whole compiler header reference/location rows and framing are hidden; expansion or invalid/missing hints reveals the full original text. Source bodies and retained structured coverage facts are not rewritten.
34
+ An only item uses the same first block, not a second format. Full text has no cut marker; an unavailable index is the YAML string "?", never a fabricated zero. The compact TUI renders compiler headers and markers as literal Text and each body as independent native Markdown, so an unfinished fence/list/quote cannot consume another block. New rooted headers keep navigation visible and put packet omission/inventory facts in the first header, never after the Markdown. Retained core-v1 compact views keep their original whole-reference/location hiding. Expansion or invalid/missing hints reveals the full original text. Source bodies and retained structured coverage facts are not rewritten.
35
35
 
36
36
  Storage compatibility is separate: already-captured Batch snapshots need their original codec to reproduce exact delivery text, while steer envelopes replay their saved content directly. Do not relabel, migrate or reformat existing journals/session messages to make the interface look uniform. Retained encoding identifiers are internal replay data, not alternate AX products. See [retained capture compatibility](coordinator-delivery.md#retained-capture-compatibility).
37
37
 
38
+ ## Rooted completion files
39
+
40
+ New source captures use a private `completion_yaml_files_v1` snapshot layout; this is replay data, not an input selector or a new product format. The YAML carrier/hint stays `completion_yaml_core_v1`. Existing snapshots keep their exact previous projection.
41
+
42
+ All runtime metadata belongs above the selected Markdown. New compact views have no service footer, appended file list or runtime warning after the body. A known cut alone adds `[N characters omitted]` at that cut; unknown loss/privacy and whole-reference omissions belong in header fields. Authored Markdown, filenames and paths keep their original language/bytes; compiler keys and purpose explanations are English.
43
+
44
+ `files.groups` stores each literal absolute path base once, with relative `entries[].path` beneath it. Source entries retain scope, generation/hash and other already-selected binding facts. `files.read_first` points to zero-based group/entry indices, preferring admitted primary text, diagnostic metadata, artifact inventory, then observed result/execution metadata; it is advice, not an automatic read. An artifact declaration does not prove that its target exists or was produced. `files.observation.group` binds existing mutable Run-file observations to their captured root; it does not add body permission or native proof.
45
+
46
+ Paths under the observed Run root share that group. External absolute paths have their own literal parent roots. Relative, malformed or dot-segment paths without a safe captured base remain as recorded under a null root with explicit base unavailability; no cwd/Run-id guess, normalization, source read or symlink resolution is allowed. A reader combines a known root and its relative path, never its own cwd. Packet-level inventory references likewise use one root plus relative leaf.
47
+
48
+ Illustrative abbreviated header, not actual Run data or a complete source binding:
49
+
50
+ ```text
51
+ ---
52
+ index: 0
53
+ run: "review"
54
+ state: "done"
55
+ kind: "primary"
56
+ files:
57
+ read_first:
58
+ group: 0
59
+ entry: 0
60
+ groups:
61
+ - root: "/work/runs/review"
62
+ entries:
63
+ - role: "primary"
64
+ purpose: "Full result text"
65
+ path: "evidence/primary.txt"
66
+ - role: "artifact"
67
+ purpose: "Declared artifact"
68
+ state: "declared"
69
+ path: "artifacts/report.md"
70
+ ---
71
+
72
+ The selected Actor Markdown ends here.
73
+ ```
74
+
75
+ The unchanged 48 KiB packet budget includes every root, entry and compiler hint. Outcomes retain priority over optional Run-file rows; whole omitted rows/locations remain explicitly covered. Stored member data, file-navigation DTOs, privacy/source fences and phase recovery are unchanged.
76
+
38
77
  ## Purpose
39
78
 
40
79
  AX means **Agent Experience**: convey enough structured, visible context for an agent to understand what happened and choose its next step, while remaining immediately readable to a person. The same projection should serve both rather than forcing the agent to reconstruct meaning from raw dumps or giving the human decorative prose that hides important facts.
@@ -113,7 +113,7 @@ Phases are monotonic:
113
113
 
114
114
  Every journal mutation uses the canonical token-owned lock, expected-phase fencing, owner and generation validation, and atomic replacement. Repeated transitions are idempotent. Corrupt, oversized, foreign-owner, or stale-generation state fails closed with bounded diagnostics.
115
115
 
116
- Ordinary source completion admission has one fresh path: presentation_format=ax_records, private result_layout=completion_yaml_core_v1 and frozen text_budget, without excerpt_format or a public selector. The inactive numbered-stream kernel path keeps its separate frontmatter_v2 default. Bounded source/compiled and actual-default source/packed acceptance observes the normal index path and in-memory entry/context/provider/hint tuple. Unchanged storage/registered-renderer/accepted-history-reopen facts transfer only on the successful original-current-manager path; this is neither fresh default-disk observation nor global lifetime-policy, native-scope or loaded-host acceptance. Direct admission and ordinary run-ui-runtime use it after unchanged owner/location checks; an existing batch stays untouched. Each shown record begins YAML frontmatter with index, run, state, then kind:primary for admitted primary/final Actor response or kind:diagnostic for explicit error/failure excerpts. Untracked fallback has no kind and retains unknown completeness/privacy outside YAML. The closed header is followed by raw, unindented Markdown, with no #N heading, result:/preview: wrapper or compiler literal fence around the body. Known local loss is [N characters omitted] at the cut, not a YAML flag/count or extra ellipsis; N counts the admitted postprivacy source prefix loss, not private/native output. Unknown upstream loss remains separate. Original coverage remains structured member data; exact source/generation/location references remain whole typed nested YAML values. Routine summaries/windows/status copies/standing map instructions remain journal facts, not duplicated model content. Material omitted_results, non-done omitted_states and whole result_inventory recovery stay explicit. Each shown record has a whole run_files row or explicit omission, with unavailable reasons retained; omitted records do not leave orphan location rows. Outcomes precede lower-priority references under the total48KiB UTF-8/64candidate-row bound including framing. Prefix admission considers full-list and decimal-count discontinuities, freezes equal scalar/CRLF-safe shares without unused-share redistribution, and never clips references or rewrites a retained excerpt. Older captures retain their original16KiB/48KiB budgets.
116
+ Ordinary source completion admission has one fresh path: presentation_format=ax_records, private result_layout=completion_yaml_files_v1 and frozen text_budget, without excerpt_format or a public selector. The inactive numbered-stream kernel path keeps its separate frontmatter_v2 default. Bounded source/compiled and actual-default source/packed acceptance observes the normal index path and in-memory entry/context/provider/hint tuple. Unchanged storage/registered-renderer/accepted-history-reopen facts transfer only on the successful original-current-manager path; this is neither fresh default-disk observation nor global lifetime-policy, native-scope or loaded-host acceptance. Direct admission and ordinary run-ui-runtime use it after unchanged owner/location checks; an existing batch stays untouched. Each shown record begins YAML frontmatter with index, run, state, then kind:primary for admitted primary/final Actor response or kind:diagnostic for explicit error/failure excerpts. Untracked fallback has no kind and retains unknown completeness/privacy outside YAML. The closed header is followed by raw, unindented Markdown, with no #N heading, result:/preview: wrapper or compiler literal fence around the body. Known local loss is [N characters omitted] at the cut, not a YAML flag/count or extra ellipsis; N counts the admitted postprivacy source prefix loss, not private/native output. Unknown upstream loss remains separate. Original coverage remains structured member data; exact source/generation/location references remain whole typed nested YAML values. Routine summaries/windows/status copies/standing map instructions remain journal facts, not duplicated model content. Material omitted_results, non-done omitted_states and whole result_inventory recovery stay explicit. Each shown record has a whole run_files row or explicit omission, with unavailable reasons retained; omitted records do not leave orphan location rows. Outcomes precede lower-priority references under the total48KiB UTF-8/64candidate-row bound including framing. Prefix admission considers full-list and decimal-count discontinuities, freezes equal scalar/CRLF-safe shares without unused-share redistribution, and never clips references or rewrites a retained excerpt. Older captures retain their original16KiB/48KiB budgets.
117
117
 
118
118
  Fresh ordinary source hints carry the core format and whole-content digest; the validated YAML core carries only packet identity and relative body/marker lengths, from which boundaries are derived. It adds no fresh HTML tail or duplicate coordinate table. These are consistency facts, not source or acceptance authority.
119
119
 
@@ -131,7 +131,7 @@ Removing fresh collection of untracked bodies would leave affected old/intermedi
131
131
 
132
132
  ### Retained capture compatibility
133
133
 
134
- The numbered wire strings ax_records_v1/v2/v3, old indexed/single_result captures and result_layout records/run_headers/headings/headings_flat_omissions/headings_outcomes/headings_shared_results/headings_shared_kinds/frontmatter_v1/frontmatter_v2 are retained storage encodings, not public alternatives. Fresh ordinary source admission chooses own-data completion_yaml_core_v1 with canonical ax_records and text_budget, never single_result. Absence preserves its original indexed/singleton codec; inherited aspects never restyle data and accessors are refused without invocation. Earlier record/header/count/kind grammar and each captured16KiB/48KiB share remain exact. The first frontmatter draft retains its original bytes and hints, including unquoted unknown index ?. Retained v2 fixed that one YAML case by writing index: "?"; numeric indices and other fields/body bytes are unchanged, and the presentation-hint schema remains completion_frontmatter_v1 because its block structure is unchanged. Preserve the frozen v1 unknown-content fingerprint90e29fb36087e2620fe0cf150b4238bce8a6d1dcc68ee922a1cf71ee8604610e and prior shared-result fingerprint4428de318b8ebaa029d3588ab7e8e705b9a80fa5cf08b6a2cc7151916207e266. Journals store snapshots rather than complete text: neither an unreleased product, a YAML correction nor member count permits relabeling/migration. Pending/queued/presented replay must reproduce original model bytes and hints without operator journal scans, source refresh or message rewrites. Removing compatibility requires a separate history-lifetime decision.
134
+ The numbered wire strings ax_records_v1/v2/v3, old indexed/single_result captures and result_layout records/run_headers/headings/headings_flat_omissions/headings_outcomes/headings_shared_results/headings_shared_kinds/frontmatter_v1/frontmatter_v2 are retained storage encodings, not public alternatives. Fresh ordinary source admission chooses own-data completion_yaml_files_v1 with canonical ax_records and text_budget (over the unchanged completion_yaml_core_v1 carrier); earlier completion_yaml_core_v1 snapshots retain their old layout, never single_result. Absence preserves its original indexed/singleton codec; inherited aspects never restyle data and accessors are refused without invocation. Earlier record/header/count/kind grammar and each captured16KiB/48KiB share remain exact. The first frontmatter draft retains its original bytes and hints, including unquoted unknown index ?. Retained v2 fixed that one YAML case by writing index: "?"; numeric indices and other fields/body bytes are unchanged, and the presentation-hint schema remains completion_frontmatter_v1 because its block structure is unchanged. Preserve the frozen v1 unknown-content fingerprint90e29fb36087e2620fe0cf150b4238bce8a6d1dcc68ee922a1cf71ee8604610e and prior shared-result fingerprint4428de318b8ebaa029d3588ab7e8e705b9a80fa5cf08b6a2cc7151916207e266. Journals store snapshots rather than complete text: neither an unreleased product, a YAML correction nor member count permits relabeling/migration. Pending/queued/presented replay must reproduce original model bytes and hints without operator journal scans, source refresh or message rewrites. Removing compatibility requires a separate history-lifetime decision.
135
135
 
136
136
  Steer envelopes already store complete content. Both attention and steer now have one canonical new-message formatter with no presentation selector; the redundant legacy formatting branches/path/body helpers are removed where no retained-data consumer needs them. Existing steer identity is reused before formatting and saved content bypasses the formatter in every pending/queued/presented recovery path. Removing stored Batch codecs later requires a separate retention/data-lifetime decision; an unreleased product is not permission to change previously captured delivery bytes.
137
137
 
@@ -91,10 +91,10 @@ F1.6 source-audit correction: Pi 1.0 native custom-message storage, session reco
91
91
  ### 10. Completion Projection, Compiler Frame and Native Renderer
92
92
 
93
93
  - **Owners:** `run-delivery.ts:1510` `completionRecordRow`, `:1683` `assembleFrontmatter`, `:1886` `projectCompletionRecords`, `:2110` `projectRunCompletionBatchPresentation`, `:2233` `readRunCompletionPresentation`, `:2283` retained projection, `:2328` message formatting. `run-ui-runtime.ts:68` `registerRunCompletionRenderer` is wired at `extension-runtime.ts:122`.
94
- - **Current:** Headers contain flow-JSON `references`/`run_files`; raw bodies and separate cut/uncertainty markers follow. Omission/inventory service text still uses pseudo-records/JSON. HTML compiler frames/closed completion markers and `details.pi_actors_presentation` bind ranges/hashes. Valid compact views render compiler text separately from native Markdown bodies; expansion/invalid hints expose original text.
95
- - **Prepared wire core:** `run-delivery.ts` `encodeCompletionYamlCarrier` / `readCompletionYamlCarrier` provide the accepted pure/nondefault mechanics; the prototype encodes and typed native view decodes them. Working source now also has a partial, unverified private candidate capture/layout route and strict-core Pi correlation. Default capture still uses `frontmatter_v2`; compiled/SDK integration and candidate acceptance are not established. They encode one `_completion` packet ID/codec and relative body/marker lengths, then derive dense ranges while decoding. Canonical bare headers are independent YAML fragments separated by codec-owned blank lines, not one mapping or a standard YAML multi-document stream; body-present headers are delimited and raw parts remain opaque. All-omitted is bare service metadata, not a fake Run. Empty selected bodies are distinct from absent bodies; empty-marker-only wrappers are refused. Input uses named top-level result keys with explicit depth/work bounds; fresh source admission and carrier acceptance remain F1.6v-gated, and meaningful service warnings must not be hidden wholesale.
96
- - **Prepared source projection (nondefault):** `projectRunCompletionYamlPrototype` projects current AX/frontmatter selected snapshots through one shared private fitter; it returns content, a format/digest-only hint and fitting facts, not a newly admitted or relabeled Batch. Frozen budgets/prefixes remain immutable. Canonical header/raw-part costs are measured additively, with unsupported data distinct from byte overflow; final content must agree with the unchanged core encoder/decoder. This prototype API remains data-only and source-class restricted. The partial private captured-layout route reuses internal YAML assembly rather than relabeling an old frozen snapshot; its independent quota/inventory, replay and epoch evidence is still incomplete. Native renderer support is prepared below; actual carrier acceptance remains a separate gate.
97
- - **Prepared native view (nondefault):** `readRunCompletionPresentation` derives frozen typed segments from the strict core and exact minimal format/digest hint; the registered renderer hides whole decoded reference/location nodes, retains every service fact and renders each body as independent native Markdown with literal Text metadata/markers. Valid-core missing/invalid hints and declared-new malformed content expose original full Text; expansion keeps that same source. Malformed content without a safely readable own new-format declaration retains historical dispatch, not a body-scanning heuristic. Headless widths/padding and old-history preservation are proved. Repo SDK 1.0.0's public `CustomMessageComponent` falls back to one Markdown component when a renderer is absent, returns undefined or throws, joining text-block arrays; a fresh component probe confirms this boundary, not session/interactive dispatch. Preserve that fallback unchanged: full content supplied to Markdown is neither independent-body rendering nor literal-visibility proof. Independent Markdown belongs only to the validated registered compact branch; registered degraded/expanded views keep original Text. Actual source-admitted native storage/context/provider/reopen and loaded terminal/phone behavior remain separate acceptance.
94
+ - **Current:** Fresh ordinary `completion_yaml_files_v1` snapshots use the unchanged strict YAML-core carrier. Header files.groups stores literal roots with relative entries, source bindings and English purposes; read_first is a group/entry pointer. Unknown-base paths stay explicitly as recorded. Native compact presentation exposes those file groups and places omission/inventory facts in the first header, never after the Markdown. Only known character-cut markers remain beside a truncated body. Earlier core-v1 and historical layouts keep their exact projection and hiding/footer behavior.
95
+ - **Prepared wire core:** `run-delivery.ts` `encodeCompletionYamlCarrier` / `readCompletionYamlCarrier` provide the accepted pure/nondefault mechanics; the prototype encodes and typed native view decodes them. Ordinary source/default capture uses the rooted snapshot layout; the earlier core-v1 snapshot and inactive numbered-stream frontmatter_v2 remain separate replay/gated paths. Strict-core Pi correlation and source/packed SDK evidence bind the selected content without granting native or read authority. They encode one `_completion` packet ID/codec and relative body/marker lengths, then derive dense ranges while decoding. Canonical bare headers are independent YAML fragments separated by codec-owned blank lines, not one mapping or a standard YAML multi-document stream; body-present headers are delimited and raw parts remain opaque. All-omitted is bare service metadata, not a fake Run. Empty selected bodies are distinct from absent bodies; empty-marker-only wrappers are refused. Input uses named top-level result keys with explicit depth/work bounds; loaded-host acceptance remains F1.7/U1-gated, and meaningful service warnings must not be hidden wholesale.
96
+ - **Prepared source projection (nondefault):** `projectRunCompletionYamlPrototype` projects current AX/frontmatter selected snapshots through one shared private fitter; it returns content, a format/digest-only hint and fitting facts, not a newly admitted or relabeled Batch. Frozen budgets/prefixes remain immutable. Canonical header/raw-part costs are measured additively, with unsupported data distinct from byte overflow; final content must agree with the unchanged core encoder/decoder. This prototype API remains data-only and source-class restricted. The ordinary rooted capture reuses internal YAML assembly and the same independently measured quotas/inventory rather than relabeling an old frozen snapshot. Native renderer support is prepared below; actual carrier acceptance remains a separate gate.
97
+ - **Native view:** `readRunCompletionPresentation` derives frozen typed segments from the strict core and exact minimal format/digest hint; the registered renderer keeps new rooted file groups and all meaningful service facts in headers, then renders each body as independent native Markdown with literal Text metadata/markers. Retained core-v1 captures keep their earlier reference hiding and service placement. Valid-core missing/invalid hints and declared-new malformed content expose original full Text; expansion keeps that same source. Malformed content without a safely readable own new-format declaration retains historical dispatch, not a body-scanning heuristic. Headless widths/padding and old-history preservation are proved. Repo SDK 1.0.0's public `CustomMessageComponent` falls back to one Markdown component when a renderer is absent, returns undefined or throws, joining text-block arrays; a fresh component probe confirms this boundary, not session/interactive dispatch. Preserve that fallback unchanged: full content supplied to Markdown is neither independent-body rendering nor literal-visibility proof. Independent Markdown belongs only to the validated registered compact branch; registered degraded/expanded views keep original Text. Actual source-admitted native storage/context/provider/reopen and loaded terminal/phone behavior remain separate acceptance.
98
98
  - **Selected-source bridge preservation:** A collector-supported legacy artifact declaration containing a lone UTF-16 surrogate is accepted and escaped by the old codec but refused by the pure YAML core; validator support does not assert that its target exists. The private bridge must preserve such known string-valued metadata slots as an explicit `utf16_code_units` mapping of four-hex-digit units, without U+FFFD repair, reference deletion, body encoding or machine/history mutation. Ordinary strings stay strings. Source-family probes reached depth eight and an exact 49,152-byte equal-share packet; these are representative witnesses, not universal compatibility proof. Pure projection/fitting precedes native renderer dispatch. One private optimizer distinguishes unsupported data from byte overflow; no public selector or newly budgeted Batch mislabeled as an old layout. Meaningful service warnings remain visible, and final output must satisfy the unchanged core's whole-packet contract.
99
99
  - **Concrete coupling:** `readFrontmatterFrame` (`run-delivery.ts:1628`) validates single-line fields/values and complete ordered coverage. The retained compact branch in `run-ui-runtime.ts` hides only single `references: ` / `run_files: ` lines; the new typed-segment branch handles whole decoded nodes. A serializer-only switch to nested YAML breaks validation or exposes orphaned reference children. Header parsing, whole-node hiding, fitting, hint/frame generation and source/body rendering must move together for new captures.
100
100
  - **Target / guard:** Block-YAML metadata with body-dependent delimiters; opaque independent body blocks and exact omission markers. Keep old codecs/bytes/hints, 48 KiB/64 shown/256 captured limits and whole references. The F1.6 necessity audit supports deleting fresh prefix hashes and duplicate coordinate/range tables, not moving the whole payload. The target carries one packet identity and minimal relative opaque-body/marker segments in YAML; absolute ranges are derived. Full admitted-source compatibility and actual carrier acceptance remain unproved, so the current HTML reader/producer are not removed in place. `completionInventoryText` (`:434`) remains machine JSON.
@@ -69,7 +69,7 @@ export interface RunCompletionBatch {
69
69
  /** Retained singleton capture; absence preserves older indexed bytes. Never a new-capture selector. */
70
70
  readonly single_result?: true;
71
71
  /** Captured record-list shape; no public format/version choice or source authority. */
72
- readonly result_layout?: "records" | "run_headers" | "headings" | "headings_flat_omissions" | "headings_outcomes" | "headings_shared_results" | "headings_shared_kinds" | "frontmatter_v1" | "frontmatter_v2" | "completion_yaml_core_v1";
72
+ readonly result_layout?: "records" | "run_headers" | "headings" | "headings_flat_omissions" | "headings_outcomes" | "headings_shared_results" | "headings_shared_kinds" | "frontmatter_v1" | "frontmatter_v2" | "completion_yaml_core_v1" | "completion_yaml_files_v1";
73
73
  /** Immutable scope/order/range data, not a caller-selected format or allocation authority. */
74
74
  readonly numbering?: RunCompletionNumbering;
75
75
  /** Formatting version/data only; no recipient ownership, read or publication capability. */
@@ -467,8 +467,12 @@ function isFrontmatterCompletionLayout(layout: unknown): boolean {
467
467
  return layout === "frontmatter_v1" || layout === "frontmatter_v2";
468
468
  }
469
469
 
470
+ function isYamlCompletionLayout(layout: unknown): boolean {
471
+ return layout === "completion_yaml_core_v1" || layout === "completion_yaml_files_v1";
472
+ }
473
+
470
474
  function isSharedCompletionLayout(layout: unknown): boolean {
471
- return layout === "headings_shared_results" || layout === "headings_shared_kinds" || layout === "completion_yaml_core_v1" || isFrontmatterCompletionLayout(layout);
475
+ return layout === "headings_shared_results" || layout === "headings_shared_kinds" || isYamlCompletionLayout(layout) || isFrontmatterCompletionLayout(layout);
472
476
  }
473
477
 
474
478
  function parseBatch(value: unknown): RunCompletionBatch {
@@ -512,7 +516,7 @@ function parseBatch(value: unknown): RunCompletionBatch {
512
516
  throw new Error("Completion shared text budget is invalid");
513
517
  }
514
518
  const numberingDescriptor = Object.getOwnPropertyDescriptor(record, "numbering");
515
- if (numberingDescriptor && (resultLayout === "completion_yaml_core_v1" || !Object.hasOwn(numberingDescriptor, "value") || presentationFormat !== "ax_records" || (resultLayout !== "headings" && resultLayout !== "headings_flat_omissions" && resultLayout !== "headings_outcomes" && !isSharedCompletionLayout(resultLayout)))) {
519
+ if (numberingDescriptor && (isYamlCompletionLayout(resultLayout) || !Object.hasOwn(numberingDescriptor, "value") || presentationFormat !== "ax_records" || (resultLayout !== "headings" && resultLayout !== "headings_flat_omissions" && resultLayout !== "headings_outcomes" && !isSharedCompletionLayout(resultLayout)))) {
516
520
  throw new Error("Completion numbering requires a canonical captured heading layout");
517
521
  }
518
522
  const numbering = numberingDescriptor ? parseCompletionNumbering(numberingDescriptor.value, members.length) : undefined;
@@ -891,7 +895,7 @@ export function requestRunCompletionStream(input: { tempDir: string; ownerId: st
891
895
  }
892
896
 
893
897
  export function admitRunCompletionBatch(input: AdmitRunCompletionBatchInput): RunCompletionBatch {
894
- return captureCompletionBatch(input, false, "completion_yaml_core_v1");
898
+ return captureCompletionBatch(input, false, "completion_yaml_files_v1");
895
899
  }
896
900
 
897
901
  /** Kernel-only opt-in; ordinary Pi capture stays fenced until session/lifecycle integration is admitted. */
@@ -901,10 +905,10 @@ export function captureRunCompletionStreamBatch(input: AdmitRunCompletionBatchIn
901
905
 
902
906
  /** Private ordinary candidate composition; stream capture retains its separately gated codec. */
903
907
  export function captureRunCompletionYamlCandidateBatch(input: AdmitRunCompletionBatchInput): RunCompletionBatch {
904
- return captureCompletionBatch(input, false, "completion_yaml_core_v1");
908
+ return captureCompletionBatch(input, false, "completion_yaml_files_v1");
905
909
  }
906
910
 
907
- function captureCompletionBatch(input: AdmitRunCompletionBatchInput, numbered: boolean, layout: "frontmatter_v2" | "completion_yaml_core_v1" = "frontmatter_v2"): RunCompletionBatch {
911
+ function captureCompletionBatch(input: AdmitRunCompletionBatchInput, numbered: boolean, layout: "frontmatter_v2" | "completion_yaml_core_v1" | "completion_yaml_files_v1" = "frontmatter_v2"): RunCompletionBatch {
908
912
  const now = (input.now ?? new Date()).toISOString();
909
913
  if (Object.hasOwn(input, "presentationFormat")) throw new Error("Completion presentation selection is not supported; new batches use AX.");
910
914
  if (Object.hasOwn(input, "numbering")) throw new Error("Completion numbering is assigned only by journal capture");
@@ -917,7 +921,7 @@ function captureCompletionBatch(input: AdmitRunCompletionBatchInput, numbered: b
917
921
  members: input.members,
918
922
  phase: "pending",
919
923
  });
920
- const draft: RunCompletionBatch = layout === "completion_yaml_core_v1"
924
+ const draft: RunCompletionBatch = isYamlCompletionLayout(layout)
921
925
  ? parseBatch({ ...captured, result_layout: layout }) : { ...captured, result_layout: layout };
922
926
  return mutateJournal(input.tempDir, input.ownerId, (journal) => {
923
927
  let batch = draft;
@@ -946,9 +950,9 @@ function captureCompletionBatch(input: AdmitRunCompletionBatchInput, numbered: b
946
950
  } else if (journal.completion_stream) {
947
951
  throw new Error("Completion stream capture requires the numbered kernel path; stream state is retained");
948
952
  }
949
- if (layout !== "completion_yaml_core_v1") batch = retainSharedCompletionTexts(batch);
953
+ if (!isYamlCompletionLayout(layout)) batch = retainSharedCompletionTexts(batch);
950
954
  if (projectCompletionBatchMessage(batch).membersShown === batch.members.length) {
951
- if (layout === "completion_yaml_core_v1") batch = retainSharedCompletionTexts(batch);
955
+ if (isYamlCompletionLayout(layout)) batch = retainSharedCompletionTexts(batch);
952
956
  journal.completion_batch = batch;
953
957
  return batch;
954
958
  }
@@ -1515,7 +1519,7 @@ function isRoutineCompletionSummary(member: RunCompletionBatchMember): boolean {
1515
1519
  }
1516
1520
 
1517
1521
  function completionRecordRow(member: RunCompletionBatchMember, index: number, byIdentity: Map<string, RunCompletionBatchMember>, flat = false, layout?: RunCompletionBatch["result_layout"], textBudget?: number): CompletionRow {
1518
- const frontmatter = isFrontmatterCompletionLayout(layout) || layout === "completion_yaml_core_v1";
1522
+ const frontmatter = isFrontmatterCompletionLayout(layout) || isYamlCompletionLayout(layout);
1519
1523
  const simpleKinds = frontmatter || layout === "headings_shared_kinds", shared = isSharedCompletionLayout(layout);
1520
1524
  const outcomes = shared || layout === "headings_outcomes", directOmission = outcomes || layout === "headings_flat_omissions";
1521
1525
  const run = member.run.startsWith("run:") ? member.run.slice(4) : member.run;
@@ -1780,6 +1784,83 @@ function completionYamlReferences(row: CompletionRow): Record<string, Completion
1780
1784
  return technical;
1781
1785
  }
1782
1786
 
1787
+ /** Split selected paths without normalize/resolve/relative: dot and symlink routes must not be rewritten. */
1788
+ function rootedCompletionPath(path: CompletionYamlData, runRoot?: string): { root: string; path: string } | undefined {
1789
+ if (typeof path !== "string" || !path.isWellFormed()) return undefined;
1790
+ const windows = /^(?:[A-Za-z]:[\\/]|\\\\[^\\/]+[\\/][^\\/]+[\\/])/u.test(path);
1791
+ const separator = windows ? /[\\/]/u : /\//u;
1792
+ if (!windows && !path.startsWith("/")) return undefined;
1793
+ if (path.split(separator).some(part => part === "." || part === "..")) return undefined;
1794
+ if (runRoot && path.startsWith(runRoot)) {
1795
+ const tail = path.slice(runRoot.length);
1796
+ if (separator.test(runRoot.slice(-1)) ? tail.length > 0 : separator.test(tail[0] ?? "")) {
1797
+ const relative = separator.test(runRoot.slice(-1)) ? tail : tail.slice(1);
1798
+ if (relative && !separator.test(relative[0]!)) return { root: runRoot, path: relative };
1799
+ }
1800
+ }
1801
+ let split = -1;
1802
+ for (let i = 0; i < path.length; i++) if (separator.test(path[i]!)) split = i;
1803
+ if (split < 0 || split === path.length - 1) return undefined;
1804
+ const end = split === 0 || (windows && split === 2 && path[1] === ":") ? split + 1 : split;
1805
+ return { root: path.slice(0, end), path: path.slice(split + 1) };
1806
+ }
1807
+
1808
+ /** Body-free, read-free navigation over already selected references. Roots are presentation bases, not containment proof. */
1809
+ function completionRootedFiles(row: CompletionRow, member: RunCompletionBatchMember, locations?: RunDirectoryNavigation): Record<string, CompletionYamlData> {
1810
+ const technical = completionYamlReferences(row), files: Record<string, CompletionYamlData> = {};
1811
+ const groups: Array<{ root: CompletionYamlData; entries: Record<string, CompletionYamlData>[] }> = [];
1812
+ const runRoot = locations?.state === "available" ? locations.directory : undefined;
1813
+ const group = (root: CompletionYamlData): number => {
1814
+ const found = groups.findIndex(item => item.root === root);
1815
+ if (found >= 0) return found;
1816
+ groups.push({ root, entries: [] }); return groups.length - 1;
1817
+ };
1818
+ let priority = Infinity;
1819
+ const add = (path: CompletionYamlData, entry: Record<string, CompletionYamlData>, rank = Infinity, base?: string): void => {
1820
+ const selected = rootedCompletionPath(path, runRoot);
1821
+ const index = group(selected?.root ?? (base === undefined ? null : completionYamlString(base)));
1822
+ const selectedPath = selected?.path ?? path;
1823
+ groups[index]!.entries.push({ ...entry, path: selectedPath,
1824
+ ...(!selected && base === undefined ? { path_basis: "as_recorded", base_unavailable: true } : {}) });
1825
+ if (selected && rank < priority) {
1826
+ priority = rank; files.read_first = { group: index, entry: groups[index]!.entries.length - 1 };
1827
+ }
1828
+ };
1829
+ for (const [role, purpose, rank] of [
1830
+ ["primary", "Full result text", 0], ["diagnostic_metadata", "Recorded error and command metadata", 1],
1831
+ ["artifact_inventory", "Declared artifact inventory; target availability unproven", 2],
1832
+ ] as const) {
1833
+ const detail = technical[role] as Record<string, CompletionYamlData> | undefined;
1834
+ if (!detail) continue;
1835
+ const { source: rawSource, ...facts } = detail;
1836
+ const { path, ...binding } = rawSource as Record<string, CompletionYamlData>;
1837
+ add(path!, { role, purpose, ...facts, source: binding }, rank);
1838
+ delete technical[role];
1839
+ }
1840
+ const artifacts = technical.artifacts as { scope: string; declarations: { name: CompletionYamlData; path: CompletionYamlData }[] } | undefined;
1841
+ if (artifacts) {
1842
+ for (const item of artifacts.declarations)
1843
+ add(item.path, { role: "artifact", purpose: "Declared artifact", name: item.name, scope: artifacts.scope, state: "declared" });
1844
+ delete technical.artifacts;
1845
+ }
1846
+ if (locations?.state === "available") {
1847
+ const { directory, files: selectedFiles, ...observation } = locations;
1848
+ files.observation = { ...observation, run: completionYamlString(locations.run), run_instance_id: completionYamlString(locations.run_instance_id),
1849
+ group: group(completionYamlString(directory)) };
1850
+ for (const item of selectedFiles) {
1851
+ const { path, ...facts } = item;
1852
+ const purpose = item.role === "result" ? "Recorded result metadata" : item.role === "execution" ? "Recorded execution and capture locations" : "Recorded Run file";
1853
+ add(typeof path === "string" ? completionYamlString(path) : null, { ...facts, purpose },
1854
+ item.state === "present" && item.role === "result" ? 3 : item.state === "present" && item.role === "execution" ? 4 : Infinity, directory);
1855
+ }
1856
+ } else if (locations) files.observation = { ...locations, run: completionYamlString(member.run), run_instance_id: completionYamlString(member.run_instance_id) };
1857
+ if (groups.length) {
1858
+ files.groups = groups;
1859
+ }
1860
+ if (Object.keys(technical).length) files.notes = technical;
1861
+ return files;
1862
+ }
1863
+
1783
1864
  type PreparedCompletionYamlProjection =
1784
1865
  | { state: "unsupported" }
1785
1866
  | { state: "overbudget" }
@@ -1788,6 +1869,7 @@ type PreparedCompletionYamlProjection =
1788
1869
  function prepareCompletionYamlProjection(safe: RunCompletionBatch, candidates: readonly { row: CompletionRow; location?: CompletionPiece }[],
1789
1870
  references: ReadonlySet<number>, ordered: readonly RunCompletionBatchMember[]): PreparedCompletionYamlProjection {
1790
1871
  const packet: CompletionYamlPacket = { batchId: safe.batch_id, records: [] };
1872
+ const rooted = safe.result_layout === "completion_yaml_files_v1";
1791
1873
  if (!safe.batch_id.isWellFormed()) return { state: "unsupported" };
1792
1874
  for (const [index, { row, location }] of candidates.entries()) {
1793
1875
  const member = ordered[index]!;
@@ -1804,28 +1886,38 @@ function prepareCompletionYamlProjection(safe: RunCompletionBatch, candidates: r
1804
1886
  else if (key === "artifact_declarations") metadata[key] = member.artifact_inventory?.declarations_total ?? Object.keys(member.artifacts ?? {}).length;
1805
1887
  else metadata[key] = completionYamlString(value);
1806
1888
  }
1807
- const technical = completionYamlReferences(row);
1808
- if (Object.keys(technical).length) metadata.references = technical;
1809
- if (references.has(index) && location) {
1810
- const navigation = safe.file_navigation!.find(item => safe.members[item.member_index] === member)!;
1811
- // Navigation is already decoded native data, not the JSON display field.
1812
- const locations = navigation.locations;
1813
- metadata.run_files = { run: completionYamlString(member.run), run_instance_id: completionYamlString(member.run_instance_id),
1814
- locations: locations.state === "available" ? { ...locations, run: completionYamlString(locations.run),
1815
- run_instance_id: completionYamlString(locations.run_instance_id), directory: completionYamlString(locations.directory),
1816
- files: locations.files.map(file => ({ ...file, ...(typeof file.path === "string" ? { path: completionYamlString(file.path) } : {}) })) } as CompletionYamlData
1817
- : { ...locations } };
1889
+ const navigation = references.has(index) && location
1890
+ ? safe.file_navigation!.find(item => safe.members[item.member_index] === member)!.locations : undefined;
1891
+ if (rooted) {
1892
+ const files = completionRootedFiles(row, member, navigation);
1893
+ if (Object.keys(files).length) metadata.files = files;
1894
+ } else {
1895
+ const technical = completionYamlReferences(row);
1896
+ if (Object.keys(technical).length) metadata.references = technical;
1897
+ if (navigation) {
1898
+ metadata.run_files = { run: completionYamlString(member.run), run_instance_id: completionYamlString(member.run_instance_id),
1899
+ locations: navigation.state === "available" ? { ...navigation, run: completionYamlString(navigation.run),
1900
+ run_instance_id: completionYamlString(navigation.run_instance_id), directory: completionYamlString(navigation.directory),
1901
+ files: navigation.files.map(file => ({ ...file, ...(typeof file.path === "string" ? { path: completionYamlString(file.path) } : {}) })) } as CompletionYamlData
1902
+ : { ...navigation } };
1903
+ }
1818
1904
  }
1819
1905
  const parts: CompletionYamlPart[] = [];
1820
1906
  const add = (part: CompletionYamlPart) => { if (parts.length) parts.push({ marker: "\n" }); parts.push(part); };
1821
1907
  for (const piece of row.pieces) if (piece.block) {
1822
1908
  if (!piece.text.isWellFormed()) return { state: "unsupported" };
1823
- add(piece.block === "body" ? { body: piece.text } : { marker: piece.text });
1909
+ if (rooted && piece.block === "marker" && !/^\[[0-9]+ characters omitted\]$/u.test(piece.text)) {
1910
+ metadata.text_warnings ??= [];
1911
+ (metadata.text_warnings as CompletionYamlData[]).push(piece.text);
1912
+ } else add(piece.block === "body" ? { body: piece.text } : { marker: piece.text });
1913
+ }
1914
+ if (safe.file_navigation !== undefined && !references.has(index)) {
1915
+ if (rooted) metadata.run_files_omission = { reason: "packet_byte_limit", shown: 0, omitted: 1, total: 1 };
1916
+ else add({ marker: "Run-file reference omitted (packet byte limit)." });
1824
1917
  }
1825
- if (safe.file_navigation !== undefined && !references.has(index)) add({ marker: "Run-file reference omitted (packet byte limit)." });
1826
1918
  packet.records.push({ metadata, parts });
1827
1919
  }
1828
- const service: Record<string, CompletionYamlData> = {};
1920
+ const service: Record<string, CompletionYamlData> = rooted ? { header_layout: "rooted_files_v1" } : {};
1829
1921
  const omitted = safe.members.length - candidates.length;
1830
1922
  if (omitted) {
1831
1923
  service.omitted_results = omitted;
@@ -1841,7 +1933,11 @@ function prepareCompletionYamlProjection(safe: RunCompletionBatch, candidates: r
1841
1933
  service.numbering = { ...safe.numbering, session_id: completionYamlString(safe.numbering.session_id), member_order: [...safe.numbering.member_order] };
1842
1934
  if (safe.numbering.kind === "unavailable") service.numbering_unavailable = safe.numbering.reason;
1843
1935
  }
1844
- if (safe.inventory_source) service.result_inventory = { ...safe.inventory_source, path: completionYamlString(safe.inventory_source.path) };
1936
+ if (safe.inventory_source) {
1937
+ const path = rooted ? rootedCompletionPath(safe.inventory_source.path) : undefined;
1938
+ service.result_inventory = { ...safe.inventory_source,
1939
+ ...(path ? { root: path.root, path: path.path } : { path: completionYamlString(safe.inventory_source.path) }) };
1940
+ }
1845
1941
  if (Object.keys(service).length) packet.service = service;
1846
1942
  const chunks: string[] = [];
1847
1943
  let bytes = 0;
@@ -1890,7 +1986,7 @@ export function projectRunCompletionYamlPrototype(batch: unknown):
1890
1986
  }
1891
1987
  }
1892
1988
 
1893
- function projectCompletionRecords(safe: RunCompletionBatch, assembler: "legacy" | "yaml" = safe.result_layout === "completion_yaml_core_v1" ? "yaml" : "legacy"): { message: string; membersShown: number; compact_ranges: [number, number][]; textBudget?: number; blocks?: readonly CompletionBlock[] } {
1989
+ function projectCompletionRecords(safe: RunCompletionBatch, assembler: "legacy" | "yaml" = isYamlCompletionLayout(safe.result_layout) ? "yaml" : "legacy"): { message: string; membersShown: number; compact_ranges: [number, number][]; textBudget?: number; blocks?: readonly CompletionBlock[] } {
1894
1990
  const frontmatter = isFrontmatterCompletionLayout(safe.result_layout) || assembler === "yaml";
1895
1991
  const shared = isSharedCompletionLayout(safe.result_layout);
1896
1992
  const maxBytes = shared ? Limits.RUN_COMPLETION_MODEL_MAX_BYTES : Limits.RUN_DELIVERY_MODEL_MAX_BYTES;
@@ -2118,7 +2214,7 @@ export function projectRunCompletionBatchPresentation(batch: RunCompletionBatch)
2118
2214
  const safe = parseBatch(batch);
2119
2215
  if (safe.presentation_format !== "ax_records" && safe.presentation_format !== "ax_records_v3") return { content: projectCompletionBatchMessage(safe).message };
2120
2216
  const result = safe.result_layout !== undefined ? projectCompletionRecords(safe) : projectRetainedRecordCompletionBatch(safe);
2121
- if (safe.result_layout === "completion_yaml_core_v1") return { content: result.message, presentation: Object.freeze({
2217
+ if (isYamlCompletionLayout(safe.result_layout)) return { content: result.message, presentation: Object.freeze({
2122
2218
  format: "completion_yaml_core_v1", content_sha256: createHash("sha256").update(result.message).digest("hex"),
2123
2219
  }) };
2124
2220
  return { content: result.message, presentation: Object.freeze({ format: isFrontmatterCompletionLayout(safe.result_layout) ? "completion_frontmatter_v1" : safe.presentation_format, content_sha256: createHash("sha256").update(result.message).digest("hex"),
@@ -2253,19 +2349,22 @@ export function readRunCompletionPresentation(content: string, value: unknown):
2253
2349
  !completionYamlKeys(hint, ["format", "content_sha256"]) || hint.format !== completionYamlCodec ||
2254
2350
  hint.content_sha256 !== createHash("sha256").update(content).digest("hex")) return full;
2255
2351
  const segments: NonNullable<RunCompletionPresentationView["segments"]>[number][] = [];
2352
+ const rooted = core.packet.service?.header_layout === "rooted_files_v1";
2353
+ const facts = Object.fromEntries(Object.entries(core.packet.service ?? {}).filter(([key]) => key !== "header_layout"));
2256
2354
  for (const [index, record] of core.packet.records.entries()) {
2257
2355
  if (index) segments.push({ kind: "separator", text: "\n" });
2258
- const metadata = Object.fromEntries(Object.entries(record.metadata).filter(([key]) => key !== "references" && key !== "run_files"));
2356
+ const metadata = Object.fromEntries(Object.entries(record.metadata).filter(([key]) => rooted || (key !== "references" && key !== "run_files")));
2357
+ if (rooted && index === 0 && Object.keys(facts).length) metadata.delivery = facts;
2259
2358
  const header = renderYamlMetadata(metadata, completionYamlMaxBytes);
2260
2359
  if (header.state !== "available") return full;
2261
2360
  segments.push({ kind: "header", text: record.parts.length ? `---\n${header.text}---` : header.text.replace(/\n$/u, "") });
2262
2361
  for (const part of record.parts) segments.push("body" in part ? { kind: "body", text: part.body } : { kind: "marker", text: part.marker });
2263
2362
  }
2264
- if (core.packet.service) {
2265
- const service = renderYamlMetadata(core.packet.service, completionYamlMaxBytes);
2363
+ if (core.packet.service && (!rooted || !core.packet.records.length)) {
2364
+ const service = renderYamlMetadata(rooted ? facts : core.packet.service, completionYamlMaxBytes);
2266
2365
  if (service.state !== "available") return full;
2267
2366
  if (segments.length) segments.push({ kind: "separator", text: "\n" });
2268
- segments.push({ kind: "service", text: service.text.replace(/\n$/u, "") });
2367
+ segments.push({ kind: rooted ? "header" : "service", text: service.text.replace(/\n$/u, "") });
2269
2368
  }
2270
2369
  return { text: segments.map(segment => segment.text).join("\n"), compact: true, records: true, yaml: true,
2271
2370
  segments: Object.freeze(segments.map(segment => Object.freeze(segment))) };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llblab/pi-actors",
3
- "version": "0.57.0",
3
+ "version": "0.57.1",
4
4
  "private": false,
5
5
  "description": "Local Actor Kernel for Pi",
6
6
  "keywords": [
@@ -151,7 +151,7 @@ Run = Recipe + Trace + Control
151
151
  5. Send `message` only for an action declared and consumed by that controlled Recipe.
152
152
  6. Use terminal state, result, declared artifacts, and execution evidence to prove completion. When an outcome includes a retained primary-source, declaration-inventory or diagnostic-metadata reference, use that exact reference for further reading, not guessed captures or sibling files. Literal previews may be clipped; their field/range/counts describe what was shown. Diagnostic sources contain recorded command/error/failure-reason metadata only, not complete primary output; other recorded fields may be referenced without being shown. Artifact inventories list declarations only: they do not assert that target files exist or were produced, or grant body-read permission. Explicit unavailability has no guessed legacy body/path fallback.
153
153
 
154
- Compact launch receipts include `run_files` as nested block YAML containing the exact selected observed location values, labeled observed locations/mutable for the exact launched Run generation when the current session and physical identity agree; otherwise they report unavailability or whole-row omission. Machine `file_navigation` details stay JSON-compatible; saved terminal messages retain their own original encodings. Selectively ordinary-read those starting locations when needed; layout/size hints are not body, privacy, terminal or native proof. No evidence bodies or session-wide catalog map are read to build this row. New terminal packets also freeze bounded location rows for captured completion members at fresh current-session admission. Each shown result keeps its whole Run-file row or explicit per-record omission; wholly omitted results stay covered by result omission/inventory. This describes Run-row coverage, not a complete file/tree inventory. Older captured formats retain their original shown/omitted/total counters; unavailability remains explicit. Ordinary-read selected paths only when needed. Packet reload/render never refreshes sources, and old absent/request-only formats keep their text. Source/npm SDK verifies an explicitly requested ordinary read from a delivered terminal result path; this is research, never routine completion polling or new primary/privacy/clock/native authority. Use the request only for file investigation, not routine completion/status polling. Copied locations/hints remain data, never transferred scope; older batches keep their original text.
154
+ Compact launch receipts include `run_files` as nested block YAML containing the exact selected observed location values, labeled observed locations/mutable for the exact launched Run generation when the current session and physical identity agree; otherwise they report unavailability or whole-row omission. Machine `file_navigation` details stay JSON-compatible; saved terminal messages retain their own original encodings. Selectively ordinary-read those starting locations when needed; layout/size hints are not body, privacy, terminal or native proof. No evidence bodies or session-wide catalog map are read to build this row. New terminal packets also freeze bounded location rows for captured completion members at fresh current-session admission. Fresh rooted completion headers group paths under literal roots with relative entries, English purposes and a read_first group/entry pointer; no cwd guess, source refresh or automatic read follows. Unknown bases stay explicit. Runtime navigation/omission/inventory facts remain above the Actor Markdown, not in a footer; retained packets keep their original projection. Each shown result keeps its whole Run-file row or explicit per-record omission; wholly omitted results stay covered by result omission/inventory. This describes Run-row coverage, not a complete file/tree inventory. Older captured formats retain their original shown/omitted/total counters; unavailability remains explicit. Ordinary-read selected paths only when needed. Packet reload/render never refreshes sources, and old absent/request-only formats keep their text. Source/npm SDK verifies an explicitly requested ordinary read from a delivered terminal result path; this is research, never routine completion polling or new primary/privacy/clock/native authority. Use the request only for file investigation, not routine completion/status polling. Copied locations/hints remain data, never transferred scope; older batches keep their original text.
155
155
 
156
156
  For selective investigation of already cataloged files, use `inspect target=runtime view=runs verbose=true`, then ordinary file tools on its current-session root-first navigation. Ordinary maps keep latest-registration order between roots and prioritize known failed subtrees within each root. For a failed investigation add status=failed: inventory is filtered, while the full owned map prioritizes observed failed subtrees across roots, always ancestors first. Priority uses only exact-generation matched inventory observations, not complete terminal truth. Launches and compatible singleton attachments populate the catalog; reads do not backfill missing locations. A `catalog: unavailable` launch warning is not workload failure: do not spawn again merely to repair navigation. The starting map's format hints do not certify syntax, encoding or complete output. See [Runs](./references/runs.md) for selective recorded-capture research and resume boundaries.
157
157
 
@@ -24,7 +24,7 @@ inspect target=run:<id> view=trace
24
24
  inspect target=run:<id> view=control
25
25
  ```
26
26
 
27
- Fresh root completions use index-first YAML frontmatter (index, run, state, admitted kind), followed by raw left-edge Markdown. No external #N heading, result:/preview: wrapper, list nesting, whole-body fence, Batch caption, members wrapper or routine outer counter is added. Primary/final Actor response uses kind:primary; explicit error/failure diagnostic text uses kind:diagnostic, never a launch command. Untracked fallback has no kind and keeps unknown original completeness/privacy explicit outside YAML. Known cut loss is [N characters omitted] at the cut, with no extra ellipsis or body clipping counters/flags in metadata. Unknown upstream loss remains separately unknown and does not assert a known positive omission. Exact source/generation/parent/location references remain in complete model content, with whole references or explicit omission, captured inventory recovery and non-done omitted states. The compact TUI independently renders literal headers/markers and native Markdown bodies from validated content-bound blocks; only whole header reference/location rows and framing are hidden. Expansion and invalid/missing hints reveal original text. Hashes/layout/markers establish consistency/correlation only, never authentication, read/action permission, acceptance or native truth. Authored YAML/next/tool/batch/omission lookalikes stay body content. Fresh packets share48KiB UTF-8 including service data, equally between up to64candidate rows, with256captured members and no redistribution of unused shares or fixed16KiB/2KiB text cap. Full admitted text fitting its share without upstream uncertainty has no cut marker; otherwise use the scalar/CRLF-safe prefix and exact retained-source loss. Allocation/text is frozen at admission; rendering/recovery does not reread sources or reallocate. Unsupported Pi event/control output is withheld. Source basis stays in reference metadata; retained structured coverage facts are not exposed as YAML clipping fields. Pending/queued/presented older formats—including #N records and the first frontmatter draft—keep exact bytes, hints and budgets. Encoding names are storage replay data, not public product choices, source permissions or work authority. No standing full-map instruction or automatic research/read follows; use selective same-session investigation when needed.
27
+ Fresh root completions use index-first YAML frontmatter (index, run, state, admitted kind), followed by raw left-edge Markdown. New source captures put all runtime metadata above that body, with no service/file footer. files.groups gives one literal root plus relative entry paths; files.read_first names zero-based group/entry indices for the first useful source, not an automatic read. role/purpose guidance is English; Actor Markdown and path/name bytes are unchanged. External paths use separate roots; unknown bases remain explicit rather than guessed from cwd or Run id. Known cut counts alone may follow the cut body; unknown-loss warnings and packet omission/inventory facts stay in the header. Retained captures preserve their old bytes and presentation. No external #N heading, result:/preview: wrapper, list nesting, whole-body fence, Batch caption, members wrapper or routine outer counter is added. Primary/final Actor response uses kind:primary; explicit error/failure diagnostic text uses kind:diagnostic, never a launch command. Untracked fallback has no kind and keeps unknown original completeness/privacy explicit outside YAML. Known cut loss is [N characters omitted] at the cut, with no extra ellipsis or body clipping counters/flags in metadata. Unknown upstream loss remains separately unknown and does not assert a known positive omission. Exact source/generation/parent/location references remain in complete model content, with whole references or explicit omission, captured inventory recovery and non-done omitted states. The compact TUI independently renders literal headers/markers and native Markdown bodies from validated content-bound blocks; only whole header reference/location rows and framing are hidden. Expansion and invalid/missing hints reveal original text. Hashes/layout/markers establish consistency/correlation only, never authentication, read/action permission, acceptance or native truth. Authored YAML/next/tool/batch/omission lookalikes stay body content. Fresh packets share48KiB UTF-8 including service data, equally between up to64candidate rows, with256captured members and no redistribution of unused shares or fixed16KiB/2KiB text cap. Full admitted text fitting its share without upstream uncertainty has no cut marker; otherwise use the scalar/CRLF-safe prefix and exact retained-source loss. Allocation/text is frozen at admission; rendering/recovery does not reread sources or reallocate. Unsupported Pi event/control output is withheld. Source basis stays in reference metadata; retained structured coverage facts are not exposed as YAML clipping fields. Pending/queued/presented older formats—including #N records and the first frontmatter draft—keep exact bytes, hints and budgets. Encoding names are storage replay data, not public product choices, source permissions or work authority. No standing full-map instruction or automatic research/read follows; use selective same-session investigation when needed.
28
28
 
29
29
  Current completion index values restart within each packet; they are not session-wide historical references. Completion streams are adopted but not enabled, and no start-stream command is available yet. Do not infer an active stream or reset a counter from missing metadata or a pending target, and never relabel older saved packets. The kernel-only allocator now commits fixed scope/order/indices, the counter and first-packet target activation together, and an internal fresh-session bridge can use it after current manager/generation admission. The default runtime does not opt in; no public action exposes it. Event reason or a matching ID alone is insufficient. Old callbacks/wrappers cannot act after replacement; fresh wrappers must belong to the current original manager. Startup/reload/resume and ambiguous imports remain closed to stream capture/ACK, without changing saved packets or inferring a counter from history. Its whole-range exhaustion or admitted counter unavailability yields a frozen unknown index (quoted "?" in fresh YAML; #? in older saved layouts), never partial indices or an automatic fresh stream. Old packets retain their original scope while a pending switch waits; uncertainty does not permit reallocation. Stream state outlives packet cleanup/receipt rotation. Malformed/missing state remains refused, not a zero counter or proof of non-connection.
30
30