Skip to content

set_run_text: wire N0c1 to the office edit surface (docx.edit/2) #462

Description

@bobzhang

The arc after #434. The unified reader retains classified, provenance-carrying projections on every mutation-safe read, and plan_whole_run_replacement (N0c1) consumes them — but nothing shipped calls it. This campaign makes ONE carefully bounded operation trust the new truth source.

Shape (design of record: the post-#434 direction consultation; matches docs/office-major-parity.md N1a→N1b): an ADDRESSED operation, semantically distinct from replace_text's literal matcher — neither a second literal-replace nor a cutover of run_rewrite.mbt (the old emitter canonicalizes w:t and deletes empty runs; N0c1 preserves properties, spellings, and suppressed content — reconciliation is a measured follow-up, not first activation).

Stages

  • A1 — package boundary: plan_run_text_replacement_archive(annotated, archive, story, at_relative~, expect~, text~) → (SplicePlan, RunTextReceipt) in docx2html/docx. Projection types stay private. The resolver uses the retained projection's OWN scan for path resolution (never story_run_span — the annotation index must not become mutation authority), maps to exactly one paragraph/run (refusing zero/duplicate/ambiguous), and pins the plan to its source.
  • A2 — transaction SDK: DocxEditSession::queue_run_text_replacement + office/docx/edit_set_text.mbt. One bounded target; REQUIRED expect (snapshot-relative addresses need a precondition); no mixing with literal replace/revision resolution in one program; no output on refusal; byte-equal no-op when text == expect; full affected-paragraph readback as the semantic postcondition; an explicit text-character policy decision (the edit parser rejects all C0, N0c1 permits XML-valid tab/LF/CR).
  • A3 — shipped surface: docx.edit/2 with {"op":"set_run_text","params":{"at","expect","text"}}; /1 untouched; capabilities/input-contract discovery; cram + SDK + wasm + fresh-agent acceptance; both .mbti diffs intentional.
  • A4 — optional consolidation (separate): differential evidence before any emitter replacement; never both emitters in production.

Release gate additionally includes the #438 XML-token-budget calibration (39/591 corpus documents currently refuse on budgets — availability work that belongs to this surface going live).

After this

  • C: migrate annotation_index/annotation_spans onto the retained trace behind this contract, proving public path/warning/ordinal parity (they still run their own physical scans).
  • B: N0c2 partial-boundary surgery (sub-run ranges, run splitting).

Non-goals

Public projection API; cross-run or range editing; replace_text fidelity changes; template row-clone emission changes; header/footer mutation policy widening (the package wrapper is story-aware; the office surface starts body-only).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions