docs: define reserved notes and initial O2 restore fence
This commit is contained in:
1 parent
54246cb32b
commit
994c3f7fb1
1 file changed
+88
-14
@@ -224,9 +224,13 @@ extractor supports them; never guess equivalent namespaces.
|
||||
|
||||
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. Reserved separator/continuation
|
||||
notes (negative IDs and type separator/continuationSeparator) are structural,
|
||||
not readable stories. Duplicate story IDs, dangling references or overlapping
|
||||
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.
|
||||
@@ -313,7 +317,7 @@ 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 reserved IDs refuse. A separator
|
||||
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.
|
||||
|
||||
@@ -681,16 +685,25 @@ unvalidated JSON. No existing C2 messages/events/sessions column changes.
|
||||
| writing_shares | conversation TEXT FK, message TEXT FK, document TEXT, payload_ref TEXT, payload_digest TEXT, operation_id TEXT UNIQUE; UNIQUE(conversation,message,document) |
|
||||
|
||||
Each table also has business/project columns if not otherwise listed; FK and
|
||||
application checks require agreement, not just ID existence. The canonical message content object is exactly `{body,provenance}`: body is
|
||||
application checks require agreement, not just ID existence. The canonical message content object is exactly `{version:1,business,project,row,nonce,body,provenance}`:
|
||||
row is the owning writing_messages row ID; nonce is fresh cryptographically
|
||||
random 32-byte lowercase hex, stored only inside the private object, not its
|
||||
metadata backup. body is
|
||||
the complete human/agent message string; provenance is an array of `{document,share,commit,blob,extractor}`,
|
||||
sorted by document/share; every entry requires live scopes. The share content
|
||||
object is exactly the full section 7.3 payload, including any quoted selection.
|
||||
object is exactly `{version:1,business,project,row,nonce,payload}`, where row
|
||||
is its writing_shares row ID, nonce has the same fresh/private rule, and
|
||||
payload is the full section 7.3 record including any quoted selection.
|
||||
Neither message bodies nor share payloads/quotes enter bus.sqlite, WAL,
|
||||
events, SQL error logs or backup manifests. Human messages with no O2
|
||||
attachment have provenance=[] but use the same private content store.
|
||||
content_ref/payload_ref are opaque 64-hex object names, not paths; their
|
||||
corresponding digest equals SHA-256 of the exact canonical UTF-8 object.
|
||||
Objects reside at writing-context/objects/<digest>.json, with no remote or
|
||||
Objects reside at writing-context/objects/<business>/<row>/<digest>.json;
|
||||
row/business/project must match both reference metadata and the authorized
|
||||
caller. No cross-business or cross-row deduplication; retention is per owning
|
||||
row and cannot delete another business's object. The private random nonce
|
||||
prevents a metadata digest from confirming a guessed short body. No remote or
|
||||
release-backup copy. Write/flush the immutable object before committing its
|
||||
bus reference. A failed transaction leaves only an inaccessible orphan,
|
||||
never a visible partial message/share; a missing or mismatched object refuses.
|
||||
@@ -724,7 +737,7 @@ its title, quote or prompt. No live rollback is part of acceptance testing.
|
||||
|
||||
The existing release behavior must be explicitly accounted for: at this base
|
||||
`scripts/stack-release.sh:474-493` copies bus.sqlite into
|
||||
`<dataRoot>/backups/stack/<ACT>/bus/`; restore_store at :496ff moves current
|
||||
`<dataRoot>/backups/stack/<ACT>/bus/`; restore_store at :498ff moves current
|
||||
bus/ to `<dataRoot>/bus.post-attempt-<stamp><suffix>/`. rehearse reads backup
|
||||
stores, and release never prunes them. These paths remain **O2-classified
|
||||
metadata stores** even though content/quotes are outside SQLite. Directories
|
||||
@@ -756,7 +769,8 @@ An **independent host-private fence** lives outside bus/ and every backup:
|
||||
`<dataRoot>/writing-control/restore-fence.json`, directory 0700, regular file
|
||||
0600, no links/mounts/remote/source-copy/rehearse access. Its exact schema is
|
||||
`{version:1,epoch,restoreOperation,droppedRowsDigest,confirmedBusinesses}`.
|
||||
epoch and restoreOperation are host-generated opaque IDs; droppedRowsDigest
|
||||
epoch is a host-generated opaque ID; restoreOperation is null before the
|
||||
first restore, otherwise a host-generated opaque operation ID; droppedRowsDigest
|
||||
is SHA-256 of the canonical sorted dropped `(table,id)` list (empty allowed);
|
||||
confirmedBusinesses is a sorted unique array of authenticated business IDs.
|
||||
Only the trusted release controller and existing owner-proof handler write
|
||||
@@ -764,6 +778,23 @@ it by durable atomic replacement; agents/testers/request paths cannot.
|
||||
It is not a human-editable readiness setting: verified release readiness is
|
||||
still required, and this file is an additional independent deny fence.
|
||||
|
||||
**First creation:** the compatible release controller durably creates the
|
||||
fence as part of W4b's first schema migration, before committing those empty
|
||||
tables or enabling any handler. It uses a fresh epoch, restoreOperation=null,
|
||||
droppedRowsDigest=SHA-256 of the canonical UTF-8 empty JSON array `[]`, and
|
||||
confirmedBusinesses=[]. Every initial writing row uses that epoch. A normal
|
||||
never-restored store does **not** require editor.restore.confirm: the
|
||||
confirmation gate applies only when restoreOperation is non-null. Initial
|
||||
live grants/shares and verified artifact readiness are still mandatory.
|
||||
|
||||
Initialization is allowed only when the pre-migration schema has no writing_*
|
||||
tables/history and there is no existing fence. If a crash leaves a durable
|
||||
initial fence but the schema transaction uncommitted, migration resumes with
|
||||
that same epoch, not another initial state. If writing tables/history exist
|
||||
and the fence is missing/malformed, fail closed; never repair by creating a
|
||||
new initial fence. Creating an initial fence is not a way around a previous
|
||||
restore or revocation. W4b acceptance exercises both migration crash orders.
|
||||
|
||||
Before **any** store swap/restore (not just one with nonzero counts), the
|
||||
current compatible controller durably creates a fresh epoch, records dropped
|
||||
writing rows and clears confirmedBusinesses. If fencing fails, restore
|
||||
@@ -785,10 +816,14 @@ and returns `{ok:true,result:{business,epoch,confirmed:true}}`. It restores
|
||||
a fresh dedicated conversation/default policy and fresh human chips must
|
||||
be created explicitly. Past rows may be inspected by an authorized recovery
|
||||
operator as metadata, but never used as current authority or prompt replay.
|
||||
Every read/resolve/cursor/share checks both business confirmation and matching
|
||||
restore_epoch; old object bytes remaining on disk are not capabilities.
|
||||
Every read/resolve/cursor/share checks matching restore_epoch and, when
|
||||
restoreOperation is non-null, that business's explicit confirmation; old object bytes remaining on disk are not capabilities.
|
||||
Thus even owner confirmation cannot revive a previously revoked old share.
|
||||
Missing/malformed/rolled-back fence state denies O2; --events N approves a
|
||||
Missing/malformed fence state denies O2. This current-epoch file does not
|
||||
claim to detect a privileged manual rollback of both fence and database;
|
||||
the supported restore protocol never restores the fence from a backup and
|
||||
always rotates it first. A same-uid operator bypassing that protocol is not
|
||||
a boundary this file can prove. --events N approves a
|
||||
store operation only and is never a substitute for this recovery protocol.
|
||||
|
||||
Acceptance seeds a secret in a content object and a share, takes a backup,
|
||||
@@ -855,8 +890,8 @@ no fixture-only readiness flag may exist in production APIs.
|
||||
| A28 | Dedicated mode vs C2 | mixed attachment/resume/fork denied; unchanged C2 supporting writes/replies fixtures pass |
|
||||
| A29 | Two humans/viewer/grant revisions | viewer cannot share; second human cannot join or reuse context; all cursor authority fields checked |
|
||||
| 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; reserved note leaves validated but never projected |
|
||||
| A32 | Revocation after backup, then restore | all writing_* counted/classified; old share refuses before/after owner confirmation; fence survives crash and no secret marker in backup/post-attempt/rehearse paths |
|
||||
| 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 | Initial migration and revocation/restore | initial null-operation fence needs no restore confirmation but no grant is implicit; non-null restore fence needs confirmation and fresh authority; all tables counted/classified; old share stays refused; crash/backup-marker sweeps |
|
||||
|
||||
Implementation acceptance includes writing, bus, harness, business, WebUI,
|
||||
seat mount/import closure and stack-copy/release fixtures; explicit production
|
||||
@@ -905,3 +940,42 @@ fence changes epoch before any store swap; owner confirmation cannot revive
|
||||
old-epoch grants/shares. A32 tests revocation/restore and secret-marker sweeps.
|
||||
R2-N1: agent grant subject means agentInstance. R2-N2: structural leaves have
|
||||
one table. This remains design only; no code, restore, parser run or test.
|
||||
|
||||
## Round 4 changes against review 9fb999abf
|
||||
|
||||
R3-B1: reserved-note classification is by type with any canonical signed ID,
|
||||
not sign; normal notes require nonnegative IDs, and references to reserved
|
||||
notes refuse. A31 covers both actual Word layouts. R3-B2: first migration
|
||||
creates the durable initial epoch before schema commit; null restoreOperation
|
||||
needs no recovery confirmation, a restored epoch does. Missing established
|
||||
fences never reinitialize. A32 covers first enable and post-restore states.
|
||||
R3-N1: business/row/private random nonce are part of each content object and
|
||||
its path, so no cross-business deduplication or guessed-body digest oracle.
|
||||
R3-N2: removed the unsupported claim to detect privileged manual rollback
|
||||
of the fence itself. R3-N3: restore_store anchor corrected to :498.
|
||||
|
||||
### Public Word fixture confirmation (not an extractor test)
|
||||
|
||||
Inspected only public Microsoft-maintained test packages in memory using
|
||||
Python ZIP/XML readers, not the O2 parser or a live/user document. No binary
|
||||
was imported into this repository. Source:
|
||||
[OfficeDev/Open-Xml-PowerTools FootNote.docx](https://github.com/OfficeDev/Open-Xml-PowerTools/blob/a9187c5ec4199106562ec91c5ffd9f355251253b/NewDocxDocuments/FootNote.docx),
|
||||
14,214 bytes; DOCX SHA-256
|
||||
`40e2de78f0f70d8acf3db734df13f107c92986f1a40865cdf9772a8b55ab5e20`.
|
||||
Its app properties identify Microsoft Office Word, version 15.0000.
|
||||
footnotes.xml has separator=-1, continuationSeparator=0, normal note=1;
|
||||
endnotes.xml has separator=-1 and continuationSeparator=0.
|
||||
footnotes.xml SHA-256
|
||||
`1da08d9c0a4a1af2706c035dfb176defd179686f81418134b796d49649e850a0`;
|
||||
endnotes.xml SHA-256
|
||||
`f83e7f1c9f91b44db26b147b22ca615a13488bc6a8084febb392ee00a6ca4f5e`.
|
||||
This confirms the reviewer's -1/0 example in a Word-identified fixture.
|
||||
|
||||
An older independent Microsoft SDK fixture confirms why IDs cannot define
|
||||
the class:
|
||||
[Open-XML-SDK ForTestCase/footnote.docx](https://github.com/dotnet/Open-XML-SDK/blob/431ab05cf160248cc3885a4a766026d4f8243792/test/DocumentFormat.OpenXml.Tests.Assets/assets/TestDataStorage/v2FxTestFiles/ForTestCase/footnote.docx),
|
||||
69,706 bytes, SHA-256
|
||||
`26dc62a5d00e2c3c1df60e0d5bf1cac43b142a090ea595b9ad11ce73e3dab268`.
|
||||
It identifies Microsoft Office Word 12.0000 and uses reserved IDs 0/1 in
|
||||
both parts, with normal footnotes 2/3. No claim is made that the whole
|
||||
packages pass v1's otherwise deliberately restrictive projection rules.
|
||||
Reference in new issue
Block a user