Commit graph

15 commits

Author SHA1 Message Date
127163dfa2 release: v0.0.13 lockstep
All checks were successful
Notify chart dev on beta cut / notify-chart-dev (push) Successful in 3s
Build + deploy releases / build-and-deploy (push) Successful in 8s
Build + deploy releases / notify-chart-prod (push) Successful in 1s
2026-05-03 20:21:06 -05:00
d6448159fa release: v0.0.12 lockstep
All checks were successful
Notify chart dev on beta cut / notify-chart-dev (push) Successful in 3s
Build + deploy releases / build-and-deploy (push) Successful in 8s
Build + deploy releases / notify-chart-prod (push) Successful in 1s
2026-05-03 19:59:38 -05:00
bf54651fb0 release: v0.0.11 lockstep
All checks were successful
Notify chart dev on beta cut / notify-chart-dev (push) Successful in 3s
Build + deploy releases / build-and-deploy (push) Successful in 8s
Build + deploy releases / notify-chart-prod (push) Successful in 3s
2026-05-03 19:03:05 -05:00
f5ffd408f2 release: v0.0.10 lockstep
All checks were successful
Build + deploy releases / build-and-deploy (push) Successful in 8s
2026-05-03 17:11:46 -05:00
b15382ba9d release: v0.0.9 lockstep — re-anchor to clean embedded artifacts
All checks were successful
Build + deploy releases / build-and-deploy (push) Successful in 7s
The zddc-server-v0.0.9 (and sibling) tags previously pointed at a
commit whose embedded versions.txt + tool HTMLs still carried
alpha-dirty labels — the cut process regenerated these in the
working tree but never folded them into the tagged commit. The
binary built from that tag (used by tnd-zddc-chart's prod
Dockerfile) embedded the alpha labels.

This commit folds the stable-labeled artifacts in. The seven
v0.0.9 tags are force-moved to point here so future binary builds
from `ZDDC_REF=stable` get clean stable bytes baked in. The
old commit (a02a26d) remains in history; just no tag references
it anymore.

Sustainable fix to ./build's release flow (commit before tag,
skip embedded mutation on plain dev/alpha cuts) is a separate
follow-up — this commit only fixes the in-flight state.
2026-05-03 16:18:05 -05:00
a02a26d3c2 feat: form-data system v0 (sixth tool + zddc-server endpoints)
All checks were successful
Build + deploy releases / build-and-deploy (push) Successful in 8s
Schema-driven form renderer plus zddc-server endpoints that turn any
<name>.form.yaml into a working data-collection form at <path>/<name>.form.html.
Submissions land in <path>/<name>/<YYYY-MM-DD>-<email-sanitized>.yaml,
ACL-gated by the existing .zddc cascade. The form posts back to its own URL;
the server strips ".html" and routes by what's underneath, so create and
update use the same client-side code path.

Form spec dialect: JSON Schema 2020-12 + RJSF-style ui:* hints, written in
YAML. Chosen for LLM authorability — it's the canonical structured-output
target for OpenAI/Anthropic, and the ui:* convention is the most-trained UI
hint vocabulary. Supported subset for v0: type (string/number/integer/boolean/
array/object), enum, min/max, minLength/maxLength, required, additionalProperties:
false, properties, items, format (date, email). Round-trip mode is form-as-truth:
submission YAML is regenerated each save, comments are not preserved (the v1
file-as-truth mode for hand-edited files like .zddc itself is deferred).

New components:
  * form/ — sixth single-file HTML tool, vanilla JS renderer (~760 LoC)
  * zddc/internal/jsonschema/ — focused JSON Schema validator covering only
    the v0 keyword subset. Match-implementation-cost-to-surface-used: a full
    library brings 70%+ surface we don't use; revisit when v1 adds $ref +
    oneOf + if/then/else.
  * zddc/internal/handler/formhandler.go — RecognizeFormRequest / ServeForm,
    capability-URL re-edit, atomic submission writes via the new
    zddc.WriteAtomic helper extracted from writer.go.
  * dispatch() in zddc-server/main.go now intercepts *.form.html and
    *.yaml.html before the static-file path; spec existence is the trigger.

Build pipeline: form joins ZDDC_RELEASE_TOOLS in lockstep, gets its own
embedded copy in handler/form.html (separate from the apps cascade —
the form renderer is fixed, not subject to per-folder version overrides).

Tests: 5 new Playwright specs (form-safety) + 14 new Go tests across the
validator and handler. All 172 Playwright tests + 10 Go packages green.
End-to-end manual verification: GET empty → POST 201 + capability URL →
GET re-edit (pre-filled) → POST update → 200, raw YAML browsable, ACL
deny → 403.

Docs: form/ section added to AGENTS.md and ARCHITECTURE.md. AGENTS.md
also documents the implementation-vs-dependency policy. CLAUDE.md repo-shape
list extended.

Deferred (v1+): .zddc editor migration onto this system, file-as-truth
lossless YAML round-trip, ui:show-when conditional visibility, oneOf/anyOf,
apps-cascade preview hook, cascade-fetched form definitions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 20:12:16 -05:00
7570fb7494 refactor: separate website repo + deploy-host model
Migrates from in-repo orphan `website` branch + LFS to a two-repo +
deploy-host model so source editing is fully decoupled from live state.

  - Source code stays here (codeberg.org/VARASYS/ZDDC).
  - Hand-edited website content moves to a separate Codeberg repo
    (codeberg.org/VARASYS/ZDDC-website, cloned at ~/src/zddc-website/).
  - Live site is /srv/zddc/ on the deploy host (Caddy bind-mount),
    populated by ./deploy from this repo's dist/release-output/ plus
    ~/src/zddc-website/.
  - Releases are no longer in any git history — reproducible from
    <tool>-vX.Y.Z tags via `./build release X.Y.Z`. No LFS, no
    Codeberg release assets.

Build/deploy split:
  - ./build (no arg) is source-only; nothing in dist/release-output/
    or /srv/zddc/ is touched.
  - ./build alpha|beta|release seeds dist/release-output/ from
    /srv/zddc/releases/ (preserving symlinks), then mutates the
    channel(s) being cut on top. The bundle is always a complete
    intended-live snapshot, so the verifier sees a complete world
    and ./deploy --releases (rsync --delete-after) replaces live
    state cleanly.
  - New ./deploy wraps the rsync flow with --content / --releases
    subcommands.

Docs updated to reflect the new model: CLAUDE.md, AGENTS.md,
ARCHITECTURE.md, zddc/README.md, README.md, .gitignore, shared/
build-lib.sh comments, deprecated zddc/release.sh message.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 09:14:40 -05:00
76e1e78c55 chore: ./build is dev-only; ./build alpha is the explicit deploy
Reverts the prior CLI simplification. ./build (no arg) now does source
work only — tool dist/ + cross-compiled zddc-server binaries — and
leaves the website worktree alone. Channel/release cuts are explicit:

  ./build                  dev build (source only, no deploy)
  ./build alpha            cut alpha          (cascades nothing)
  ./build beta             cut beta           (cascades alpha → beta)
  ./build release [X.Y.Z]  cut stable         (cascades all)

Rationale: editing source shouldn't have a side-effect on the live
site. The website worktree at ~/src/zddc-website/ is what Caddy serves
in real time, so any write to it is a deploy. Treating dev iteration
as alpha-publish was confusing — the user wanted source builds and
deploys to be distinct verbs.

Mechanically: a `dev` (default) branch is added to the case statement;
the post-build matrix-index regen + channel-link verifier are
conditional on RELEASE_CHANNEL being set; dev builds skip them.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 08:29:58 -05:00
6167e99f3a chore: simplify CLI to ./build / ./build beta / ./build release
Renames build.sh → build and replaces the --release flag form with
subcommands:

  ./build                  cut alpha (default; active dev iteration)
  ./build beta             cut beta  (cascades alpha → beta)
  ./build release          cut stable (coordinated next version)
  ./build release X.Y.Z    cut stable at explicit version
  ./build help

The contract shift: there's no longer a "plain dev build that doesn't
touch channels" at the top level. Every full-stack build is a publish
action — running ./build IS active dev iteration, which is what alpha
already meant. To iterate on one tool without writing to the website
worktree, use the per-tool sh tool/build.sh (unchanged).

Output continues to land in ${ZDDC_DEPLOY_RELEASES_DIR:-$HOME/src/zddc-website/releases}
and nothing is pushed automatically. Commit + push the website branch
yourself when you want to publish. Stable cuts still tag locally on
main; tags push separately too.

Behind the scenes: the export of ZDDC_DEPLOY_RELEASES_DIR is moved
above the per-tool build.sh invocations so children inherit it. The
prior "if RELEASE_CHANNEL else write_zddc_server_stubs_all" branch is
collapsed since RELEASE_CHANNEL is always set under the new CLI.

Docs (CLAUDE.md, AGENTS.md, ARCHITECTURE.md, zddc/README.md) updated
to reference ./build everywhere; the per-tool sh tool/build.sh refs
stay (they're a separate, narrower entry point).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 08:11:10 -05:00
76820fa8dd chore: split website out into orphan branch + worktree
Moves website source + release artifacts off `main` and into a new
orphan branch named `website` in this same Codeberg repo. A `git worktree`
of that branch — typically at ~/src/zddc-website/ — is what the system
Caddy now bind-mounts and serves at zddc.varasys.io. Decoupling source
from the live site means editing source can no longer accidentally
affect what's published.

Layout going forward:
- ~/src/zddc/         — main worktree (this branch, source only).
- ~/src/zddc-website/ — git worktree of the `website` branch:
                         hand-edited content + LFS-tracked release
                         artifacts (server binaries) + regular-git
                         HTML tool releases + symlinks.
- Caddy bind-mount swapped: ~/src/zddc/website → ~/src/zddc-website
  (quadlet at /etc/containers/systemd/caddy.container, restarted).

Build pipeline now writes releases to
${ZDDC_DEPLOY_RELEASES_DIR:-$HOME/src/zddc-website/releases}.
- build.sh:                RELEASES_DIR points at the env var
- shared/build-lib.sh:     promote_release honors the env var, falls
                            back to the legacy in-repo path so any
                            standalone single-tool release on a checkout
                            that still has website/ keeps working
- freshen-channel:         passes ZDDC_DEPLOY_RELEASES_DIR through to
                            the worktree-based build

Docs (CLAUDE.md, AGENTS.md, ARCHITECTURE.md, .gitignore) updated for
the new layout. The 51 MB of website/ blobs stays in main's history
(no force-push); over time Codeberg's GC will pack them down.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 07:52:20 -05:00
d688e20dad feat(releases): channel options in version dropdown, drop chip pills
Restructures the version picker on the releases page so channel
mirrors are first-class, selectable options:

  Channels (mutable URLs)
    stable — currently v0.0.8        ← default selection
    beta — tracks stable
    alpha — tracks stable
  Pinned versions (immutable URLs)
    v0.0.8
    v0.0.2
    v0.0.1

Picking "stable" now rewires every download link on the page to the
*_stable.html (HTML tools) or zddc-server_stable_<plat> (binary)
channel-mirror URL — the kind a user wants to copy + bookmark for a
"latest stable" reference. Same for beta and alpha. Picking a pinned
vX.Y.Z still rewires to immutable per-version URLs.

Removed the separate "Or pick a channel" chip-pill row that previously
sat under the picker. The dropdown is now the single control; chips
duplicated functionality and added visual noise. The .channel-chips
CSS rules in website/css/style.css come out with them.

Static defaults (without JS) now use the stable channel mirror URLs
too, so both copy-from-source and JS-rewire produce the same outcome
for users who want stable. The page works end-to-end with JS off.

Embedded snapshots refreshed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 21:19:59 -05:00
8c2e65e4a2 fix(mdedit): two-line ZDDC tree display + dark-mode editor contrast
Two issues from one session:

* File tree: ZDDC-conforming filenames render as a single line
  even though the JS already produced two-div markup (filename-main +
  filename-secondary). Cause: .tree-row__label was display:flex
  (row-direction), so the two divs laid out side-by-side. Fix: wrap
  each label's text in a new .tree-row__name span styled
  flex-direction:column. Both file and folder code paths use the
  same wrapper now; non-ZDDC entries collapse to a single
  .filename-main line so typography stays consistent across the tree.
  Tested by injecting a ZDDC filename into a mock directory and
  asserting filename-secondary's bounding-box top is below
  filename-main's bottom.

* Toast UI Editor was unreadable in dark mode. Toast UI ships with
  light-only chrome; its .toastui-editor-md-container has color #222
  on a transparent bg, so when mdedit's dark theme rendered the
  surrounding pane in #1e1e1e the editor text fell on near-black
  background → effectively invisible. Fix: add CSS overrides in
  mdedit/css/editor.css that target the editor's load-bearing
  surfaces (md-container, md-preview, ww-container, ProseMirror,
  toolbar, mode-switch tabs, popups) and apply var(--bg) /
  var(--text). Toolbar icons get a filter:invert(0.85) hue-rotate
  to flip the sprite-baked dark glyphs. Both manual override
  (data-theme="dark") and OS-pref auto fallback (prefers-color-scheme)
  are covered. Tested by computing contrast ratios on every editor
  surface in dark mode — all came in at 10:1+ (well above WCAG AA's
  4.5:1).

Embedded snapshots refreshed to current main HEAD's dev build label.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 21:09:46 -05:00
17b0a4dff9 release: v0.0.8 lockstep
First lockstep cut. All six tools (5 HTML + zddc-server) at the same
version. zddc-server jumped from 0.0.7 → 0.0.8; HTML tools jumped from
0.0.2 → 0.0.8 (the coordinated next-stable rule picks max-tag + 1, so
HTML tools skip ahead in lockstep with the binary).

Tags created:
  archive-v0.0.8
  transmittal-v0.0.8
  classifier-v0.0.8
  mdedit-v0.0.8
  landing-v0.0.8
  zddc-server-v0.0.8

All tags point at 9fce18c (the source-state commit).

Artifacts under website/releases/:
  - 5 per-version HTML tool files (immutable real bytes)
  - 4 zddc-server binaries × 5 cascade levels (per-version + 4 symlink
    levels) per platform = 20 binary entries per platform × 4 platforms
  - 6 channel/per-version stub HTML pages for zddc-server (matrix-cell
    download fan-out)
  - All HTML tool channel mirrors updated to track v0.0.8
  - Matrix index regenerated with v0.0.8 as current stable

channel-link verification: 30 link(s) ok
First time the verifier runs in non-bootstrap mode (zddc-server stable
chain anchored).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 20:12:48 -05:00
9fce18cd45 feat: lockstep release infra + cascade/.archive fixes + profile perf + page redesign
Four entangled change-sets from one session, committed together because
their file-level overlap (build.sh, docs, embedded/, watcher.go, …) makes
post-hoc separation noisy:

* fix(archive): nested-party + folder-type cascade
  transmittalIsUnderVisibleParty short-circuited on the first matched
  party segment, only checking the immediately-next segment for a
  folder-type marker. Paths like BM/sub/Issued/<txn> bypassed the Issued
  toggle entirely. Replaced with isUnderHiddenFolderType (full-path) +
  any-segment party match. Eight new Playwright cases pin the contract
  in tests/archive-cascade.spec.js.

* refactor(zddc-server): scope .archive index by project
  archive.Index now buckets by top-level segment
  (.ByProject[<project>].ByTracking[<tracking>]). Resolve and AllEntries
  take a project parameter; handler extracts it from contextPath's first
  segment. /.archive/ at root returns 404 — stable refs must be
  project-rooted. Within-project (tracking, rev) collisions emit a WARN
  with both paths. Cross-project tracking-number duplicates no longer
  collide.

* perf(zddc-server): lazy-load expensive bits of the profile page
  serveProfilePage now ships a minimal shell: Email, EmailHeader,
  IsSuperAdmin (root .zddc only). Visible projects + admin subtrees +
  editable scaffolds populate client-side via /.profile/access. Subtree-
  admin scaffolds live in <template id="tmpl-subtree-admin">; pure
  non-admins receive no live admin form. ScanZddcFiles now memoized,
  invalidated on .zddc events by the watcher and writer helpers.

* feat: lockstep release + redesigned releases page
  sh build.sh --release [version|alpha|beta] is the canonical lockstep
  cut: every tool (5 HTML + zddc-server) bumps to the same coordinated
  version. zddc-server binaries now committed under website/releases/
  with the same cascade chain as HTML tools (no more Codeberg release-
  asset publication). zddc/release.sh deprecated (kept as a guard);
  shared/publish-codeberg-release.sh removed.

  Releases page redesigned as an action-first install guide: hero +
  version dropdown that rewires every download link, channel chips for
  always-visible alpha/beta access (state-aware labels: "tracks stable"
  vs "active dev"), Path A (zddc-server with platform auto-detect from
  UA), Path B (5 standalone tool HTMLs), version-pinning empowerment
  narrative (drop-a-copy vs .zddc apps: cascade), channels explainer.

  Channel-link verifier asserts every <tool>_{stable,beta,alpha}.html
  resolves at the end of every build. Bootstrap-friendly: zddc-server
  artifact checks skip until the first lockstep cut anchors the chain.

Tests: 167 Playwright + all Go packages green.
Docs: CLAUDE.md, AGENTS.md, ARCHITECTURE.md, zddc/README.md updated.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 20:11:38 -05:00
4ede42010a feat(zddc-server): CLI flags, --version, CWD-default ZDDC_ROOT
Adds command-line flags to zddc-server alongside the existing env vars.
Each setting can be set via --<flag-name> or ZDDC_<NAME>; the flag wins
on conflict, the env var wins over the hard-coded default.

  --root          / ZDDC_ROOT          (now defaults to CWD if both unset)
  --addr          / ZDDC_ADDR          (:8443)
  --tls-cert      / ZDDC_TLS_CERT      ("none" / empty / path)
  --tls-key       / ZDDC_TLS_KEY
  --log-level     / ZDDC_LOG_LEVEL     (info)
  --index-path    / ZDDC_INDEX_PATH    (.archive)
  --email-header  / ZDDC_EMAIL_HEADER  (X-Auth-Request-Email)
  --cors-origin   / ZDDC_CORS_ORIGIN   (https://zddc.varasys.io; "" disables)
  --insecure-direct / ZDDC_INSECURE_DIRECT (false)
  --help          (prints flag list to stderr, exits 0)
  --version       (prints binary + embedded tool versions, exits 0)

So an operator can `cd /srv/zddc && zddc-server` with zero config — the
served root defaults to the current directory, and TLS defaults to a
self-signed cert. config.Load now takes []string (test-friendly: nil
skips flag parsing entirely; tests pass an empty slice for env-only
loads).

Adds a `version` package-level var in main.go injected at link time via
`-ldflags="-X main.version=..."`. The build.sh runs git describe against
zddc-server-v* tags; for in-flight commits between releases it produces
e.g. zddc-server-v0.0.7-19-gadb6904-dirty.

Adds an embedded versions manifest:
  - Each tool's compute_build_label (in shared/build-lib.sh) writes a
    sidecar <tool>.label to $BUILD_LABELS_DIR if that env var is set.
  - Top-level build.sh sets BUILD_LABELS_DIR before running each tool's
    build, then assembles zddc/internal/apps/embedded/versions.txt as
    one `<app>=<build label>` line per app.
  - apps.EmbeddedVersions() loads the manifest at runtime.
  - main.go logs a compact summary on every startup; --version dumps
    the full per-app label.

Removes the old cfg.BuildVersion field — the X-ZDDC-Source: embedded
header now uses the package-level main.version directly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 15:43:31 -05:00