Compare commits

...

2 commits

Author SHA1 Message Date
5b8bcaed89 chore(embedded): cut v0.0.25-beta 2026-05-29 14:37:10 -05:00
c489a78f34 feat(server): enable edit-history on the project-level personal workspace
Per the working-folder design: <project>/working/<email>/ is each user's
personal workspace (public by default, owned by the creator who can privatize
via .zddc). The post-reshape defaults had stripped that node to a bare
aggregator, so personal markdown drafts got no history. Add history: true +
an auto_own (un-fenced) per-user-home rule to the project-level working node.
archive/<party>/working/ keeps its own history: true. Scope stays working-only
(staging/reviewing unchanged).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-29 14:36:56 -05:00
9 changed files with 43 additions and 17 deletions

View file

@ -2582,7 +2582,7 @@ td[data-field="trackingNumber"] {
</svg>
<div class="header-title-group">
<span class="app-header__title">ZDDC Archive</span>
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.25-beta · 2026-05-28 19:19:54 · 9972e67</span></span>
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.25-beta · 2026-05-29 19:37:02 · c489a78</span></span>
</div>
<button id="addDirectoryBtn" class="btn btn-primary">Use Local Directory</button>
<button id="refreshHeaderBtn" class="btn btn-secondary hidden" title="Refresh Data"></button>

View file

@ -2476,7 +2476,7 @@ body {
</svg>
<div class="header-title-group">
<span class="app-header__title">ZDDC Browse</span>
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.25-beta · 2026-05-28 19:19:54 · 9972e67</span></span>
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.25-beta · 2026-05-29 19:37:02 · c489a78</span></span>
</div>
<button id="addDirectoryBtn" class="btn btn-primary">Use Local Directory</button>
<button id="refreshHeaderBtn" class="btn btn-secondary hidden" title="Refresh listing" aria-label="Refresh listing"></button>

View file

@ -1793,7 +1793,7 @@ body.is-elevated::after {
</svg>
<div class="header-title-group">
<span class="app-header__title">ZDDC Classifier</span>
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.25-beta · 2026-05-28 19:19:54 · 9972e67</span></span>
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.25-beta · 2026-05-29 19:37:02 · c489a78</span></span>
</div>
<button id="addDirectoryBtn" class="btn btn-primary">Use Local Directory</button>
<button id="refreshHeaderBtn" class="btn btn-secondary hidden" title="Refresh and rescan directory" aria-label="Refresh" style="font-size:1.1rem;"></button>

View file

@ -1536,7 +1536,7 @@ body {
</svg>
<div class="header-title-group">
<span class="app-header__title">ZDDC</span>
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.25-beta · 2026-05-28 19:19:54 · 9972e67</span></span>
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.25-beta · 2026-05-29 19:37:02 · c489a78</span></span>
</div>
</div>
<div class="header-right">

View file

@ -2635,7 +2635,7 @@ dialog.modal--narrow {
</svg>
<div class="header-title-group">
<span class="app-header__title">ZDDC Transmittal</span>
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.25-beta · 2026-05-28 19:19:53 · 9972e67</span></span>
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.25-beta · 2026-05-29 19:37:02 · c489a78</span></span>
</div>
<span id="no-js-notice" class="text-gray-400 text-xs italic">JavaScript not available</span>
<!-- Publish split-button (Transmittal-specific primary action;

View file

@ -1,8 +1,8 @@
# Generated by build.sh — do not edit. One <app>=<build label> per line.
archive=v0.0.25-beta · 2026-05-28 19:19:54 · 9972e67
transmittal=v0.0.25-beta · 2026-05-28 19:19:53 · 9972e67
classifier=v0.0.25-beta · 2026-05-28 19:19:54 · 9972e67
landing=v0.0.25-beta · 2026-05-28 19:19:54 · 9972e67
form=v0.0.25-beta · 2026-05-28 19:19:54 · 9972e67
tables=v0.0.25-beta · 2026-05-28 19:19:54 · 9972e67
browse=v0.0.25-beta · 2026-05-28 19:19:54 · 9972e67
archive=v0.0.25-beta · 2026-05-29 19:37:02 · c489a78
transmittal=v0.0.25-beta · 2026-05-29 19:37:02 · c489a78
classifier=v0.0.25-beta · 2026-05-29 19:37:02 · c489a78
landing=v0.0.25-beta · 2026-05-29 19:37:02 · c489a78
form=v0.0.25-beta · 2026-05-29 19:37:02 · c489a78
tables=v0.0.25-beta · 2026-05-29 19:37:02 · c489a78
browse=v0.0.25-beta · 2026-05-29 19:37:02 · c489a78

View file

@ -1534,7 +1534,7 @@ body.is-elevated::after {
</svg>
<div class="header-title-group">
<span class="app-header__title" id="table-title">ZDDC Table</span>
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.25-beta · 2026-05-28 19:19:54 · 9972e67</span></span>
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.25-beta · 2026-05-29 19:37:02 · c489a78</span></span>
</div>
</div>
<div class="header-right">

View file

@ -206,7 +206,24 @@ paths:
working:
default_tool: browse
available_tools: [browse]
# Project-level working is BOTH an outstanding-only aggregator of
# the per-party archive/<party>/working/ slots AND the home for
# each user's personal workspace at <project>/working/<email>/.
virtual: true
# Edit-history versioning for personal markdown drafts (inherits
# to the <email>/ homes below). archive/<party>/working/ carries
# its own history: true separately.
history: true
paths:
"*":
# Per-user personal workspace: <project>/working/<email>/.
# auto_own (NOT auto_own_fenced) makes the creator the owner
# (rwcda + a .zddc they can edit) while leaving the home PUBLIC
# by default — the owner opts into privacy by adding
# inherit:false / restricting permissions in their own .zddc.
default_tool: browse
available_tools: [browse]
auto_own: true
staging:
default_tool: browse
available_tools: [browse]

View file

@ -49,10 +49,11 @@ func TestDefaultToolAt_FromEmbeddedConvention(t *testing.T) {
}
// TestHistoryAt_Defaults — the embedded convention enables edit-history
// versioning on archive/<party>/working/ and (because history is
// subtree-inheriting and ignores the auto_own_fenced homes' inherit:false)
// on the per-user homes and any depth beneath them. Sibling slots do not
// get history.
// versioning on BOTH (a) the project-level personal workspace
// <project>/working/ + its per-user <email>/ homes, and (b) the per-party
// archive/<party>/working/ + its homes. History is subtree-inheriting and
// ignores the homes' inherit:false fences. Sibling slots (staging,
// reviewing, mdl, incoming, received) do NOT get history.
func TestHistoryAt_Defaults(t *testing.T) {
resetCache()
root := t.TempDir()
@ -60,9 +61,17 @@ func TestHistoryAt_Defaults(t *testing.T) {
path string
want bool
}{
// Project-level personal workspace.
{filepath.Join(root, "Project-X", "working"), true},
{filepath.Join(root, "Project-X", "working", "alice@example.com"), true},
{filepath.Join(root, "Project-X", "working", "alice@example.com", "notes"), true},
// Per-party working.
{filepath.Join(root, "Project-X", "archive", "Acme", "working"), true},
{filepath.Join(root, "Project-X", "archive", "Acme", "working", "alice@example.com"), true},
{filepath.Join(root, "Project-X", "archive", "Acme", "working", "alice@example.com", "notes"), true},
// Sibling slots get no history.
{filepath.Join(root, "Project-X", "staging"), false},
{filepath.Join(root, "Project-X", "reviewing"), false},
{filepath.Join(root, "Project-X", "archive", "Acme", "mdl"), false},
{filepath.Join(root, "Project-X", "archive", "Acme", "incoming"), false},
{filepath.Join(root, "Project-X", "archive", "Acme", "staging"), false},