Files
shard-wiki/workplans/SHARD-WP-0008-write-path.md
tegwick 92d5774baf feat(adapters): writable FolderAdapter + positive write conformance (WP-0008 T1)
FolderAdapter(writable=True) declares WRITE+PER_PAGE, implements write() and
current_rev() (mtime token for drift detection). Conformance gains a
content-preserving positive write probe for WRITE-claiming adapters. 5 tests
green, full suite green, pyflakes clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 11:09:43 +02:00

5.3 KiB

id, type, title, domain, repo, status, owner, topic_slug, created, updated, depends_on, state_hub_workstream_id
id type title domain repo status owner topic_slug created updated depends_on state_hub_workstream_id
SHARD-WP-0008 workplan write path — overlay engine, writable adapter, apply-under-drift whynot shard-wiki active tegwick whynot 2026-06-15 2026-06-15
SHARD-WP-0007
12bed418-39d6-47fa-a359-ff04bae6ec99

SHARD-WP-0008 — Write path

Goal

Implement the write path on top of the foundation slice (SHARD-WP-0007): the overlay-before-mutation lifecycle (draft → patch → apply-under-drift) plus write-through for capable shards, faithful to FederationRequirements.md ADR-05, CoreArchitectureBlueprint §8.2 (overlay engine) / §8.6 (apply-under-drift) / §8.1 (overlays are coordination-canonical events). Target capability: edit a page → draft overlay recorded in the decision log → apply (fast-forward) to a writable shard, or refuse on drift, or keep as local truth on a read-only shard, with overlay_state surfaced in provenance (union without erasure).

Non-goal (this slice): three-way/auto merge (refuse-on-conflict is enough now), federation propagation, network API, lossy native-syntax overlays. Those are later.

Guiding rules

  • Overlay-before-mutation (I-5); no silent remote mutation. Detection is core, resolution is policy (I-7). Overlays/decisions are coordination-canonical (the decision log, §8.1).
  • Honour the §11 dependency rule and capability-as-data: write only where the verified profile supports WRITE; everything below write-through degrades to overlay (I-8).

Writable file-store adapter + positive write conformance

id: SHARD-WP-0008-T1
status: done
priority: high
state_hub_task_id: "80492f8e-125c-4015-b3c0-821fbec038e0"

Make FolderAdapter optionally writable (writable=True): declare WRITE + write_granularity=PER_PAGE in the profile, implement write(key, body) (write-through to disk, return the updated Page with a new rev), and current_rev(key) for drift detection. Extend the conformance suite with a positive, non-destructive write probe for adapters that claim WRITE (write a probe key, read back, clean up). Tests: writable round-trip; read-only folder still rejects write; conformance passes for both.

Overlay model + OverlayEngine.draft()

id: SHARD-WP-0008-T2
status: todo
priority: high
state_hub_task_id: "cc6bf9a3-667d-468d-972d-dae51931a657"

coordination/overlay.py: an Overlay value type (id, target identity, base_rev, body, state) and OverlayEngine.draft(identity, body, base_rev) that records an OVERLAY_CREATED event in the decision log (coordination-canonical) and returns the draft. The log fold exposes open overlays. Tests: draft recorded + retrievable via fold; overlay id stable.

Patch rendering

id: SHARD-WP-0008-T3
status: todo
priority: medium
state_hub_task_id: "90d98c16-ed3b-414f-802c-b0400eca6ede"

Render an overlay as a reviewable patch (a Patch with a unified diff of base→overlay body, Markdown/native). Pure function over (base body, overlay body). Tests: patch shows the change; empty patch when unchanged.

apply-under-drift

id: SHARD-WP-0008-T4
status: todo
priority: high
state_hub_task_id: "2a0179b1-802e-44e6-883d-9f1babefee80"

OverlayEngine.apply(overlay_id) with §8.6 semantics: compare overlay base_rev to the shard's current_rev; unchanged → fast-forward (write-through via the adapter, record an applied/MERGE_DECIDED event, overlay state → APPLIED); changed → refuse + re-present as a conflict (no silent clobber); read-only target → stays DRAFT (local truth, fully attributed). Tests: ff apply mutates the shard; drift refuses; read-only keeps draft.

Overlay-aware union read

id: SHARD-WP-0008-T5
status: todo
priority: medium
state_hub_task_id: "4536d74f-3860-4b4c-82d2-e8d20e6e2125"

When resolving a page that has an open overlay, surface it: the read reflects overlay_state=DRAFT in the provenance envelope and (where policy shows drafts) the overlaid body as a local projection over the canonical page — never hiding that it is an unapplied overlay. Tests: page with a draft reads with overlay_state DRAFT; applied/none reads clean.

Wiring into InformationSpace + integration

id: SHARD-WP-0008-T6
status: todo
priority: medium
state_hub_task_id: "ab01fffb-61ad-416c-9f13-fdfbfd503153"

Add InformationSpace.edit(name, body) (write-through if the resolved shard supports WRITE, else create an overlay), overlay(name, body), and apply_overlay(id). Integration test for the full path (write-through on a writable shard; overlay→apply fast-forward; drift refusal; read-only shard keeps a draft). Update SCOPE; pytest + pyflakes green.


Acceptance criteria

  • pytest green, pyflakes clean, no new runtime dependencies.
  • Overlay lifecycle works: draft (logged) → patch → apply (fast-forward) / refuse-on-drift / stay-draft-on-read-only; write-through works for capable shards.
  • No silent remote mutation: applying against a drifted/read-only target never clobbers.
  • Overlays are coordination-canonical (in the decision log); overlay_state is surfaced in provenance (union without erasure).
  • Each task committed; state-hub synced.

Suggested task order

T1 writable adapter → T2 overlay/draft → T3 patch → T4 apply-under-drift → T5 overlay-aware read → T6 wiring + integration.