Compare commits

...
4 changed files with 1833 additions and 644 deletions

No files matched your search

+24
View File
@@ -5344,3 +5344,27 @@ Gander: after Duckworth-0100 design approval with C1-C5, prepared the two host-s
2026-10-22T18:11:57Z | Sage | Row 275 (#1780, Morgana, Duckworth) LANDED 3410df7c3. Before: refactor at 48e450ce8; viewers had no verb list of their own and board reads were not refused to users. After: a fast-forward of 3 commits; manifest 39847b15 (4 paths) blobs match; gate 17:52:12Z-18:05:00Z green (whole files 7/22/6, bus 834, cli 861, harness 151, business 231, seat 167, 10 scripts with 3 named skips), M6 and M10 killed; Duckworth APPROVE rev 3260 (comment 30717); note and done by sage-2897; #1780 comment 30728 and closed. N1 (board refusal test as a loop over BOARD_VERBS) is non-blocking.
2026-10-22 18:11:58 UTC | Gander row276 #1781 prepared, gate pending | Before: row253 left5legacy Case1 AS_USER calls unsupervised across sudo pty sessions. After: candidate uses its unchanged supervisor with per-call inner/outer budgets, separate streams, strict display-only failure trailer, fake-only paired process-model cases and15unique mutants. Duckworth0182 B1 corrected the plan before product code;0183 cleared build. Parse-only Bash checks pass; no Node, behavioral test, host, unit or config action. Runtime gate and publication await Sage.
2026-10-22T23:03:39Z | Gyro Q195 O2 rewrite, #1752 / Vikunja #448, mos-1356 | Before: landed O3 design 95e3f7166/blob 4cb59999. After: Q231/Q233 full WordCraft O2 design on gyro/editor-o2 from refactor c4f77373f; canonical git DOCX, original Markdown/wiki preservation, human cadence default 0 with instant accepted-save commits, full rich-feature first slice. Ten briefs include independent source/dependency security clearance before any build queue entry, exact editor-only CSP approval gate, restricted source/build/bridge, separate reviewed DOCX citation gate and flags-only agent access. Existing Case 2 semantics unchanged; any integration requirement change goes through Mos to Jason. Static checks: ten briefs/seven fields, independent reviewers, unique anchors, current source/base/blob pins, docs scope and append-only logs pass. No builds, browser/worker runs, code, queue or live changes. Fenton review pending; CSP and implementation gates remain closed.
2026-10-22T23:03:53Z | Gyro Q195 O2 push guard | CI queue guard identity gyro / purpose push returned exit 0, documented degraded-pass: CANNOT_ASSERT credential-unresolvable. Audit: /mnt/storage/scratch/gyro-q195-ci-queue-audit.jsonl. No credential fallback or CI-green claim.
2026-10-22T23:09:38Z | Gyro Q195 O2 fenton-0006 fixes | Before: e012bab0b left stale-source ambiguity, incomplete migration/shipping ownership, undefined typing transactions and an unmeasured CSP gate. After: D12 explicitly routes superseded-source/C2 reply notices to Mos/Jason and refuses adoption before W4b/notice path; Q2 remains open. F2-F6 add schema-edge placeholders and restore-accounting files, shipped runtime data/writing closure with no sandbox store mount, per-chapter DOCX and 2s-pause/15s-span save groups, volume/latency/growth gates, split-run clickable wikilinks and historical Obsidian graph warning, and S0 isolated existing-artifact CSP measurement before exact-header approval. Static ten-brief/ownership/settings/checklist checks pass. No build/browser run, product/queue/live change. Independent re-check pending.
2026-10-22T23:09:50Z | Gyro fenton-0006 push guard | identity gyro, purpose push, exit 0 documented degraded-pass CANNOT_ASSERT credential-unresolvable; audit gyro-q195-ci-queue-audit.jsonl. No fallback credentials or CI-green claim.
2026-10-22T23:10:14Z | Gyro mos-1358 ruling recorded | Q36 / Vikunja 562 keeps C2 superseded notices OPEN with Jason. Markdown adoption refusal until W4b PASS is now a separate settled Mos build-order ruling, not a Jason question. D12 and Q2 distinguish them; no notice build authorized.
2026-10-22T23:13:27Z | Gyro Q195 O2 fenton-0007 F7/F8 | Named human-only editor.saveGroupPauseMs=2000 and editor.saveGroupMaxMs=15000 with integer/range/cross-field validation and W3a UI/CLI refusal tests. W3b owns production adoption refusal until W4b; isolated fixture conversion remains testable without request-flag bypass. W4b owns adoption module/API tests and reviewed lifting only with committed-reader/citation readiness and, if Q36 approves, the separate notice row PASS. Q36 unresolved stays closed. Static ten-brief, setting-key/bounds, refusal/lift ownership and two-question checks pass. Docs only; no build, browser/worker run, product/queue/live change. Fenton checks F7/F8 on next push.
2026-10-22T23:13:48Z | Gyro mos-1359 / r3 push guard | D13 records save-group timing as Mos's accepted reading of Q226 F41, not Jason's ruling; both defaults remain human-only settings. Push guard identity gyro/purpose push: exit 0 documented degraded-pass, CANNOT_ASSERT credential-unresolvable; audit gyro-q195-ci-queue-audit.jsonl, no credential fallback or CI-green claim.
2026-10-23T00:52:58Z | Gyro Q235-Q237 policy rewrite started, Vikunja 571, mos-1366/1367 | Before: approved O2 e36bce352 keeps Markdown originals at their paths and Q36 notices open; landed W4 2af460ab7 has the same boundary. Imported that byte-identical W4 baseline as 1ac76a417, from refactor 062646487, to make the policy-only revision diff explicit. Prepared P1-P6/B1-B4: human one-way per-story import, human-set source-repo archive, DOCX current reader, scoped format map/archived non-canon reads, W7 conversion publication after W4b/approved PRD/10-27 and Jason first-real-book go. Q234 exact CSP, mos-1363 and S0 M1-M14 retained. W4 locator/extractor, shares and restore-fence blocks compare byte-identical to the approved baseline. Scope/source review ongoing; Mos impact map must be folded before Fenton handoff. No build/browser/worker run, code, queue, private-book or live action.
2026-10-23T01:37:07Z | Gyro Vikunja571 final impact-map / mos-1372/1375 fold | Prepared parent/W4 rewrite against brain-redux d183246 impact map at stack 062646487. P1-P6/B1-B4 and engineering Q1-Q16 are mapped to eleven briefs. D9 replaces the earlier private O2-only context/per-document/share model: normal Case 2 access in any authorized thread/room, supporting writes intact, changed policy awaits PRD 1.17 approval. New DOCX story creation has the same opening gate as human per-story import. Host-only push to human-set off-host remote replaces the no-remote ban; remoteURL defaults unset and same-host bare is disallowed. W7 gates on Hermes #423 step5, W4b, PRD approval, post-10-27 and first-real-book go; owns conversion events COUNTED/--events/pre-conversion restore reconciliation, manifest order/next_chapter, creative role cite wording, archive/old-path edits and format/link/citation routing. Store+off-host acknowledgment precedes archive commit/push, then catalogue publication; post-push failures remain resumable pending with pinned source. Current checks pass: complete brief fields, policy/map coverage, exact Q234 CSP, locator/projection mechanics byte-equivalent except explicit authority wording, A01-A35 IDs, immutable map pin, four-doc scope and append-only logs. W4 authority/remote/recovery sections reopened for Fenton; older APPROVE not reused. No product/build/browser/worker/private-book/queue/live action. Earlier entry describing preserved shares/fence applies only to the pre-D9 intermediate draft; D9 now withdraws those unimplemented structures.
2026-10-23T01:37:55Z | Gyro 571 push guard | identity gyro/purpose push: exit 0 documented degraded-pass CANNOT_ASSERT credential-unresolvable, scratch audit gyro-q195-ci-queue-audit.jsonl; no credential fallback or CI-green claim.
2026-10-23T01:41:59Z | Gyro sage-3121 A1-A3 PRD alignment | Before: 8d209016b adds a current Connections graph, excludes new Markdown stories in converted books and defaults archiveFolder. After: parent/W4 align with PRD1.17 d6 sha256 886b93c571f87bfbb2f27ee3113b6800a32d8f89196d95ace33566031bee380a: clickable editor links only; graph/tests later pending J-b; new different-path Markdown in a converted book remains canon until import, only recreated converted old paths are unmapped; archive folder is human-set in library mapping with no default, missing folder refuses conversion. Static A1-A3/11-brief checks pass; W4 locator/extractor/access/remote/recovery blocks unchanged. Local commit only, push held for Sage's named gap while Gizmoduck holds 270+271 run5. No product/build/browser/worker/queue/live action. Fenton gets local SHA through shared object store.
2026-10-23T01:49:08Z | Gyro fenton-0012 B1/B2 and N1-N6, mos-1379 | B1: off-host remote must deny the real shared jason.woltje seat-helper credential as well as seat identities until #431; private visibility/dummy-token denial is insufficient; W3b/A16/A26 require that future fixture proof. B2 follows mos-1379: human-only editor.agentReadComments and editor.agentReadTrackedDeletions both default false, comment/original/markup reads/resolves/index/context refuse when off; final access remains D9 and no role allowlist/per-document grant. N1 staging-ref allowlist and retained private refused/published audit refs; N2 URLs literal with fidelity-report loss and confirmation; N3 future paths marked new or predecessor row; N4 rename/sharing wording fixed; N5 historical thread text not refreshed; N6 protected VM1012 backup cited in P5. Static checks pass, locator JSON/package/projection mechanics retained. Local commit only; HTTPS push still held for Sage's named gap. No credentials tested/read/printed, no product/build/browser/worker/queue/live action. Fenton gets exact local SHA/blobs.
+7
View File
@@ -1549,3 +1549,10 @@ are never rewritten or removed; corrections are new entries.
2026-10-22 | Della | Row258 E01 3094e3bfa focused manifest review | APPROVED 11-path manifest/static F1/F2/N1 corrections; file and full-blob digest recipes verified. M1-M11 fixed; all execution/landing evidence still required in CLEAR. No shared-log edit, Node, tests, HTTPS Git or live action.
2026-10-22T17:55:40Z | Sage (Opus 5.5, 1ef1e4f8) | Row 253 landing; post-253 doc sweep | 253 LANDED 48e450ce8. Sweep on sage/sweep-253: Gosalyn Case 2 design and rows, 229 design, Gyro 0acbdb0d8, Della 179391055, 268 docs, seat dirs for Della, Scrooge, Huey, Louie and Ludwig, human-users-build:70 under Q173, DEFERRED 253 N1, 198 N2, row 203 text, 224 residual and 206 sharee list, and seat log lines.
2026-10-22 14:48 UTC | Researcher (Sonnet 5.5, 9bac0794) | Rows 220 and 216 resumed (sage-2708, sage-2716, sage-2719); local commits only | 220 e4a204836 on researcher/row220-r2 (on ea6dc9eff): C1 run tests, C2 default-reader M7 test, configDirectory fixture scope, BUILD.md round 2b. 216 4f3fbc25a on researcher/row216-r2 (on aca16404c): index cache, find/get/search/manuscript/universeInfo, PRD 1.14 levels. Nothing pushed, claimed or run; node --check not run. Waits for Sage's CLEAR and go; rebase onto 253 on a new branch before any gate.
2026-10-22T23:03:39Z | Gyro (Codex gpt-6.1-sol, mos-1356) | Q195/Q231/Q233 O2 design rewrite, gyro/editor-o2 from c4f77373f | Canonical queue next gyro: nothing. Ten docs-only briefs; full-feature WordCraft, independent 15-crate/199-package security review, editor-only CSP candidate, instant git DOCX saves and retained Markdown/wiki sources, committed-only DOCX citation gate, no agent story prose. Static structure/source-anchor/scope checks only; no code, build/run, queue or live change. Fenton review requested after push.
2026-10-22T23:09:38Z | Gyro (Codex gpt-6.1-sol, fenton-0006) | Q195 O2 design corrections on gyro/editor-o2 | F1 requirement boundary sent to Mos, adoption gated; F2-F6 source-checked docs fixes prepared. Ten briefs and two open owner items checked statically. No implementation, build/browser/worker run, queue or live action; Fenton re-check after push.
2026-10-22T23:13:27Z | Gyro (Codex gpt-6.1-sol, fenton-0007) | Q195 O2 r3 F7/F8 | Save-group keys/defaults/validation and W3b refusal/W4b lift ownership explicit. Static docs checks only. Q36 remains open; no implementation or gate lift. Direct Fenton/Mos handoff after push.
2026-10-23T00:52:58Z | Gyro (Codex gpt-6.1-sol, mos-1366/1367) | Vikunja571 Q235-Q237 O2 parent/W4 format-policy rewrite on gyro/editor-o2 | Canonical queue next gyro: nothing. Prepared P1-P6 and B1-B4 docs, baseline W4 import 1ac76a417; no product/build/browser/worker/private-file/queue/live action. Mos impact map fold precedes review/push handoff.
2026-10-23T01:37:07Z | Gyro (Codex gpt-6.1-sol, mos-1368/1372/1375) | Vikunja571 O2 parent/W4 revision complete for review | P1-P6/B1-B4 and A17-A41/Q1-Q16 folded; same-thread Case 2 lookups/support writes, human-set host-pushed off-host remote, Hermes/restore/counting/order/role gates. Static docs checks pass; old locator/projection mechanics retained, authority/access review reopened. No code, build/browser/worker run, private conversion, queue or live action. Direct Fenton/Mos/Sage handoff after push.
2026-10-23T01:41:59Z | Gyro (Codex gpt-6.1-sol, sage-3121) | 571 PRD d6 A1-A3 alignment | Both designs corrected and statically checked; local commit for Fenton in shared repo object store. HTTPS push held for Sage gap, independent review pending. No product, test-slot, queue or live change.
2026-10-23T01:49:08Z | Gyro (Codex gpt-6.1-sol, fenton-0012/mos-1379) | 571 B1/B2 and N1-N6 docs corrections | Real-helper denial gate and two off-by-default human review settings; static acceptance/brief/immutable-mechanics checks pass. Local candidate for Fenton via shared Git objects; no HTTPS push before Sage gap, no runtime or credential experiment.
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,671 @@
# Q195 O2 W4: committed DOCX citations and Case 2 access
Policy rewrite for Vikunja 571, mos-1366/1367/1368/1372/1375, Q234–Q237.
Normative parent: `docs/plans/2026-10-21_q195-writing-editor.md` in the same revision.
Original W4: Rocko/Megavolt, #1799, refactor 062646487, blob
`2af460ab772f8d204598dc8cb79b3c161f311623`. Gyro writes this assigned revision; Fenton
independently reviews it. The reviewer-owned verdict file is untouched.
Impact map: brain-redux d183246, `projects/mosaic-mvp/case2-docx-impact-map.md`, stack pin
062646487. Sections 1/2/6/7 and A19/A20/A28 are reopened, plus part/view authorization
wording. Exact locator, package-validation and projection mechanics in sections 3–5 remain
from the reviewed baseline except their replaced per-document-scope wording.
## 1. Confirmed format policy and approval gates
Q235–Q237 P1–P6 and mos-1372 D1/D2 settle the design basis: canon and playground story
files become DOCX, retaining universe/book and source scope. Type-folder notes, agent files,
instructions, PRDs, character sheets, summaries and supporting documentation stay Markdown.
An unmarked-folder story is eligible; the human selects one story file at a time. New
stories start directly as DOCX in the human-selected universe/book or playground, without a
Markdown precursor, under the same production-opening gate as import.
The October 27 release stays Markdown. Production import/new-story opening waits for W4b,
W7, the post-10-27 release, the approved Case 2 PRD/brief amendment, Hermes retirement
(#423 step 5) and configured off-host durability. The first real use on Melanie's books
also waits for Jason's scoped go and mos-1374's protected manual VM1012 backup before the
first real import, handled by its authorized human operator, not this design seat. All starts are human-only; `library.convert` has no role
grant or agent request path and stays a hard wait unless an approved PRD changes it.
Nothing in this document authorizes conversion, new private story creation or deployment.
Q234's exact frame CSP, mos-1363 and S0 M1–M14 remain unchanged implementation gates.
mos-1372 D9 replaces the prior W4 O2-only-conversation, per-document-grant and per-send-share
requirements for Case 2 lookups. Agents read converted stories through the normal Case 2
lookups in any thread or room under the same live project/universe/source-scope checks as
Markdown canon/playground. Final accepted text follows that access. Under mos-1379,
editor.agentReadComments and editor.agentReadTrackedDeletions are human-only booleans,
both false by default. The former gates comment stories; the latter gates original/markup
views. This is two settings, not a role-level allowlist or per-document grant. They can then use existing supporting-Markdown write tools under
Q223. The agent never writes a story/DOCX/archive file. D9 is marked as a choice for Jason
in PRD 1.17 approval; it is design text, not an already approved role/policy expansion.
No code may rely on that changed requirement before the approved PRD and independent review.
Human import commits the verified DOCX to a private staging ref first and obtains its
off-host push acknowledgment. It then creates/pushes the source archive move+mark through
new human-only bus plumbing on the C2-02/C2-03b writer, not two single-path saves. Finally
one host publication protocol advances writing-published and the catalogue under the
publication/read lock. No staged ID is reader-visible before catalogue CAS. Before that
switch, agents read the source at its pinned commit; sync cannot advance it early. After
it, only the current DOCX is a chapter. Pre-push failure leaves source Markdown unmoved;
after archive push, failure is a visible resumable pending operation, never an assertion
that nothing moved, a rollback push or Markdown revival. Old bytes/history remain.
The archive is in the source-repository folder set by a human in the library mapping.
There is no default; missing/invalid folder keeps conversion closed. It is recorded with
converted date, source commit/blob/path and replacement ID in the operation record. It is
read-only in the Console. Explicit `archived` scope returns only requested authorized
records, always marked and non-canon; default/current queries never opt into it. An old
source lookup returns a typed conversion record and routes an authorized DOCX read, never
stale Markdown or fake DOCX lines. Historical line cites still verify at commit/blob and
show converted/historical state; archive access alone is not current story authorization.
Pre-conversion text already in thread history is not rewritten/refreshed; its cites verify
against their original commit/blob and show historical/converted state, not the current DOCX.
A Markdown file recreated at a converted old path is unmapped, neither canon nor playground,
excluded from lookups and flagged to the human. A new Markdown story at a different path in
a converted book stays canon until import, flagged and offered for human import; no automatic
conversion. Existing playground scope rules remain. Clickable DOCX editor links stay; no
DOCX graph exists yet. A Connections graph and its tests wait for Jason's J-b answer.
Every conversion runs the pinned extractor before archiving and refuses unsupported output.
An independently reviewed importer preserves every wiki token and front-matter key.
The v1 extractor does not accept OOXML hyperlinks: emit Markdown label/URL as literal text
with a fidelity-report entry for lost clickable behavior, never w:hyperlink/r:id. Bare URLs
stay literal; wiki links stay exact and host-clickable. Unsafe/unrepresentable URLs refuse.
This handled literal mode is explicitly confirmed before archive push; metadata
moves to the canonical manifest (type/name/appears_in/relationships feed the index). Links
resolve across Markdown/DOCX through owned aliases, not host paths. A lost link fails the
fidelity report. Plain links/front-matter values resolve or raise R4; unresolved chapter
embeds must not take the old silent attachment-drop path. Images/.canvas/.base remain attachments.
## 2. Document identity, order and freshness
Host code alone opens `<dataRoot>/writing/<business>/<project>/`. Opaque document IDs resolve
through the canonical manifest, never caller paths. Conversion preserves book/chapter identity
and scope, binding the original path/name as an alias to the DOCX ID. New stories get a fresh
ID and the human-selected universe/book or playground. No format-based canon promotion.
The map tells authorized agents format, source scope, owned location and current version;
archived entries are available only in explicit archived requests. No host paths/credentials.
A lookup snapshots the reachable committed manifest and DOCX blob from one publication.
No worktree, draft, archive or engine-memory fallback. `refs/heads/writing-published` is the
canonical served ref. A document's publications are the first-parent commits adding or
changing its blob/manifest entry; sibling-only saves do not change its currentCommit.
History locators name only such reachable publications, with current project/universe checks.
Deleted entries refuse until explicitly reinstated by an authorized human. New local saves
publish before acknowledgment. A lookup starting after an acknowledged save returns that
save or a later one and names it. A lookup already in flight stays on its captured version;
never label an observed older snapshot latest. Recheck live access before emitting text.
D10's ordered chapter-ID manifest drives manuscript paging and next_chapter after conversion,
replacing row216's initial path-order rule (RULINGS.md:32–34). Before the first conversion,
seed the order from that existing rule; replace each source entry with its DOCX identity in
place. A human reorder is a manifest commit. next_chapter never names an archive. Pending
unconverted files retain their legacy identity/scope until their individual publication
switch; no file has two working formats and new stories start as DOCX. Book-null notes
stay out of manuscript; hybrid exclusions and source-universe boundaries still apply.
## 3. Exact wire schema, version 1
All objects reject unknown keys. IDs are nonempty ASCII `[A-Za-z0-9_-]{1,128}`;
commits/blobs are lowercase 40-hex Git object IDs in the repository's current
SHA-1 object format. A future object format requires a new schema revision.
Digest values are lowercase 64-hex SHA-256. Integers are safe nonnegative
JSON integers. No floats, coercion, duplicate JSON keys or implicit defaults
except the explicitly listed request defaults below. These are proposed DOCX records for the Case 2 lookup/citation union.
A locator is exactly:
```json
{
"kind": "docx-range", "version": 1,
"business": "acme", "project": "book", "document": "chapter_1",
"commit": "<40 lowercase hex>", "blob": "<40 lowercase hex>",
"extractor": {"id": "mosaic-docx-text-v1", "revision": "<64 lowercase hex>"},
"part": {"class": "body", "name": "word/document.xml", "story": "main"},
"paragraph": {"ordinal": 0, "xmlId": null},
"start": 0, "end": 5, "textView": "final", "quote": "Hello",
"quoteDigest": "<sha256 of UTF-8 quote>"
}
```
Part triples are exact: body/main uses the body part; footnote/endnote/comment
uses its class-matching part and a canonical nonnegative decimal story ID
(`0` or `[1-9][0-9]*`), never a user path. Paragraph `xmlId` is JSON null
when absent. A textView is always recorded in every locator; there is no
resolver default. quote is a nonempty valid Unicode string bounded to 16,384
code points and 64 KiB UTF-8. Unknown enum values or unexpected types refuse.
The ordinal-primary rule below deliberately refines D25's wording ("IDs
when present, otherwise ordinal"): a possibly duplicated paraId is a required
cross-check, never the lookup key. This is an O2-only design choice for Sage's
implementation brief, not an amendment to Case 2.
`paragraph.ordinal` is the zero-based paragraph index within the selected
story, in deterministic XML document order, including empty paragraphs and
table-cell paragraphs. `xmlId` is null exactly when the selected node has no w14:paraId, otherwise the literal eight-hex `w14:paraId`,
canonicalized uppercase. Ordinal is always present: paraId alone is not
unique or stable enough. The key is mandatory: passing null for a node that has the attribute refuses.
The non-null value must equal that node's attribute; duplicated IDs do not
trigger a search, since ordinal selects the node. Mismatches refuse.
Thus identical paragraphs remain distinct. `start < end <= codePointLength`
selects one paragraph, end exclusive. A multi-paragraph selection has the exact wrapper below, not a bare array:
```json
{
"kind":"docx-selection", "version":1,
"business":"acme", "project":"book", "document":"chapter_1",
"commit":"<40 lowercase hex>", "blob":"<40 lowercase hex>",
"extractor":{"id":"mosaic-docx-text-v1","revision":"<64 lowercase hex>"},
"part":{"class":"body","name":"word/document.xml","story":"main"},
"textView":"final",
"ranges":[
{"paragraph":{"ordinal":0,"xmlId":null},"start":1,"end":5,"quote":"ello","quoteDigest":"<64 lowercase hex>"},
{"paragraph":{"ordinal":1,"xmlId":null},"start":0,"end":5,"quote":"World","quoteDigest":"<64 lowercase hex>"}
]
}
```
It has 2..32 ranges, all sharing the wrapper's exact document, publication,
blob, extractor, view and part. Ordinals are consecutive and increasing.
First range ends at its paragraph length, last starts at zero; intermediate
ranges cover whole paragraphs. Each range verifies its own quote/digest;
no inserted newline is included in any digest. Empty intermediate paragraphs
are represented by start=end=0, quote="" and SHA-256 of empty UTF-8; the first
and last are nonempty. Total quote budget is 16,384 code points and 64 KiB
UTF-8 for the entire selection. A one-paragraph selection uses docx-range
only: there is one canonical representation. No auto-merging, cross-story
selection or clipping. Resolver's locator union and a range chip accept
either exact kind. An atomic selection fails entirely if any range fails;
a response never returns only the valid fragments.
`extractor.revision` is the digest of a canonical build manifest containing
extractor source blob IDs, projection rules revision and locked parser/ZIP
library versions. The release pins that manifest and independently verifies
its digest. It is not caller-supplied executable code or a mutable version
label. Its canonical manifest is exactly `{manifestVersion:1,id,rulesRevision,
sources,dependencies,formattingProperties}`. id is mosaic-docx-text-v1,
rulesRevision is integer 1; sources is a path-sorted array of `{path,blob}`
for every extractor/transitive source input; dependencies is a name-sorted
array of `{name,version,integrity}` from the lock, including ZIP/XML parsers;
formattingProperties is a sorted unique array of expanded XML names.
Duplicate keys/entries refuse. Canonical bytes are compact JSON, UTF-8,
no BOM/newline, recursively lexicographic ASCII object-key order; strings
escape only quote/backslash and U+0000..001F (lowercase four-hex \u escapes),
with other scalar values literal. Arrays preserve the specified sorted order,
integers are decimal without leading zeroes. revision is SHA-256 of those
bytes. Independent tooling must reproduce it. Server readiness is derived
from the verified release artifact containing that manifest and its reviewed
formatting list, not any human-authored config field.
Resolver requires that exact available revision; changed extraction
rules create a new revision, never silently reinterpret an old locator.
A paragraph extraction record is exactly:
```json
{
"part": {"class": "footnote", "name": "word/footnotes.xml", "story": "7"},
"paragraph": {"ordinal": 0, "xmlId": null},
"textView": "final", "text": "Note text", "length": 9,
"textDigest": "<sha256 UTF-8 text>",
"anchors": [], "wikiTokens": []
}
```
Anchors have the exact shape `{kind,story,offset}`; allowed
kinds are `footnote-reference`, `endnote-reference`, `comment-start`,
`comment-end`, `comment-reference`; story is a canonical decimal nonnegative XML
ID string (`0` or `[1-9][0-9]*`, the same as note/comment locator stories),
offset a code-point boundary in this record. They never grant
access to their target. wikiTokens have exactly `{start,end,literal,form,target,label,heading}`.
form is link/label/heading/embed; label and heading are null except in their
corresponding form. target is 1..256 code points without `[`, `]`, `|`, `#`,
control characters or newline; a label/heading is 1..256 code points without
brackets, `|`, `#`, controls or newline. literal is respectively `[[target]]`,
`[[target|label]]`, `[[target#heading]]` or `![[target]]`. start/end are exact
paragraph code-point bounds, including the exclamation for embed. No nested
forms or combined label+heading/embed variants are interpreted in v1; they
remain text. Tokens are maximal nonoverlapping complete forms in left-to-right
order, with their literal equal to the text slice. They are not instructions
or external links. All text
and metadata are untrusted document data. Part/story IDs, excerpts and
comment content never enter system prompts as instructions.
## 4. Story classes and package validation
Version 1 accepts transitional WordprocessingML namespace
`http://schemas.openxmlformats.org/wordprocessingml/2006/main`, relationships
`http://schemas.openxmlformats.org/package/2006/relationships`, office
relationship types rooted at
`http://schemas.openxmlformats.org/officeDocument/2006/relationships/`, and
`w14:paraId` from `http://schemas.microsoft.com/office/word/2010/wordml`.
Prefixes are irrelevant; expanded namespace/local names decide. Strict OOXML
and unknown alternate-content choices refuse until a separately pinned
extractor supports them; never guess equivalent namespaces.
| Class | Exact part names | Story selector | Agent exposure |
| --- | --- | --- | --- |
| body | word/document.xml | main | final by default; existing project/universe access |
| footnote | word/footnotes.xml | w:footnote/@w:id | own story; same project/universe access as its document |
| endnote | word/endnotes.xml | w:endnote/@w:id | own story; same project/universe access as its document |
| comment | word/comments.xml | w:comment/@w:id | explicit part request plus human comments setting; same project/universe access |
| layout | word/headerN.xml, word/footerN.xml (N positive decimal) | none | denied in v1 |
| supporting | separately declared non-story document | separate identity | C2 tools/scopes only; no DOCX scope inheritance |
| opaque | media, styles, numbering, theme, fonts, custom XML, embedded objects | none | no raw bytes through O2 reader |
Body/note/comment ownership comes solely from relationships in that committed
package, not filenames supplied by a request. A note/comment belongs to one
DOCX, never the book or an adjacent chapter. Classify reserved notes by
w:type in {separator, continuationSeparator, continuationNotice}, with any
canonical signed integer ID (`0` or `-?[1-9][0-9]*`, no plus/leading zeroes),
not by sign. A normal note has absent type or type normal and a canonical
nonnegative ID; unknown types refuse. Reserved notes are structural and never
readable stories. Any document reference to a reserved note refuses, including
an id-0 continuation separator; the reference must resolve to a normal note. Duplicate story IDs, dangling references or overlapping
ambiguous comment ownership refuse extraction. Unreferenced comment/note
stories are not agent-readable. Cross-paragraph comment anchors may be
recorded, but never concatenate their text with body text.
The root `_rels/.rels` must contain exactly one internal officeDocument
relationship to `word/document.xml`. Its matching content type is
`application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml`.
Optional footnotes/endnotes/comments each have at most one matching internal
relationship and their matching `...wordprocessingml.{footnotes,endnotes,comments}+xml`
content type. Their relationship targets must be the exact part names above.
Reject normalized-path aliases, absolute paths, traversal, encoded separators,
backslashes, duplicate ZIP names, symlink entries, encryption and overlapping
ZIP data. Never extract ZIP entries onto the filesystem.
Only internal relationships of types officeDocument, styles, numbering,
settings, webSettings, fontTable, theme, image, header, footer, footnotes,
endnotes and comments are accepted. Resolve internal targets relative to the
owning part within the package, reject escape and validate existence/type.
Reject every external relationship, hyperlink relationship, altChunk,
attachedTemplate, OLE, package embedding, VBA/macro content type or executable
part. Textual literal wiki links need no relationship. Unsupported rich
constructs refuse the agent projection, not the human save: the human can
retain a full document without it becoming readable to agents.
Parse XML without DTDs, external entities, XInclude or network/file resolution.
Reject DOCTYPE/entity declarations. Bound before allocation: compressed blob
32 MiB, total expanded bytes 128 MiB, each entry 16 MiB, 2048 entries,
expansion ratio 100:1 both per entry and for the total (nonempty expanded data with zero compressed bytes refuses), XML depth 128, 1,000,000 nodes, 100,000 paragraphs,
1,000,000 code points per paragraph and 10,000,000 per document. Extraction
has a 5 s host deadline and bounded worker memory of 256 MiB. Exceeding any
bound yields `editor-document-unsupported`, no truncated success. These are
initial server safety ceilings, not grants or business quota settings;
changing them requires reviewed parser evidence. CRC/size mismatches refuse.
## 5. Deterministic reading views
`textView` enum is `final`, `original`, `markup`. Default requests use final.
Final is the accepted-reading projection, not an accept-changes operation.
A text run is visible in final iff no ancestor is w:del or w:moveFrom; in
original iff no ancestor is w:ins or w:moveTo. This ancestor veto applies to
nested revisions, so an insertion inside a deletion is absent in both final
and original. Markup includes both in source order with revision spans for
every revision container (nested spans may overlap). w:t and w:delText use
the same ancestor rule, never special substring searches. Revision IDs are
canonical nonnegative decimals; malformed or unmatched move ranges refuse.
Paragraph-mark revisions under pPr/rPr mark only the paragraph boundary,
not the runs' text. A mark-only w:ins or w:del changes **no projected text**
in final or original: run content follows the ancestor rule alone. Although
accepting a mark deletion in Word joins paragraphs, this locator projection
never merges, splits or renumbers XML paragraphs in any view. It preserves
the text on both sides as separate ordinal records. In markup a paragraph
mark contributes a zero-width span at that paragraph's code-point length,
kind paragraph-mark-insert or paragraph-mark-delete with its revision ID;
it never becomes a whole-paragraph deletion span. A mark-only insertion's
text stays in original; a mark-only deletion's text stays in final. Inline
run revisions remain independent. No view edits or accepts/rejects changes.
Original/markup require editor.agentReadTrackedDeletions=true; comment stories require
editor.agentReadComments=true. Both are human-only and false by default (mos-1379); a comment
in original/markup needs both. Check them in addition to ordinary project/universe access,
refusing with editor-access-refused and no text when off. No role-level allowlist or
per-document grant is added. A final-body read stays available and never silently includes
deleted revisions/comments. Human editor review/save remains full-featured and unaffected. Revision author/date metadata
is omitted from agent responses in v1.
Closed story/run leaf table (all names in w namespace unless stated):
| Leaves | Text/anchor contribution |
| --- | --- |
| t, delText | decoded text subject to view/ancestor rule |
| tab | U+0009 |
| br, cr | U+000A, regardless of page/column type; layout kind does not affect offsets |
| noBreakHyphen | U+2011 |
| softHyphen | U+00AD |
| annotationRef | zero text; only allowed in comment story |
| separator, continuationSeparator, continuationNotice | structural only, allowed only inside reserved footnote/endnote stories; never projected |
| footnoteRef, endnoteRef | zero text; only in matching note story |
| footnoteReference, endnoteReference | zero text; matching anchor at current offset with canonical story ID |
| commentRangeStart, commentRangeEnd, commentReference | zero text; matching comment-start/end/reference anchor |
| moveFromRangeStart, moveFromRangeEnd, moveToRangeStart, moveToRangeEnd | zero text; validate paired IDs, do not duplicate revision text |
| bookmarkStart, bookmarkEnd, permStart, permEnd, proofErr, lastRenderedPageBreak | zero text; structural only, never access grants |
| sym, ptab | refuse requested story (font/position dependent) |
| fldChar, instrText, delInstrText, fldSimple | refuse requested story, including field results |
| drawing, pict, object, txbxContent, subDoc, altChunk | refuse requested story |
Leaf validation covers **the entire selected XML part**, including all its
normal and reserved stories, before any requested story is projected. Reserved
separator/continuation notes are structurally validated against this same
closed vocabulary, with separator/continuationSeparator/continuationNotice
permitted only there, never a readable locator story. Each reserved ID/type
must be internally consistent; duplicate IDs within a part refuse. A separator
leaf in a normal note/body/comment refuses. A valid separator in a reserved
note does not make readable footnotes/endnotes unsupported.
The table is exhaustive for story/run leaves; unknown leaves refuse, including
nontext leaves not explicitly named. Formatting properties belong only to
the separately closed manifest list. Anchors/range marks under invisible
revision ancestors are omitted in that view but still structurally validated.
Comment author data and ACL-like Word permission markers never supply Mosaic
authority. Unknown extension/AlternateContent text is unsupported, not ignored.
Walk direct story paragraphs and table cells in XML order, including nested
tables in their containing cell order. Paragraph ordinals do not change with
view. Concatenate visible text across adjacent runs with no invented spaces.
Preserve decoded Unicode as stored: no NFC, case folding or whitespace
collapse. xml:space text remains
literal. Offsets count Unicode scalar values, not UTF-16 units or graphemes;
unpaired surrogates/invalid XML characters refuse. Field instructions,
hidden/vanished text and text boxes are not silently omitted: their presence
in a requested story makes v1 projection unsupported. Field results and
unknown semantic text-bearing elements likewise refuse until specified.
The projection traverses only these containers in the w namespace:
body, footnote, endnote, comment, tbl, tr, tc, p, r, ins, del, moveFrom,
moveTo, smartTag and sdtContent. A document root wraps body; note/comment
part roots wrap their corresponding stories. sdt may contain sdtPr (ignored
properties) and sdtContent only. Hyperlink containers are unsupported even
without a relationship. Unknown text-bearing containers refuse. Nontext
subtrees pPr, rPr, tblPr, tblGrid, trPr, tcPr and sdtPr may be ignored only
if they contain no story text elements, field codes, external references,
objects or unknown namespaces. Structural-leaf behavior is defined only by
the closed table above. w:sectPr is layout-only, with relationship targets
validated normally.
Formatting-property descendants are a closed W4b release artifact: its full
expanded-name list is included in the extractor manifest and independently
reviewed before enablement; any name absent from that list refuses. This
artifact can narrow the allowed property subtrees, never add a text-bearing
container to this v1 contract. Missing artifact is no readiness, not a
permissive descendant-text scraper.
Reference marks contribute anchors at the current text boundary, not invented
note numbers or inline comment bodies. Each note/comment is separately paged.
A single range cannot straddle a view, paragraph or story; the selection wrapper
may cover contiguous paragraphs only under section 3. Extract literal
`[[target]]`, `[[target|label]]`, `[[target#heading]]` and `![[target]]`
after concatenating visible runs within one paragraph, so split-run tokens
survive formatting changes. Preserve complete literal bytes as UTF-8 after
XML decoding and code-point start/end; never follow OS paths or external URLs.
Targets resolve only via the host's owned-document resolver, with independent
authorization; unresolved targets stay literal and marked unresolved in human
UI. No link parsing grants reads. Nested/unclosed bracket sequences remain
plain text, and tokens cannot cross paragraph/view boundaries.
## 6. Reading APIs, verification, paging and staleness
These are proposed typed tool schemas over the existing runner socket, not
native WordCraft MCP. The same reader backs Case 2 lookups in any authorized thread or
room under mos-1372 D9. Caller/session/business come from the bound broker.
Agents cannot override them using object fields.
- `editor_read_committed({project,document,version,textView,part,cursor,limit})`:
project, document, version and part are required; only textView, cursor and
limit may be omitted. version is exactly `{mode:"latest"}` or
`{mode:"commit",commit}`; part is
one class/name/story triple above; textView defaults final; cursor is null
on first page, limit 1..100 (default 20). No path, blob or draft argument.
- `editor_resolve_citation({locator})`: verify the exact immutable range;
it does not search for a nearby quote. Return exact quote and locator plus
`currentCommit` and `stale` after current authorization.
- `editor_flag` is W5's metadata-only write; W5 must validate the same
locator before storing a flag and may not write into the document.
Read response is exactly `{version:1, business,project,document,commit,blob,
extractor,textView,part,rows,nextCursor,currentCommit,stale}`. Each row has the
extraction record above. The public envelope contains no absolute paths or
raw package attributes. `nextCursor` is null at end; `currentCommit` is the
current published document commit; stale is exactly commit != currentCommit.
A resolver response is exactly `{version:1,locator,currentCommit,stale}`:
the verified quote is the locator's quote, with no separate unverified text.
There is no default "first part" or automatic descent into notes/comments. The broker-bound business must equal
locator.business; a mismatch is editor-access-refused before object lookup.
Markup additionally requires `revisionSpans` on each
row: array of `{kind,id,start,end}`, kind insert/delete/move-from/move-to/
paragraph-mark-insert/paragraph-mark-delete (mark spans have start=end),
with null-free canonical decimal IDs and valid boundaries; other views omit
that key. Limits cap output at 64 KiB UTF-8 JSON per response, including envelope and cursor. End a page before the first complete
row that would overflow, and return a cursor for that row. This is normal
paging, not partial-row success. If that first row cannot fit even on an
otherwise empty page, return editor-range-too-large with no text. Such a
paragraph is unsupported for agent reading in v1; no subrange read exists.
A human-visible "paragraph exceeds agent reading limit" reason appears only
after authorization. The human editor/save is unaffected. All empty paragraphs
still produce rows and advance the cursor. No page can return the same cursor
without progress.
Cursor is a host-authenticated opaque token binding principal, session,
project/document, commit/blob, extractor, view, part, next ordinal, the complete
project/universe authorization and format-publication revision vector defined in section 7 and expiration (5 minutes). It carries no plaintext content.
Tampering, reuse by another session, wrong request parameters or a revoked
scope refuses. A latest cursor continues its captured snapshot with stale
metadata if a save intervenes; starting again with null cursor returns the
new publication. Cursor is not a capability and grants are rechecked every
page. Repeated ordinal ranges are stable within one committed projection.
Resolver steps: authorize the current principal, live project/universe/source scope and publication membership; load
that commit's manifest/blob; validate package; run the exact pinned extractor;
select exact part/story/ordinal and mandatory XML-ID value; select code-point range;
require literal quote equality and SHA-256(UTF-8 quote) equality. Require both
blob and commit membership, not digest alone. Any mismatch refuses
`editor-citation-invalid` without guessed text. After newer publication the
old valid locator returns `stale:true` with old text; it never auto-relocates
to identical paragraphs or another note. Jump opens that committed view with
an explicit old-version label. If current grant no longer allows it, even
old quote resolution refuses and the UI hides cached content.
Errors: `editor-context-unavailable` for missing readiness; `editor-access-refused`
for absent live project/universe authorization (same response for nonexistent or foreign IDs);
`editor-document-unsupported` for parser limits or unsupported features after
authorization; `editor-version-unavailable` for authorized missing history or
extractor; `editor-citation-invalid` for locator/quote mismatch;
`editor-cursor-invalid` for invalid paging; `editor-range-too-large` for size.
The exact refusal envelope is `{ok:false,error:{code,message}}`; code is one
of those enum strings or editor-policy-conflict (409, stale catalogue/settings revision), and message is fixed server text for that code (no user
input). Both missing/foreign and ungranted IDs use the same code/message/status
403. Syntax errors before identity lookup use editor-citation-invalid, 400;
context unavailable is 503, cursor-invalid 400, version unavailable 409,
unsupported/range-too-large 422. Successful tools return `{ok:true,result}`
where result is the defined response; errors never include result/partial
rows. Return no source text, XML, path or untrusted parser error in refusals.
### 6.1 Case 2 query and citation adapters
Keep `library_find`, `library_get`, `library_search`, `library_manuscript` and the universe
lookup. Host adapters join Markdown metadata/read results and the committed DOCX extractor
into one typed, scope-filtered index; only current identities enter normal lookups. A request
on a converted alias returns its conversion record and the authorized DOCX result. Every
answer names format, store/owned ID and captured commit. No loss of chapter search/manuscript
or supporting-doc workflow is accepted. Same project/universe/source-scope rules apply in
all threads/rooms; archive/draft scope never becomes canon because its format is DOCX.
DOCX pages use paragraph locators and opaque cursors, not invented line equivalents.
Retain section 6's 64-KiB/1..100 paragraph bounds (default20); human reply limits still apply.
A manuscript cursor binds ordered-manifest commit, the selected document publication vector,
principal/request/scope revisions and expiry. Resume only that snapshot with current access;
changed/foreign cursor refuses. next_chapter uses the next visible current manifest ID,
never an archive or a guessed sort of DOCX names. Index/cache keys include local publication
and extractor revisions; no minute-old Markdown refresh window is copied to DOCX.
C2-06's checked cite union preserves legacy `{path,commit,lines,quote,as?}` for Markdown and
adds `{kind:"docx",locator,as?}` where locator is section3's exact range/selection. Never infer
a cite kind from a .docx suffix or parse DOCX as lines. The host checks project/universe,
source canon/playground/archive status, fetched provenance, quote and commit before message
storage. requireCitation and as:canon apply to both; historical converted/archived sources
cannot assert current canon. The host reads Mosaic-Agent trailers from the correct source
repository or writing-store publication, never trusts an agent author field. Console and
the shared reply renderer show format, locator/lines, version, staleness and converted state.
C2-18 Discord remains a separate ruled delivery task, not enabled by a shared renderer.
## 7. Existing Case 2 authority, remote durability and restore
### 7.1 Access and supporting writes (reopened M1)
Reuse existing bound business/project/universe access, live holder/role and source scope.
No private O2 conversation ID, per-document access table or send/share token gates a Case 2
lookup. Any existing authorized thread/room may use the checked reader and normal library
tools. No arbitrary native WordCraft MCP, execute, open/save or raw filesystem/git tool is
added. The host store is never mounted in a worker. Rendered/extracted content travels over
the ordinary authorized Case 2 tool/message path and existing transcript/run-record policy;
the withdrawn private-only transcript/output rule cannot forbid that documented workflow.
Grant loss blocks later lookups through existing checks; do not promise erasure of earlier
delivered text or rewrite immutable run evidence. This is the D9 choice for PRD approval.
The existing `library_doc_write`/`library_doc_delete` still require library.write plus the
live supporting-repo Gitea grant and supportingPath before git. They operate only on human-
marked supporting Markdown, with the existing size/base-CAS/seat-author/push/notice/revert
rules. An agent can read a DOCX story and update its character sheet in the same authorized
thread. There is no agent write to DOCX, original story, archive or conversion manifest.
The archive prefix wins over supporting globs; conflicts refuse mapping. Format/status/type
notes in the six creative contracts replace stale 'every item cites lines' wording with
free chat plus optional checked line/DOCX citations under requireCitation. No per-document
export grant or O2-only session is a hidden prerequisite.
The cursor authority revision is the server's current project grant, universe/mapping/scope
revision, the two human review-settings revisions and format-publication generation for
the bound caller/session. It contains no
sharing human or writing_access_events/writing_shares sequence. Check the review settings before every part/view/citation/search/index/context attachment,
not only on first open. No request boolean can enable them. Recheck before every page,
resolution, index hit and message insertion. Scope revocation and format changes invalidate
cached authorization; metadata for missing/foreign IDs uses the same refusal as before.
### 7.2 Selection convenience and ordinary messages
Keep Q233's human-only setting, default a visible removable chip on each send. A chip may
attach only a verified committed locator/version, never unsaved selection text. It helps the
writer point at a passage; it neither grants nor limits the agent's ordinary project/universe
lookup rights and does not freeze a later latest lookup to that older commit. The sent cite
remains immutable historical evidence. Multi-human/thread/room behavior follows existing Case 2
permission checks, not a new one-human conversation restriction. Saved-context/pin records
remain on the bus through their reviewed schema, with no share-token authority layer.
### 7.3 Host-only off-host remote (replaces the ban)
`editor.remoteURL` is a human-only setting, default unset. No same-host bare/filesystem/loopback
remote is the default or qualifies as off-host durability. The human selects an off-stack-host
private destination (for example private Gitea) and separately configures host-only auth.
Until #431 corrects the real seat helper's shared jason.woltje credential route, the remote
must be on a host/account that principal and all seat credentials cannot reach; private
visibility alone proves nothing. Prefer a separate off-host instance. An existing-instance
owner/org qualifies only after denial through the actual helper credential path proves no
jason.woltje access. W3b tests that real helper route and seat identities against an authorized
empty fixture remote, without printing/logging credential values; no dummy-token substitute.
Only the host process pushes. No seat token can list/fetch/clone/fork/push the writing repo,
no seat gets its credential, and no raw Gitea grant or store mount is created. Validate the
owned remote, TLS/host policy and off-host storage identity; reject URL userinfo, unexpected
remotes/object alternates and non-fast-forward updates. Allow host pushes only to refs/heads/writing-published and
refs/heads/import-staging/<operation-id>. A refused candidate retains a private non-reader
staging ref and journal status; after publication the staging ref stays as an audit link.
No automatic deletion or force-update of staging refs. No silent fallback or force push.
Every writing-store commit pushes there. Agents read the local publication immediately;
receipts/UI distinguish local commit and remote pending/failed/synced. Missing remote blocks
production opening. Before source archive push, the staged DOCX must have remote acknowledgment.
A failed later push keeps local commits, queues bounded host retry/readback and shows failure;
it never rolls back the local story. Source archives push through their separate human
library writer. The configured retry deadline is human-only (default30s, 1s..300s).
Remote/provisioning changes require the normal owner authority, never this design execution.
The remote exception is for story git history/manifest; generic stack copies/releases are
not story backups and contain no host credentials. Normal Case 2 output/notes follow the
existing project's approved storage/sharing policy; the former blanket no-backup/no-remote
rule is withdrawn. PRD 1.17 explicitly presents this D7/C4 change to Jason.
### 7.4 Conversion events, rollback --restore and irreversible recovery
W7 owns `writing_conversion_events`: a STRICT append-only table with seq INTEGER PRIMARY KEY,
at TEXT, business/project/document/operation_id/stage TEXT, record_ref/record_digest TEXT;
All fields except seq are NOT NULL; operation_id+stage is unique, no update/delete. The private host journal/record contains source
commit/blob/path, archive path/commit, DOCX commit and conversion date; the row is metadata
and never prose/credentials. Records are flushed before their bus references. Table rows
join stack-release COUNTED and T46 exactly once, so post-backup conversion events contribute
to --events and the existing restore approval/counting behavior. No new private conversation,
per-document grant or per-send share tables are created for D9.
Three recovery cases are required: (1) crash after durable DOCX staging but before archive
push, (2) crash after archive push before publication, and (3) rollback --restore from a
pre-conversion bus backup while archive commits and O2 documents remain. The source is pinned
until final publication in cases1/2; after archive push state is visibly pending, never
'original untouched'. Case3 drops conversion rows only through the counted/approved restore
path. The durable host conversion journal/format registry is not restored from that older bus
backup. A compatible controller compares journal, both git histories, remote acknowledgment
and restored metadata before lookups/writes resume; it reconstructs missing metadata through
new recovery events without reviving Markdown or any old access grant. If reconciliation
cannot prove a single current identity/version, refuse that project's lookups and surface the
pending operation to the human. Do not replay chapter text into an old index or hide event loss.
Incompatible old binaries cannot activate converted projects through the supported controller;
raw privileged rollback tampering is outside the guarantee. Never rewrite git/run history.
Hermes retirement (#423 step5) is a production-opening prerequisite, with old story-write and
store-read access removed before any conversion/new-story operation. W7 checks its retirement
receipt and host capability preflight; no design seat retires services or accesses Melanie's
host. Independent tests use fixtures only. Preserve the existing stack grant/restore behavior;
the previous unimplemented W4 private-share restore-fence/table design is withdrawn with M1,
not backfilled into legacy rows. Conversion's durable registry is not an authorization token.
## 8. Acceptance matrix and release evidence
These are required future fixture gates, not implementation results.
| ID | Evidence required | Negative control / bypass |
| --- | --- | --- |
| A01 | Exact body quote independently recomputed from commit/blob/revision | change quote, digest, blob, commit or extractor; each refuses |
| A02 | Two identical paragraphs and notes have different locators | no content-search relocation; swapped ordinal/story refuses |
| A03 | XML ID absent/duplicate and ordinal behavior | missing/mismatched paraId cannot silently choose another node |
| A04 | Emoji, combining characters, tabs, breaks and split runs | UTF-16 offsets, normalization and whitespace collapse fail |
| A05 | Literal split-run wiki forms retained | no path/URL fetch; malformed/cross-paragraph tokens stay text |
| A06 | Final/original/markup independently verified with moves/deletions; review settings off by default | final read succeeds; original/markup or comment request/resolve refuses until matching human setting, both needed for original comment; no document rewrite |
| A07 | Body/note/endnote/comment exact ownership | orphan/dangling/cross-document references and duplicate IDs refuse |
| A08 | Package allowlist, aliases, CRC, XML/ZIP limits | external rel, macro, traversal, symlink, entity, ZIP bomb and timeout refuse |
| A09 | Commit snapshot and publication ordering | next latest after Saved gets new commit; no worktree/draft fallback |
| A10 | Historical resolve stale label | old quote stays old; removed grant/history refuses without text |
| A11 | Pagination complete/deterministic and bounded | tampered/foreign/revoked cursor and oversized row refuse |
| A12 | Cross-user/business/project/universe denial | foreign project/universe IDs, same blob elsewhere and guessed unpublished objects grant nothing |
| A13 | Selection chip points only at committed text; ordinary lookup authority independent | draft mapping refuses; missing chip does not deny an authorized lookup |
| A14 | Normal project/universe/source-scope checks in every thread/room | pin, guessed ID, foreign universe and revoked holder cannot grant access |
| A15 | Latest after acknowledged save; explicit historical cite stays immutable | chip/per-send snapshot cannot force stale latest results |
| A16 | Host-only store and remote credentials; checked reader routes only | no worker store mount, arbitrary git/engine access or seat remote token; actual seat helper credential denied, not just a dummy token |
| A17 | Existing Case 2 message/transcript policy | no O2-only/raw-session backdoor that skips existing thread/project checks; no false erasure promise |
| A18 | Reader/resolve/flag plus existing Case 2 lookups/supporting writer after gates | native MCP, execute, save, replacement and story comment writes refuse |
| A19 | Unconverted/support Markdown unchanged; converted path returns record and DOCX | no stale archive as chapter or DOCX-as-lines; historical line cite verifies by old commit/blob |
| A20 | Conversion/new story gates W4b/W7/PRD/post-10-27/Hermes/owner go | agent start, missing readiness, early release, fixture flag and missing first-real-book go refuse |
| A21 | Human full-feature save remains separate | unsupported projection yields no agent context, never lossy human save |
| A22 | Scope revocation during extraction | final pre-emission check prevents async stale-authority leak |
| A23 | Sibling chapter save | currentCommit/stale/cursor for untouched document remain unchanged |
| A24 | Full page and oversized paragraph | end before overflow; first oversized row refuses without text; no unreachable subrange claim |
| A25 | Every read/write/tool surface uses existing Case 2 isolation | same document ID across business/universe or replayed cursor refuses |
| A26 | Host-only off-host remote and per-save push | unset/local-only/helper-readable/unexpected remote refuses opening; real helper denial tested; push outage visible, local next lookup still fresh |
| A27 | Conversion restore accounting and durable journal reconciliation | pre-conversion --restore loses counted row but cannot revive Markdown; no lost-event concealment |
| A28 | Reopened M1 supports same-thread DOCX-read then supporting-note write | any room/project-authorized caller works; no per-document/share token; story/archive write refuses |
| A29 | Readiness is reviewed runtime/extractor plus approved PRD, not caller fields | no request/go/setting can assert release or Hermes retirement |
| A30 | Canonical schemas and complete selections | unknown keys, inconsistent ranges, xmlId null mismatch and noncanonical story IDs refuse |
| A31 | Closed leaf/revision table | every leaf/nested rule; mark-only deletion keeps text in final, mark-only insertion keeps text in original; markup mark spans zero-width; Word -1 separator/0 continuation-separator and older 0/1 reserved layouts validate, references to them refuse |
| A32 | Existing grant/restore controls and conversion metadata COUNTED | restore cannot revive grant, current Markdown or uncounted conversion event |
| A33 | Staging/archive/publish journal and operation readback | crash/sync at every boundary; pinned source until publish; post-push failure pending, not undone |
| A34 | Manifest order, typed index/links and format map | next_chapter never archive; draft scope retained; cross-universe/hybrid exclusions and R4/R5/R6 |
| A35 | Per-file fidelity, source history, human controls and missing-folder refusal | all constructs/wiki/front matter preserved; no agent conversion; new DOCX has no Markdown precursor |
Implementation acceptance includes exact schemas/parser fixtures, live project/universe
revocation probes, same-thread supporting writes, remote denial/failure, counted-event restore
cases, Hermes gate, pinned-copy/sandbox closure and G1. All skips are named; an unexercised
guard blocks enablement. Old O2-only/private-share acceptance wording is replaced, not claimed
passed. No test, conversion or runtime experiment ran for this rewrite.
## 9. Reopened review and handoff
Fenton reviews this policy rewrite against mos-1368's A17–A41/Q1–Q16 and mos-1372 D1–D9,
including reopened M1 and A19/A20/A28, host-only remote and C5 restoration. Megavolt's old
APPROVE stays historical at the original blob; no author writes its verdict file. The
locator/projection facts remain source-backed, but the new authority/tool/runtime contract
requires its own independent approval and the Case 2 PRD approval, not a silent addendum.
Owner sends both design blobs/commit to Fenton, Mos and Sage. No code, private document,
conversion, source build/browser test, queue entry or live change is authorized here.