Commit Graph
62 Commits
Author SHA1 Message Date
Willem van den Ende 9730987846 app: give credo checks one load path (fixes redefining-module warning)
lib_dev/ was both compiled (elixirc_paths for :dev and :test) and source-loaded
by credo through `requires:` in .credo.exs. Two load paths for one module means
that whenever _build/dev already holds the beam, `mix credo` warned:

    warning: redefining module Firehose.Checks.NoConnShadowing
    (current version loaded from _build/dev/.../Elixir.Firehose.Checks.NoConnShadowing.beam)

Keep the explicit contract and drop the accidental one: `requires:` is the
documented way for credo to load project checks, so lib_dev/ now leaves
elixirc_paths in every environment. Nothing under test/ referenced the check, so
the :test entry was dead as well, and credo compiles the file on every run
anyway, so the check still gets compiled — just once.

One-time migration for checkouts that already built it:
`mix clean` (or delete _build/dev) to drop the stale beam; until then the old
warning persists. Fresh clones are unaffected.
2026-10-26 20:01:33 +00:00
Willem van den Ende f54ce2fab7 app: note that CoreComponents.table/1 and list/1 are unused upstream scaffold
These two come from the upstream Phoenix generator and are worth keeping for
future data/admin screens, so they stay rather than being deleted as dead code.

The note also records why they look unused but aren't pointless: the collections
already in the UI are hand-rolled (editor_dashboard_live's drafts/scheduled rows
are bordered divs; Blogex.Components.post_index renders post previews and tag
lists itself). That is the fact a future reader needs before either deleting
these or writing yet another bespoke list.
2026-10-26 19:50:47 +00:00
Willem van den Ende cb13ccecab docs: the Lens pass runs each suite before its sensors
Same shape in both apps now that coverage is wired: one suite run exports the
coverage, then the sensors read it. AGENTS.md said "sensors ... and finally both
test suites" and told sensor authors only to list targets in VERIFY_SENSORS; add
the export dependency and the "a check must fail when its input is missing" rule,
since `mix test.coverage` exits 0 when it finds no export.
2026-10-26 18:41:02 +00:00
Willem van den Ende abb712f8a2 app: coverage floor (86) + framework-glue exclusions
Measured before choosing: 86.17%, identical via `mix test --cover` and via the
exported sample + `mix test.coverage`, stable across seeds. Floor is the integer
below that, with the rule written next to it: a FLOOR, ratcheted up as
behavior-test yaks land, never lowered (a drop means the change or an exclusion
is wrong).

Exclusions are the modules the suite cannot or should not exercise, each
justified in the config comment: `use`-generated glue (Repo, Mailer, Telemetry,
ErrorHTML/ErrorJSON), the `use FirehoseWeb` macro, production release tasks
(Release), the lib_dev credo check (NoConnShadowing), and test scaffolding
(DataCase, ConnCase, AccountsFixtures, Test.FakeBlog). Everything else counts,
CoreComponents/controllers/LiveViews included.

Wiring matches blogex and the fast/push split: `test.coverage` runs the suite
once with `--cover --export-coverage default` (deleting stale exports first,
since `mix test.coverage` imports every .coverdata it finds and would pool
them), then the `coverage` sensor enforces the floor from that export. The
sensor guards on the export existing because `mix test.coverage` exits 0 when it
finds nothing — a floor check that did not run must not pass.
2026-10-26 18:40:09 +00:00
Willem van den Ende 754c8fa1b9 blogex: coverage floor (74) + test-scaffolding exclusions
`test_coverage` sets the floor the Lens pass enforces, measured first: 74.53%
with test/support excluded (`mix test --cover` and the exported sample give the
same number). The rule — a FLOOR, ratcheted up as behavior yaks land, never
lowered — is written next to the config, along with why each module is excluded
(test scaffolding only: fixtures measure the tests, not the library).

Wiring, per the fast/push split: `test.coverage` runs the suite once with
`--cover --export-coverage default`; the `coverage` sensor then enforces the
floor from that export via `mix test.coverage` (no second suite run). So
`verify` runs the suite first and the sensors after it. The sensor guards on the
export existing: `mix test.coverage` exits 0 when it finds no .coverdata, and a
floor check that did not run must not report success.

blogex/.gitignore: cover/ (generated).
2026-10-26 18:38:35 +00:00
Willem van den Ende a9a02aa9ba app: hand-write the User Inspect impl so coverage can instrument it
`redact: true` makes Ecto derive an Inspect impl at the `schema` line.
Elixir 1.20.4 emits that whole derived impl on that one line, and OTP 27's
coverage instrumentation (sys_coverage) turns it into invalid Erlang
("variable '_2' unsafe in 'case'"), so `mix test --cover` aborted for the whole
app before reporting anything. Minimal repro, no Ecto needed:
`@derive Inspect` on a plain struct fails on Elixir 1.20.4 + OTP 27.3.4.19 and
works on Elixir 1.18.3 + the same OTP.

Writing the impl out by hand, one expression per line, keeps `inspect/1`
output byte-identical (Ecto/Elixir render redacted fields as
`#Mod<..., ...>`) and keeps redaction pinned by the existing test, and lets the
coverage sensor land. Revisit when the Elixir/OTP pins change.
2026-10-26 18:38:13 +00:00
Willem van den Ende 96278e0d02 AGENTS.md: document the fast loop, the Lens pass and its triage classes
Records the two loops (make check per commit, make verify per push), how to
install the hook (make hooks), the deliberate --no-verify bypass, the Lens
practice (separate pass, don't chase nits inline, file a yak), the triage
classes (real bug / environment-dependent test / design nit), and how that
reconciles with the zero-defects policy. Playwright stays outside the Lens
pass pending an explicit decision.
2026-10-26 17:59:44 +00:00
Willem van den Ende 5db2814c2e pre-push Lens pass + make hooks installer
.githooks/pre-push runs 'make verify', tees the log to .git/lens-pass.log and,
on failure, prints one summary (last step started, log path, bypass) before
exiting 1. 'make hooks' symlinks .githooks/* into the clone's hooks dir.

core.hooksPath is deliberately left alone: bd keeps its own pre-commit
(post-merge) hooks in .git/hooks and pointing hooksPath at .githooks would
silently retire them while bd still reports them installed.
2026-10-26 17:58:58 +00:00
Willem van den Ende 068911b4e8 make verify: add the Lens pass container (both apps, cheapest first)
Root verify runs check first, then a per-app verify in each Makefile: sensor
slots hooked to VERIFY_SENSORS (empty today, so nothing is claimed that is not
run) and then that app's suite. Measured: 9.9s wall, app 178 + blogex 156 tests.
2026-10-26 17:58:42 +00:00
Willem van den Ende 0b815dc66a make check: include blogex in the cheap static gate
Root check now loops app then blogex then the pin check, mirroring the shape
the Lens pass will use. blogex gains a check target (compile with warnings
fatal + format); credo is a marked slot until its dep exists, and the gate
never claims a sensor it did not run.
2026-10-26 17:58:14 +00:00
Willem van den Ende ea588bd670 blogex: add precommit alias (compile --warning-as-errors, format, test) 2026-10-26 17:57:56 +00:00
Willem van den Ende 888aa8b00b blogex: format drift in link_validator (found before wiring blogex into make check) 2026-10-26 17:57:50 +00:00
Willem van den Ende cbbdaae53d doc: plan for internal code health sensors
Records the plan for bringing coverage floors, CRAP scores, credo strict,
sobelow, boundary and mutation testing to firehose, framed as the
"internal verification" counterpart to the existing Playwright / conn /
LiveView tests.

Ordered in phases because the fast/push split (make verify + pre-push
hook, cheap precommit) is the container the other sensors wire into.
Includes the steering principles that made the stickies run work
(behavior not state, functional core/imperative shell, delete dead code,
leave defensive branches uncovered deliberately) and the deferred
decisions (CRAP threshold below 30, boundary.spec.check, Playwright in
the Lens pass).
2026-10-26 17:47:04 +00:00
Willem van den Ende a1ff6dbbac mix.lock: patch/minor dependency bumps (18 packages)
All within existing mix.exs constraints. Notables: bandit 1.12.5->1.13.1,
phoenix 1.8.15->16, phoenix_live_view 1.2.12->13, swoosh 1.28.1->1.29.0,
tailwind 0.4.1->0.5.1 (new bundled CLI - check CSS output after deploy).
Tests: 156 passing (app + blogex).
2026-10-26 12:53:33 +00:00
Willem van den Ende 127eb474d2 External link marker: new tab + icon on links leaving the blog
External links in post bodies now open in a new tab and show a
box-with-arrow marker icon, so readers can tell at a glance which
links leave the site.

- blogex: new Blogex.ExternalLinks.rewrite/1 marks up anchors with
  http(s) hrefs at compile time with target="_blank", rel="noopener"
  and class="blogex-external" (idempotent, merges into existing
  class/rel values, leaves relative, mailto: and #anchor links alone)
- blogex: Post.build/3 applies the rewrite, so every blog gets it
- app: CSS in .blogex-post-body draws the marker via a mask so it
  inherits the link colour; empty ::after content stays invisible
  to screen readers
- make test now also runs the blogex suite; it is currently red
  with 3 pre-existing blog_integration_test failures caused by the
  vacuous link validator (parked yak
  link-validator-never-sees-compiled-html-...)
2026-10-02 12:11:10 +00:00
Willem van den Ende c70d904586 automated release notes 2026-04-02 10:59:06 +00:00
Willem van den Ende dfa1763e5e I author, agents generate code 2026-04-02 09:56:49 +00:00
Willem van den Ende 9e3f44bf74 change dev server to unique (fixed) port 2026-04-02 09:56:49 +00:00
Willem van den Ende 5cc65ee391 agent forgot to commit a bunch of files 2026-04-02 09:56:49 +00:00
Willem van den Ende 806d95db6e agent forgot to commit the first allium spec 2026-04-02 09:56:49 +00:00
Willem van den Ende b2a4cdab42 Add scheduled publishing release note blog post
Includes 7 screenshots demonstrating date filtering, status
banners, editor dashboard, and registration gating.
2026-04-01 22:10:45 +00:00
Willem van den Ende b6ff541b13 Fix status banner auth check to use current_scope
phx.gen.auth sets current_scope, not current_user. Use !! to
ensure boolean for HEEx template and register_and_log_in_user
in tests for proper auth session.
2026-04-01 22:06:07 +00:00
Willem van den Ende 88ec475a5b Sync beads: close all 12 scheduled publishing issues 2026-04-01 21:48:38 +00:00
Willem van den Ende 74a1201b88 Add integration tests for scheduled post filtering in Phoenix 2026-04-01 21:47:15 +00:00
Willem van den Ende 8d40e09e90 Verify router respects date filtering on all endpoints 2026-04-01 21:46:59 +00:00
Willem van den Ende 2591796d82 Format editor dashboard LiveView 2026-04-01 21:44:12 +00:00
Willem van den Ende f1560ff0e7 Add LiveView editor dashboard with drafts and scheduled tabs 2026-04-01 21:42:45 +00:00
Willem van den Ende 5395b2de80 Show draft/scheduled status banners for authenticated users 2026-04-01 21:40:17 +00:00
Willem van den Ende 86f7ffbe94 Gate registration to ALLOWED_REGISTRATION_EMAIL 2026-04-01 21:39:15 +00:00
Willem van den Ende df20c478f4 Seed demo user in dev environment 2026-04-01 21:36:58 +00:00
Willem van den Ende 20f12847d6 Allow direct access to draft and scheduled posts by slug 2026-04-01 20:39:19 +00:00
Willem van den Ende 370275f7b5 Verify feeds exclude future-dated posts 2026-04-01 20:37:27 +00:00
Willem van den Ende a380d0cb69 Add phx.gen.auth authentication scaffolding
- LiveView-based email/password auth via mix phx.gen.auth
- Auth links removed from public navigation (direct URL access only)
- Accounts context with User schema and token management
2026-04-01 20:31:13 +00:00
Willem van den Ende 0577ceced0 Filter future-dated posts from public views and add unfiltered post access
- all_posts/0 now excludes posts where date > today
- all_tags/0 computed at runtime from filtered posts
- posts_by_tag/1 and recent_posts/1 inherit date filtering
- Add unfiltered_posts/0 to Blog macro and FakeBlog
- Add all_posts_unfiltered/0 to Registry for dashboard use
2026-04-01 20:30:27 +00:00
Willem van den Ende 037e9f86ff Add post visibility and days_until_live helpers 2026-04-01 20:24:33 +00:00
Willem van den Ende 505a2d0bd6 Add custom Credo check for conn shadowing in tests
Detects `conn = get(conn, ...)` patterns and directs to
refactor_conn_aliasing.sh for automatic fixing.
2026-03-20 21:37:04 +00:00
Willem van den EndeandClaude Opus 4.6 dcf3032d0e Add custom Credo check for conn shadowing in tests
Detects `conn = get(conn, ...)` patterns and directs to
refactor_conn_aliasing.sh for automatic fixing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 21:37:04 +00:00
Willem van den Ende 9426582abc Refactor conn aliasing in controller tests to use pipe chains
Applied refactor_conn_aliasing.sh to eliminate conn shadowing.

Show draft posts in test and dev
2026-03-20 21:36:08 +00:00
Willem van den Ende 6a5269f30a Refactor conn aliasing in controller tests to use pipe chains
Applied refactor_conn_aliasing.sh to eliminate conn shadowing.

Show draft posts in test and dev
2026-03-20 21:36:08 +00:00
Willem van den Ende c18f9cd2e3 Fix Sandbox module not available in DataCase setup
The alias was inside the `using` block (only available to consumers),
but setup_sandbox/1 runs in DataCase itself. Use fully qualified name.
2026-03-20 21:19:54 +00:00
Willem van den EndeandClaude Opus 4.6 5d040b4062 Fix Sandbox module not available in DataCase setup
The alias was inside the `using` block (only available to consumers),
but setup_sandbox/1 runs in DataCase itself. Use fully qualified name.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 21:19:54 +00:00
Willem van den Ende 5d49af2790 Add reusable script to refactor Phoenix test conn aliasing
Portable awk-based script that transforms conn shadowing patterns
into idiomatic pipe chains across 4 cases (body extraction, single
assert, pattern match assert, multi-use rename).
2026-03-20 21:19:54 +00:00
Willem van den EndeandClaude Opus 4.6 5186edc2e9 Add reusable script to refactor Phoenix test conn aliasing
Portable awk-based script that transforms conn shadowing patterns
into idiomatic pipe chains across 4 cases (body extraction, single
assert, pattern match assert, multi-use rename).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 21:19:54 +00:00
Willem van den Ende a5c26f24ab Add healthcheck and attempt to fix devcontainer
user was root instead of vscode, and pi was broken.
Claude code had gone missing
2026-03-18 17:15:45 +00:00
Willem van den Ende 99639090b6 Add healthcheck and attempt to fix devcontainer
user was root instead of vscode, and pi was broken.
Claude code had gone missing
2026-03-18 17:15:45 +00:00
Willem van den Ende a5dee5c21e set default port to 5000 for production 2026-03-18 13:55:49 +00:00
Willem van den Ende ddf75031e0 set default port to 5000 for production 2026-03-18 13:55:49 +00:00
Willem van den Ende 9e6252e1e7 set DATABASE_URL 2026-03-18 13:48:12 +00:00
Willem van den Ende 3bfca5a726 set DATABASE_URL 2026-03-18 13:48:12 +00:00
Willem van den Ende 6f2beb8bb8 Add MIT license 2026-03-18 13:22:12 +00:00
Willem van den Ende 3846cae6ca Add MIT license 2026-03-18 13:22:12 +00:00
Willem van den Ende 24847ca7fd Clearly mark sample posts as generated 2026-03-18 12:11:28 +00:00
Willem van den Ende 999ed4e121 Clearly mark sample posts as generated 2026-03-18 12:11:28 +00:00
Willem van den Ende e0e5acb322 open port 4050 for testing in docker compose file 2026-03-18 12:07:20 +00:00
Willem van den Ende fcd2a91ecc open port 4050 for testing in docker compose file 2026-03-18 12:07:20 +00:00
Willem van den Ende 9bad5d3770 Enable UTF-8 in devcontainer 2026-03-18 11:30:27 +00:00
Willem van den Ende 87d7b39d22 Enable UTF-8 in devcontainer 2026-03-18 11:30:27 +00:00
Willem van den Ende f563d3c26a Add postgres to devcontainer / compose 2026-03-18 11:22:54 +00:00
Willem van den Ende 7c3aac56ec Add postgres to devcontainer / compose 2026-03-18 11:22:54 +00:00
Willem van den Ende e780d6b6e5 Add Dockerfile-based Dokku deployment for monorepo layout
Uses a multi-stage Docker build that copies both app/ and blogex/,
preserving the path dependency. Includes release scripts, migration
module, and a sample Dokku setup script.
2026-03-18 10:55:44 +00:00
Willem van den EndeandClaude Opus 4.6 2d97353649 Add Dockerfile-based Dokku deployment for monorepo layout
Uses a multi-stage Docker build that copies both app/ and blogex/,
preserving the path dependency. Includes release scripts, migration
module, and a sample Dokku setup script.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 10:55:44 +00:00
Willem van den Ende 6887ae4087 Security: Validate blog controller inputs (page param, blog ID)
Ran a claude /security-review, fixed two vulnerabilities

  Use a plug to resolve blog_id, returning a clean 404 for unknown blogs
  instead of raising with inspect(). Parse page param with Integer.parse
  so invalid values (non-numeric, negative, zero) fall back to page 1
  instead of crashing. Add 5 tests covering these cases.a
2026-03-17 12:17:29 +00:00