Commit Graph
336 Commits
Author SHA1 Message Date
m038 01c3e72c8f test(post): add location-override Playwright coverage
Mocks the Open-Meteo geocoding endpoint via page.route() so the suite is
hermetic. Covers the panel's closed-by-default state, search happy path,
Paris/Texas disambiguation ranking, no-match/network-failure/in-flight
states, XSS-safe rendering, map canvas singleton behavior, drag sync, the
mismatch flag, the maplibre-gl lazy-load boundary, and a full submit
round-tripping lat/lng into the entry's frontmatter.
2026-07-24 19:38:39 +02:00
m038andClaude Sonnet 5 641b0c376e docs(working): plan — post form location override; doc-review fixes to spec
Adds the implementation plan for the location-override feature and folds in
ce-doc-review findings: a panel-open sync gap (pin didn't render on reopen
with pre-existing coordinates), keyboard/ARIA accessibility gaps in the
search-results list and mismatch flag, a shared MAP_STYLE module to remove
duplication drift risk, and a corrected Open-Meteo risk/mitigation split.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-24 19:06:50 +02:00
m038 2ab6575e4b docs(working): spec — post form location override (search + map + drag pin)
Addresses the actual root cause behind the Denmark 2026 corrupted-coordinate
bug: there was no supported way to set an entry's location to somewhere other
than the current GPS position, forcing hand-typed/pasted raw coordinates
through Admin2's fragile text field. Backend sanitization (cache-on-save)
already guards against silent corruption; this spec adds a frontend way to
avoid needing that path at all.
2026-07-23 20:39:30 +02:00
m038andClaude Fable 5 94bfc53b90 docs(working): overnight pre-trip readiness audit + product ideation report
Audit: posting pipeline / auth / API surface review with prioritized P1-P3
findings and a morning checklist; P1-1 (prod 2M upload limit) marked
resolved 2026-07-09 via the CGI->FPM switch in Webmin. Ideation: 7 ranked,
repo-grounded ideas (top pick: OG meta + RSS follow-along stack).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0195b3cDdMeize2Mm1FgC2aU
2026-07-09 17:59:05 +02:00
m038andClaude Fable 5 0defa85f58 test(post): cover the upload-submit gate and lightbox EXIF-dims invariant
Regression specs for the two 2026-07-09 prod bugs (fixed in user/ e17a5dc):

- upload-gate.spec.js — UG1/UG2: create submit is blocked with a visible
  message while a photo upload is in flight or after it FAILED; nothing may
  land on disk. The form plugin's own guard misses LOADING and
  PROCESSING_ERROR, which silently dropped a photo on a fast save.
- lightbox-dims.spec.js — LD1: a slide's data-pswp-* must equal the
  browser-rendered natural size of the linked image. Fixture is an 800x600
  JPEG with EXIF Orientation=6 (renders 600x800 portrait), planted on disk
  in the demo trip (the active trip may be an unpublished draft that 404s).

New fixture: tests/fixtures/test-photo-exif-portrait.jpg.

Note: the suite currently needs GRAV_TEST_USER/GRAV_TEST_PASS overrides —
the .env GRAV_TEST_PASS contains shell-special chars that break `make
test-account` (see the Makefile comment requiring a plain password).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0195b3cDdMeize2Mm1FgC2aU
2026-07-09 17:59:05 +02:00
m038andClaude Fable 5 9ffeb4d2d8 fix(make): build-assets drops privileges via --user; bump CLAUDE.md Grav to 2.0.7
Close the remaining root-owned bind-mount vector: build-assets (a docker
run, missed by the docker-exec fix in 209b804) now runs as the host
uid/gid with HOME=/tmp for npm's cache. Verified: build completes clean,
zero root-owned files under user/themes, bundles byte-identical.

Solution doc updated from "still open" to fixed; CLAUDE.md stack section
now matches the Dockerfile's Grav 2.0.7.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0195b3cDdMeize2Mm1FgC2aU
2026-07-08 23:41:10 +02:00
m038andClaude Opus 4.8 6cf50920df chore(user): bump pin — taglines, Denmark desc, Past Trips→Trips rename
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 23:39:42 +02:00
m038andClaude Opus 4.8 60e80c3e72 docs(future): plan — view unpublished trips on frontend when logged in
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 23:38:49 +02:00
m038andClaude Fable 5 24867524a1 docs(solutions): compound refresh — fix reference drift, grow CONCEPTS.md
Refresh audit of all 13 docs/solutions learnings against the current
codebase. Core guidance verified accurate everywhere; three docs had
reference drift:

- dual-repo-submodule-workflow: point worktree setup/teardown at the
  make worktree-new/worktree-rm targets (manual procedure misses
  .worktree-env isolation)
- docker-exec-root-owned-bind-mount-files: tracked-plugin list now
  includes entry-actions; fix-perms description matches actual target
- grav-plugin-config-without-code-wont-enable: 3-category model's
  custom-in-repo list now includes entry-actions

CONCEPTS.md: add Container, Content repo, Outer repo, Pin, Env tree,
Remote-only plugin; refresh Active Trip (switching is one setting now).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0195b3cDdMeize2Mm1FgC2aU
2026-07-08 23:37:56 +02:00
m038andClaude Fable 5 f3816bfc3e docs(future): blueprint vetting research + recommendation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 23:22:45 +02:00
m038andClaude Opus 4.8 084f683e19 docs(plans): mark frontend-entry-edit + photo-editor-media-api complete
Both shipped with feat/journal-post-form (merged + deployed to prod) and
passed owner UI/touch-drag QA on 2026-07-08. Corrected the stale
"not merged / not deployed" language and fixed a duplicate Status marker.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 23:08:20 +02:00
m038andClaude Opus 4.8 62f940f6ef chore(user): bump pin — feature entries + Denmark publish
Content repo f4ab730: featured: true on 3 entries (homepage highlights) and
Denmark 2026 published with its Vestkystruten GPX.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mpdu3Dt1iVoozHwAMyjrbn
2026-07-08 22:30:14 +02:00
m038andClaude Opus 4.8 bc15f0b07d docs(solutions): extend root-owned bind-mount doc to docker run / build-assets
The install-plugins fix (209b804) only covered docker exec. build-assets
runs `docker run node:20-alpine` without --user, so it still writes
root-owned node_modules + esbuild bundles into user/themes/ — which is what
blocked `git worktree remove` at teardown. Broaden the doc and prevention
rule to cover docker run, with the --user fix.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mpdu3Dt1iVoozHwAMyjrbn
2026-07-08 22:30:14 +02:00
m038 b205db0ea9 Merge feat/journal-post-form: trip publish toggle (tests + docs), bump user pin
Land the owner trip publish/unpublish toggle to local main: Playwright specs
(TP1-TP8), the ce-compound solution doc + CONCEPTS.md Published/Draft concept,
and the plan/spec docs. Bumps the user submodule pin to 543e8e3 (the merged
user/ main containing the feature + denmark-2026 cover content).

Local landing only — nothing pushed.
2026-07-08 17:48:32 +02:00
m038andClaude Opus 4.8 bb2b64bd78 docs(solutions): in-place header edit + APCu cache staleness (Part 3)
Document the trip publish-toggle cache-invalidation finding: an in-place
trip.md `published` edit under cache.check.method: folder + APCu driver stays
stale because the folder checksum is unchanged AND the web APCu store is
unreachable by a CLI clearcache — fixed with apcu_clear_cache() from the web
request. Cross-link the sibling grav-deleteall doc (the create/delete case) as
necessary-but-not-sufficient here, and add the Published/Draft trip status
concept to CONCEPTS.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mpdu3Dt1iVoozHwAMyjrbn
2026-07-08 17:17:22 +02:00
m038andClaude Opus 4.8 2cdb435182 test(trip): cover publish-toggle failure/lock paths + missing-key 400
Add the three cases the code review flagged as uncovered:
- TP7 (R15): a failed POST reverts the switch and surfaces the visible toast.
- TP8 (R13): the in-flight lock suppresses a concurrent second submit (exactly
  one POST fires while the switch is aria-busy/disabled).
- TP5 leg: a MISSING published key -> 400 (the array_key_exists branch, distinct
  from the is_bool branch already covered).

All 10 trip-publish specs green (serial, worktree container).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mpdu3Dt1iVoozHwAMyjrbn
2026-07-08 17:17:09 +02:00
m038andClaude Opus 4.8 500d59bdae chore: bump user submodule pin to 4cc0a18 (denmark cover)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDS6t8wcpbwKvvrxykVQ5K
2026-07-08 17:16:53 +02:00
m038andClaude Opus 4.8 3e1ddd8132 test(trip): publish-toggle Playwright specs + plan/spec docs; bump user pin
TP1/TP1b/TP2–TP6 cover the owner gate, coverless drafts, cache-correct
hide/restore, the active-trip confirm, backend authz (401/403/400), and
the home fallback. The suite pins site.owner_username to the authenticated
test user (restore on teardown) and runs serially — it mutates global
config and clears the shared cache, so it collides with parallel readers.

Bumps the user/ pin to the finished trip-publish-toggle content (064f0f0)
and marks the plan Complete.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mpdu3Dt1iVoozHwAMyjrbn
2026-07-08 14:50:20 +02:00
m038andClaude Opus 4.8 28e57f62c2 feat(makefile): add remote-warmup — clear + warm cache after deploy
A `reset --hard` content deploy leaves Grav's compiled-Twig/page cache
stale, so the first visitor pays the recompile. `remote-warmup` clears
the cache then crawls the public site (homepage + trips listing + every
trip page linked from it) to pre-render pages. Grav has no native warmup
command, so it's an HTTP crawl — which also doubles as a smoke test
(non-2xx pages flagged). Wired into REMOTE_TARGETS (-test/-prod variants)
and added as the final step in both deploy-cycle.md phases.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDS6t8wcpbwKvvrxykVQ5K
2026-07-08 13:05:33 +02:00
m038andClaude Opus 4.8 3d9d3ecb85 docs(solutions): capture docker exec root-owned bind-mount fix
New learning: docker exec defaults to root, so make targets writing into
the ./user bind mount (esp. install-plugins -> gpm) created root-owned
files (11,624 accumulated), breaking worktree-rm. Fix: HOST_UID/HOST_GID +
`-u` on file-writing execs while the grav container still boots as root.

Cross-linked reciprocally with the sibling docker-dev-env upgrade doc.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDS6t8wcpbwKvvrxykVQ5K
2026-07-08 12:15:01 +02:00
m038andClaude Opus 4.8 209b804423 fix(makefile): create container files as the host user, not root
`docker exec` defaults to root, so `make install-plugins` wrote plugins into
the ./user bind mount as root — un-removable on the host without a root
container (exactly what blocked the 2.0.4 worktree cleanup). The grav service
can't simply run `user: 1000` because the base image entrypoint needs root to
bind :80 and set up cron, so drop only the file-CREATING CLI to the host user:

- HOST_UID/HOST_GID from id -u / id -g
- install-plugins makes cache/tmp writable (container-internal, never touches
  the host) then runs gpm as the host user, so plugins land owned by you — no
  post-hoc chown, no root files, no root rm needed at teardown

Verified: gpm reinstall as uid 1000 leaves 0 root-owned files under ./user
(was 11624), site healthy (/ and /admin 200), plugin patches reapplied.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDS6t8wcpbwKvvrxykVQ5K
2026-07-08 11:35:48 +02:00
m038andClaude Opus 4.8 20df900188 docs(plans): refresh journal-post-form status — merged to main
The feat/journal-post-form branch is now merged into main; drop the stale
"not yet pushed / awaiting owner go-ahead" tail from the Status line.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDS6t8wcpbwKvvrxykVQ5K
2026-07-08 10:56:07 +02:00
m038andClaude Opus 4.8 c4891d8f60 chore(makefile): add worktree-new/worktree-rm targets for isolated dev servers
Encode the dual-repo worktree SOP as make targets so no step is skipped:
worktree-new creates the outer worktree off main, inits its own user/
submodule, branches both repos, and starts an isolated Grav dev server on an
auto-picked free port (8090+) whose identity is persisted in a git-ignored
.worktree-env; worktree-rm tears it all down including the submodule deinit
that, when skipped by hand, leaves orphaned .worktrees/ dirs.

docker-compose.yml container_name + ports are parametrized as ${VAR:-default}
so the main checkout is byte-identical, and the 11 hardcoded intotheeast_grav
refs in local targets now use $(GRAV_CONTAINER). CLAUDE.md points at the
commands instead of the manual steps.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDS6t8wcpbwKvvrxykVQ5K
2026-07-08 10:56:07 +02:00
m038andClaude Opus 4.8 793ca10d4d chore(user): bump pin — delete-index fix + gpx-manager listing
Points user/ at 55da834 (entry-actions delete cache fix + gpx-manager shows
unpublished trips newest-first).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mpdu3Dt1iVoozHwAMyjrbn
2026-07-08 10:29:21 +02:00
m038andClaude Opus 4.8 2e96106c84 test(post): DEL4 — a deleted entry stays gone after a page reload
Guards the page-tree-index staleness fix. DEL1 only checked optimistic DOM
removal + disk; DEL4 reloads and asserts the server no longer renders the card.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mpdu3Dt1iVoozHwAMyjrbn
2026-07-08 10:29:21 +02:00
m038andClaude Opus 4.8 ceb0570c86 docs(spec): trip publish/unpublish toggle design
Owner-gated publish switch on /trips cards + trip pages; extends
entry-actions with a scope-guarded route + page-tree cache invalidation.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mpdu3Dt1iVoozHwAMyjrbn
2026-07-08 09:16:38 +02:00
m038 877d29b2b4 Merge branch 'feat/journal-post-form'
# Conflicts:
#	Makefile
#	docs/working/backlog.md
#	user
2026-07-08 00:10:14 +02:00
m038 fa6550a232 Merge branch 'main' into worktree-content-fixes 2026-07-07 23:52:34 +02:00
m038andClaude Opus 4.8 838f237ef5 docs(solutions): capture Grav cropResize-vs-cropZoom cover-image gotcha
New ui-bugs learning: cropResize fits-inside (returns a source-aspect
sliver), cropZoom crops-to-fill. Using cropResize for a cover/banner
strip hands the browser a portrait sliver that object-fit:cover then
upscales into a blur. Documents the fix, the empirical op comparison,
and prevention (verify Medium op dimensions; guard retina upscaling;
regression-test composition, not just the URL).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDS6t8wcpbwKvvrxykVQ5K
2026-07-07 23:49:58 +02:00
m038andClaude Opus 4.8 5276768e12 test(trip-cover): cover-strip + retina-cap regression; bump user pin
- trip-header/trips-list specs now assert the cropZoom wide-strip aspect
  and the all-or-nothing retina rule (1x-only for sub-2w sources), and a
  new regression on us-canada-mex-2024 covers the reported portrait-blur
- remove the orphaned AE4 test (no-photos-demo fixture was deleted)
- backlog: full-res pixelfed reimport (luxury quality item)
- plan: record the cover-quality follow-up + AE4 fixture removal
- bump user pin -> 536ca20 (trip-description-hero cover fix)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDS6t8wcpbwKvvrxykVQ5K
2026-07-07 23:39:32 +02:00
m038andClaude Opus 4.8 44c3a1c32e docs(handover): mark photo-editor Playwright handover complete/superseded
Coverage goal delivered and verified (39 post specs pass on :8091);
superseded by 2026-07-07-journal-post-form-review-handover-and-qa.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mpdu3Dt1iVoozHwAMyjrbn
2026-07-07 23:07:27 +02:00
m038andClaude Opus 4.8 b752178eb4 refactor(demo-load): iterate docs/demo/trips/* instead of per-trip blocks
demo-load / demo-reset now loop over every fixture under docs/demo/trips/
rather than hardcoding each trip, so new fixtures (no-photos-demo and any
future one) are picked up with no Makefile edit. The only per-trip specific —
the source `dailies/` folder mapping to `01.dailies/` in the pages tree — is
uniform across fixtures, so one loop covers all. chown is scoped per fixture
dir (never the whole 01.trips tree) and all copies stay `|| true`.

Verified on the worktree server: a full reset then reload restores both
italy-2026-demo (7 gpx + 12 entries + stories) and no-photos-demo; trip suite
green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDS6t8wcpbwKvvrxykVQ5K
2026-07-07 23:03:54 +02:00
m038andClaude Opus 4.8 af07ef403c test(trip): add AE4 no-banner coverage + record deferred review findings
- trip-header.spec.js: new U4/R9/AE4 test — a trip with no cover_image and no
  entry images renders its text header with no .trip-header-banner strip.
- Makefile: demo-load/demo-reset now also (un)load the no-photos-demo fixture,
  guarded with `|| true` so runs whose user/ predates the fixture skip it
  instead of failing globalSetup.
- plan: post-review follow-up notes the applied fixes and records the two
  intentionally-deferred findings (macro-owned resolution per KTD2; inline
  toggle script per U4's Approach) so they are not re-flagged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDS6t8wcpbwKvvrxykVQ5K
2026-07-07 09:13:59 +02:00
m038andClaude Opus 4.8 06f4c25631 docs(handover): review handover + owner QA checklist; mark edit-plan review-complete
Add a review handover (Claude→future Claude: branch state, commit map,
dual-session isolation facts, and the owner-triggered landing procedure) plus
an owner UI QA checklist for the flows the harness can't verify (touch-drag,
interactive photo add/delete/reorder). Update the frontend-entry-edit plan
status: implementation + code-review done; only owner QA + landing remain.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mpdu3Dt1iVoozHwAMyjrbn
2026-07-07 09:12:01 +02:00
m038andClaude Opus 4.8 6a73be3e49 test(trip): tighten description-clamp assertion + correct R11 coverage note
- trip-header.spec.js: replace the vacuous `toContainText('finally made
  sense')` (the tail text is in the DOM even while collapsed) with real
  clamp/un-clamp assertions — clientHeight < scrollHeight when collapsed,
  clientHeight >= scrollHeight once expanded — so the test actually proves the
  toggle changes visibility.
- trips-list.spec.js: the header comment claimed R11 coverage no fixture
  provided. Note that R11 (set-but-unresolvable cover_image) shares the exact
  else-branch the R7/AE3 fallback test exercises, so it's covered by
  construction in the shared cover macro.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDS6t8wcpbwKvvrxykVQ5K
2026-07-07 08:35:41 +02:00
m038andClaude Opus 4.8 e10496afe7 docs(solutions): BUG-001 part 2 — deleteAll doesn't rebuild page-tree index
Document why deleteAll() alone left a freshly-posted entry 404-ing on its
edit-prefill API lookup (regular-pages index keyed on config->checksum, which
survives a create under cache.check.method:folder) and why the fix adds
Cache::invalidateCache(). Note the H1/M8 travelling:true coverage gap as a
tracked residual. Cross-link from bugs-and-fixes.md.

Code review F8 (learnings) + F5 (residual-gap tracking).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mpdu3Dt1iVoozHwAMyjrbn
2026-07-07 08:32:20 +02:00
m038andClaude Opus 4.8 d576487886 test(post): share createPhotoEntry helper and fix cleanup leak
Hoist the duplicated per-spec createEntry photo-fixture into a single
createPhotoEntry() in helpers.js (used by delete-flow, edit-mode, and the
anon-view draft). Register the tag for cleanup BEFORE the awaited 15s
success-toast assertion, so a create that lands on disk but whose toast
assertion times out no longer leaks an untracked entry. Add AE3b covering the
disclosure deviation branch (a non-default toggle auto-expands More options).

Code review F2 (leak), F3 (duplication), F6 (coverage).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mpdu3Dt1iVoozHwAMyjrbn
2026-07-07 08:32:09 +02:00
m038andClaude Opus 4.8 86f9018f73 docs: document trip_header_extras param on trip-feed-col shared partial
Code review flagged the shared partial's CLAUDE.md contract table as stale:
trip-feed-col.html.twig gained a trip_header_extras flag (set at :254, wired
from trip.html.twig) but the parameter table the trip/home callers rely on to
stay in sync had no row for it. Add the row + a note on what it gates and why
home omits it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDS6t8wcpbwKvvrxykVQ5K
2026-07-06 07:35:18 +02:00
m038andClaude Opus 4.8 7ea90de12b test(trip): specs for trip one-liner, description, banner & home gating
- trips-list.spec.js: one-liner presence/absence, retina srcset, cover
  fallback, alt text (U3).
- trip-header.spec.js: HTD stacking order, expandable description, banner
  fallback, split intact (U4).
- home.spec.js: AE7 — the gated trip-page extras never leak onto the home
  route (asserted mode-independently so it can't race the home-highlights
  suite that toggles travelling in a parallel worker).

Also marks the plan complete.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDS6t8wcpbwKvvrxykVQ5K
2026-07-06 00:02:48 +02:00
m038andClaude Opus 4.8 f4dbac6fc2 test(home,maps): skip travelling-gated H1/M8 with a stated reason
H1 (home journal feed) and M8 (home journey map source) only apply when
config.site.travelling is true — home.html.twig otherwise renders the
between-trips highlights grid, which has neither. They now detect that mode
(.home-highlights-title) and test.skip() with an explicit reason instead of
failing misleadingly, so they still run and validate whenever travelling is on.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mpdu3Dt1iVoozHwAMyjrbn
2026-07-05 23:42:55 +02:00
m038andClaude Opus 4.8 d3c17791b7 test(post-form): add edit/delete/anon coverage and fix stale photo-gate assumptions
New specs: edit-mode (ES1 save round-trip + ES2/ES3 prefill 404/500 states),
delete-flow (DEL1-3 happy/cancel/failed), anon-view (AN1 no owner controls,
AN2 draft hidden from anon), photo-editor (live add/delete/reorder). Existing:
P3-P8 now attach a photo to satisfy the create photo-gate; V3 picker cap 4->6.
Full post suite 38/38, stable across parallel (3-worker) runs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mpdu3Dt1iVoozHwAMyjrbn
2026-07-05 23:42:45 +02:00
m038andClaude Opus 4.8 7534d7d178 test(post-form): expect zero-padded photo-01..NN filenames
The create path now routes through the shared PhotoRenumberer, which
zero-pads to photo-01..NN; update the Playwright assertions and title to
match the new naming.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 20:14:50 +02:00
m038andClaude Opus 4.8 9295914238 docs: capture history-rewrite-under-live-git-sync + secrets-audit tooling
Update the git-sync secret-exposure solution doc with today's operational
lesson: untracking an already-committed secret under a live bidirectional
sync. Covers the direction:both force-push-revert trap, the freeze-every-
server-first sequence, audit-before-reset (authoritative secret in env/),
the stale origin/main ref + sparse-checkout gotchas, and the ignore:-field
mechanism.

Add Makefile targets that supported the fix:
- remote-secrets-audit: secret-safe (existence + size + git ls-files, never
  contents) audit of config/ vs env/<host>/config secret locations
- remote-content-status: also show the .gitignore diff git-sync regenerates

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 19:25:32 +02:00
m038andClaude Opus 4.8 8441ce392d docs(plan): photo-editor implemented + server-logic verified; status update
Record implementation completion and the verification split: PhotoRenumberer
unit-verified, build/lint clean, /post + assets serve locally; owner-session UI
verification and on-device touch-drag reserved for the user. Note the server-side
SVG block deferred to the R6 add/delete fast-follow (config/security.yaml is
gitignored).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 19:25:04 +02:00
m038andClaude Opus 4.8 3cb7dfbd8b make: add remote-seed-api-salt + show HEAD in remote-content-status
remote-seed-api-salt writes a per-host popularity salt into the env
override tree (user/env/<host>/config/plugins/api.yaml) so the api plugin
reads it there instead of appending one to the git-tracked
config/plugins/api.yaml. That appended salt kept the content working tree
perpetually dirty, which aborted git-sync's auto-merge on webhook and
silently broke prod auto-deploy. Salt is generated server-side, never
committed, and re-runs are idempotent.

remote-content-status now prints HEAD so a webhook auto-pull can be
verified.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 16:53:30 +02:00
m038andClaude Opus 4.8 bb7f4a02ef docs: trip switching is one setting (site.active_trip), not three files
The post form no longer hardcodes pageconfig.parent — cache-on-save derives the
write target from site.active_trip at submit time. Update the "Switching to a new
trip" section and the Trip-architecture note accordingly, and point at the Admin
Site → Active Trip page-picker. Drops the stale post-form.md / system.yaml sync.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 14:55:05 +02:00
m038andClaude Opus 4.8 1cf2d12bc7 fix(add-page-by-form): patch Grav-2.0 edit-mode header fatal + deploy wiring
Adding a new photo while editing an entry 500s: add-page-by-form's edit branch
reads existing frontmatter via `(array)$page->header()`, but Grav 2.0's
Grav\Common\Page\Header keeps data in a protected `items`, so the cast mangles
keys and `$original_frontmatter['photos']` is never set → array_merge(null,…)
TypeError. Fix: use Header::toArray() (clean keys, stdClass fallback) + guard the
per-field merge. Grav 2.0.7 does not change this — only the plugin fix does.

add-page-by-form is abandoned upstream (last release 2023-09) and its dir is
git-ignored/GPM-managed, so the fix is tracked as deploy/patches/*.patch and
re-applied after any GPM install/update:
- make apply-plugin-patches (local) — chained into install-plugins
- make remote-apply-plugin-patches-{test,prod} — piped over SSH into
  `patch -p1 --forward`; chained into remote-install-plugins / remote-update-plugins
Content syncs don't touch user/plugins/, so the patch survives them; only a GPM
op wipes it (now auto-restored). Runbook + README document the step and a
verify check. Remove once the plugin is forked.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 13:43:12 +02:00
m038andClaude Opus 4.8 0f6b1e69cd docs: capture local Grav core upgrade + refresh version-authority docs
New learning: docs/solutions/tooling-decisions/upgrade-local-grav-core-rebuild-docker-image.md
— the local Grav core is baked into the Docker image (only ./user is bind-mounted),
so it upgrades by a Dockerfile URL bump + image rebuild + `docker rm -f` recreate,
not the `gpm self-upgrade` the servers use (non-durable in-container).

Refreshed three docs this exposed as stale/incomplete:
- local-setup.md: rewrote the stale "newer Grav RC" section with the durable
  rebuild procedure (recreate gotcha, verify, plugin refresh, non-durability note).
- deploy-cycle.md: Phase 0 now upgrades the local core; state-model notes the
  image as a fourth surface beyond the three server layers.
- stale-grav-version-blocks-api-plugin-install.md: version-authority surfaces
  3 -> 4 (hardcoded Dockerfile URL); clarified .env* GRAV_VERSION governs fresh
  remote installs only, never the local Docker core.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Np4cMQLF77i664CAQXySzU
2026-07-05 12:05:51 +02:00
m038 10f990e0e7 Merge remote-tracking branch 'origin/main' into feat/journal-post-form 2026-07-05 11:37:28 +02:00
m038andClaude Opus 4.8 fec6a475a2 deploy: bump Grav to 2.0.7 across build image + env pins
Local Docker image was still baked at 2.0.4 while test and prod had
self-upgraded to 2.0.7. Bump the Dockerfile release zip to 2.0.7 and
align the GRAV_VERSION pins so a fresh remote-install lands on 2.0.7
directly instead of installing an older base and needing a self-upgrade.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Np4cMQLF77i664CAQXySzU
2026-07-05 11:34:21 +02:00