Commit Graph

1872 Commits

Author SHA1 Message Date
admin 43b67283c3 website: the footer dash swept site-wide, and the primary CTA meets WCAG AA
gates / gates (push) Failing after 14m58s
Two operator decisions from STOP 3, both independent of the home-page switch,
which was NOT approved and has NOT happened. index.html still serves the old
design; only the footer line and the button change on it.

1. The footer em dash, on all 21 page files (12 HU + 8 EN + the preview).
   "(c) 2026 felhom.eu - Sajat felhod..." now uses the spaced en dash, which is
   the correct Hungarian gondolatjel. Done as one sweep because site_gates.py
   gate 3 requires every page in a language set to carry an IDENTICAL footer, so
   this could never have been a one-page edit. Gate green: all 14 still match.

   Scope, stated honestly: this clears the footer only. 300 em dashes remain in
   the BODIES of the other 19 pages (gyik 53, en/faq 53, adatkezeles 33,
   szolgaltatasok-nonpublic 27, testing 24, teszteles 23, index 17/19, ...). The
   preview page is the only page at zero. The rest is NEXT.md work, page by page.

2. R-930, the operator's choice of the three offered: white on --blue measures
   4.01:1, under WCAG AA's 4.5:1 for body text. .cta-button goes to 1.2rem/700,
   which is >=18.66px at >=700 weight, so WCAG counts it as LARGE text and the
   floor becomes 3:1 - which 4.01 clears without touching --blue. Darkening the
   token was rejected because --blue is shared with the hub and controller UIs.
   Horizontal padding trimmed 32->26px to protect the one-line rule for the
   longest label; verified in the browser at 390px, not assumed.
   .cta-button-secondary is unchanged: it already measures 7.17:1.

   This reaches the primary button on 16 pages, which is the point - the defect
   was never the home page's.

site.css?v= bumped to 12 on all 21 files. The pages sat at v=10 and the preview
at v=11; leaving them split would have served a returning visitor the old
stylesheet and the change would have looked like it did not deploy.

site_gates.py green.
2026-10-11 00:25:43 +02:00
admin 94ac6afbe8 audit: the preview's pre-flight, before/after shots, and two filed rows
gates / gates (push) Failing after 12m59s
PREFLIGHT.md - taste-skill §14 plus the Felhom additions, run in writing against
the DEPLOYED preview, Pass/Fail per line. Measured, not assumed:

  page height 1440: 10 922 -> 6 780 px (38% shorter)
  page height  390: 19 913 -> 10 865 px (45%, 23.6 -> 12.9 phone screens)
  initial load:     13 req / 308 KB -> 11 req / 260 KB   (same conditions)
  fully loaded:     16 req / ~540 KB -> 15 req / ~545 KB (ESSENTIALLY UNCHANGED -
                    the 93 KB portrait is paid for by dropping the 49 KB hero logo
                    and the 31 KB mono font; stated rather than spun)
  third-party hosts: 0 -> 0
  em dashes in our copy: 18 -> 0
  layout families: 8 for 11 sections (3 repeats) -> 10 for 10 (none)
  no horizontal scroll: clientWidth == scrollWidth at 390 and at 1440

Contrast: three NEW styles measured 3.88 / 3.14 / 3.57 on the first pass, all under
WCAG AA. Fixed to --text-2 and re-measured on the deployed file: 7.56 / 6.12 / 6.96.

A measurement that lied, recorded because it nearly shipped a false verdict: the
first helper reported .limits p at 1.17:1 by treating the translucent --warn-dim
as opaque. Compositing the whole ancestor stack gives the true 5.67:1, a pass. The
three real failures in the same run were real. An instrument that can report a
wrong number silently is not a measurement.

Two rows filed, both needing something this session may not do alone:
  R-930 (Business & legal, P3) the primary CTA is 4.01:1, under AA. MEASURED
        IDENTICAL ON THE LIVE PAGE, so pre-existing and site-wide, not a regression
        of this redesign. Three fixes offered, each touching brand, so it goes to
        the operator rather than being changed unilaterally.
  R-931 (Process & tooling, P4) felhom.eu serves NO compression at all - site.css
        goes over the wire as 94 310 raw bytes with no Content-Encoding even when
        gzip is offered. An nginx setting in manifests/, not a website change.
        Worth more than anything on this page.

Register: 127 -> 129 rows, 2 opened, 0 closed. register_shape_gate.py OK.
2026-10-10 22:12:47 +02:00
admin 6f58c00fe7 website: the comparison column and the hero caption meet WCAG AA
gates / gates (push) Failing after 11m58s
Measured on the live preview, not assumed. --text-3 gave 3.14:1 (comparison
header), 3.57:1 (comparison rows) and 3.88:1 (hero caption) against their own
backgrounds, all under the 4.5:1 floor for body text. The audit's own rule was
that the existing 7.56:1 body contrast is an accessibility win to protect, so
dimming a column below AA to make it read as 'the quieter half' is a regression,
not a style. All three move to --text-2; the two halves of the comparison are
still told apart by the accent colour and the bold lead on the right.
2026-10-10 22:08:47 +02:00
admin a818b9c576 website: the redesigned home page, staged at /preview/ (noindex)
gates / gates (push) Failing after 14m33s
Part C. The live home page is NOT touched: every CSS rule added is a new class
under .page-index, so index.html renders byte-for-byte as before.

website/preview/index.html  (BOM + CRLF, noindex, Disallow: /preview/)
  Ten sections, ten different layout families. The three repeats the audit found
  are gone: why-grid ran 3x and apps-showcase 2x.
    - hero: a real dashboard screenshot instead of the logo, sized by its content
      instead of a forced 100vh band, no infinite float animation, and a sentence
      made of four facts instead of "Professzionalis ... telepites es uzemeltetes".
    - the ten capability cards become three labelled clusters. Their TEXT is
      verbatim: the audit's own finding was that the writing is right and the
      layout is wrong, so only the layout moved. Every hedge ("ha van") survives.
    - NEW "Ki all mogotte" with the operator's photo and five approved sentences.
    - the 3 cloud-problem cards + the 4 own-server cards merge into ONE two-column
      comparison. No new claim about any competitor: all four left-hand sentences
      already existed on the page.
    - the two tile walls (10 + 7 tiles duplicating pages that already exist) shrink
      to a two-item band that keeps the app names and the links.
    - section headers are left-aligned and varied, not 11x centred-two-words-plus-
      one-blue-word.

  Em dashes in the page's own copy: 18 -> 0. Deliberately kept: the 6 in <title>,
  meta description, OG, Twitter and JSON-LD (operator decision at STOP 1 - indexed
  strings deserve their own pass), and 1 in the shared footer, which gate 3 requires
  to be identical across all 14 pages. Both stated, neither swept silently.

  JetBrains Mono is no longer fetched. Exactly 13 characters were loading 31 KB:
  the 1..5 process badges, the 01..05 service numbers, and - the audit missed this
  at first and it is corrected in the file - the 3/2/1 of the backup rule.

assets/operator-portrait.webp  720x900, 93 KB
  Cropped from an original that stays OUTSIDE this public repo. All metadata
  stripped and VERIFIED BY READ-BACK: 0 EXIF tags, 0 GPS IFD entries, and none of
  EXIF/XMP/ICCP/samsung/SM-A705FN/2023:10:18 appear anywhere in the bytes. Built by
  re-writing the pixels into a fresh image, so the source info dict cannot travel.
  Honest correction to the brief's premise: this photo had NO GPS tag to begin with.

scripts/site_gates.py
  preview/index.html registered in NO_TWIN, with the reason. It cannot go in TWINS:
  gate 3 wants its nav identical to index.html's (globe -> / and /en/) while the
  twin check wants a pair's globe pointing at the pair's own URLs. The English twin
  is written in the same commit as the switch, as a real twin. Everything else still
  runs on the preview - BOM, emoji, nav/footer, globe, analytics, CDN, tokens,
  cache-busting, dash-language, viewer, tail.

site_gates.py green. The builder (kept in the session scratchpad) writes BOM + CRLF
and asserts both: it first wrote LF and turned the nav/footer gate red for the
preview, which is exactly the trap this CHANGELOG's morning entry records.
2026-10-10 22:01:12 +02:00
admin fc52e3865e skills + audit: vendor taste-skill, add the Felhom override, audit the home page
gates / gates (push) Successful in 6m30s
Part 0 and Part A of the home-page redesign. Nothing under website/ is touched.

skills/
  - design-taste-frontend installed to ~/.claude/skills/ as a VERBATIM copy of
    github.com/Leonxlnx/taste-skill @ 717446e07a (2026-10-09, MIT). Body verified
    byte-identical line by line; the only addition is a provenance block. The repo
    holds scripts (skill.sh, scripts/*.mjs) but the SKILL FOLDER holds only SKILL.md,
    so no script was copied and none was run. Not installed via npx or skill.sh.
  - skills/felhom-web-design/SKILL.md is the override layer and names every conflict:
    the static-HTML stack fence (no React/Tailwind/Motion/npm), nothing fetched from
    another server (kills taste-skill's picsum/Unsplash/SimpleIcons ladder and its
    npm icon libraries, since we have a self-hosted sprite), real images only, the
    Hungarian gondolatjel surviving the en-dash ban, the claim rule, and the SEO-keep
    list. 137 lines, check_skills.py PASS.
  - SOURCES.md records the provenance and the kept/overridden table.

documentation/audits/redesign-2026-10-10/AUDIT.md
  Measured against the LIVE site, not the file. 12 patterns to retire (R1-R12), each
  naming the taste-skill rule it breaks; 7 to keep; dial reading 3/2/4 -> 6/3/4;
  8 levers in priority order for the operator to approve at STOP 1.

  Headline measurements: 10 922 px tall at 1440 and 19 913 px at 390 (23.6 phone
  screens); 11 sections but only 8 layout families, why-grid used 3x and
  apps-showcase 2x; 18 em dashes; 16 requests / 533 KB from exactly two hosts.
  Contrast measures 7.56:1 body and 16.67:1 headings - AAA, and an accessibility win
  to preserve rather than a thing to fix.

  Method note: resize_window does not move window.innerWidth on this workstation and
  DevTools device mode could not be driven, so the page was rendered in a same-origin
  iframe at each width. Faithful, with two positive observables: the hamburger
  computes to display:block at 390, and clientWidth == scrollWidth == 375.

Gates: site, hostinstall, hub-confirm, register and the rest green. instructions and
script-tests fail on this Windows workstation for environment reasons that predate
this change (E:\git\CLAUDE.md is the deliberate Windows adaptation the gate wants
identical; fcntl missing; relpath across C:/E:; the cp1250 console trap). Re-run on
DooPlex follows.
2026-10-10 21:32:40 +02:00
admin 7ff64f40ed STATUS + REPORT: the design round, the sitemap BOM, and that there are no testers
gates / gates (push) Failing after 12m27s
Records what your screenshots turned up: the per-page scoping that left the
tester pages unstyled, the site-wide missing base link rule (which also
affected gyik/technologiak/biztonsagimentes), the sitemap BOM, and the
correction that nobody is testing today so all five places are open.
2026-10-10 20:45:18 +02:00
admin 88200cffd7 website: the waiting-list sentence follows from 'all 5 places are open'
gates / gates (push) Successful in 6m22s
'Ha most nincs szabad hely' read oddly directly after saying every place is
free. It now talks about what happens when the test fills up, which is the
case the sentence is actually for.
2026-10-10 20:43:37 +02:00
admin 69035f4af5 website: the tester pages get the design system, and content links stop turning purple
gates / gates (push) Successful in 6m34s
Root cause of "no formatting for the points": .info-card and .highlight-box are
scoped per page (.page-technologiak / .page-biztonsagimentes) and the new pages
carry .page-teszteles, so NONE of the card chrome applied - the sections were
unstyled text runs. The tester pages now join the technologiak scope, whose h3
is a flex row (these headings carry an icon).

Three more gaps the new pages exposed, all fixed site-wide rather than patched:
  - There was no base `a` rule at all, so an inline link in body copy fell back
    to the browser default and changed colour once visited. .legal was the only
    place this had been fixed. /gyik, /technologiak and /biztonsagimentes each
    carry such links and had the same bug.
  - `code` was styled only under .legal.
  - A <ul> inside an info-card was unstyled: wrong colour, wrong indent.

Justified body copy on the tester pages, as asked. NOTE: no other page
justifies today, so this is deliberately scoped to .page-teszteles and can be
rolled out site-wide or dropped in one edit. hyphens:auto, because Hungarian
sets badly when justified without it.

site.css -> v=10 on all 20 pages.

sitemap.xml: BOM removed. Search Console shows the freshly submitted clean
sitemap as "Sikertelen lekeres" with an empty last-read, and a BOM before the
XML declaration is a known irritant for its parser. The file is otherwise valid
(18 <url>, parses, served 200 as application/xml). No gate covers sitemap.xml
and the BOM rule is for website/*.html only.

Facts corrected - there are NO testers (operator, this evening): "Tester 1" is a
disposable virtual box and "Tester 2" is a friend whose machine is unassembled
and switched off. The page said "Nehany hely mar betoltve", which was untrue; it
now says the test is starting and all 5 places are open. Same correction in
OUTREACH.md (five people needed, not three), CONTEXT.md, and the terms-1.1 mail,
which in practice has one recipient, not two. No scheduled post claimed a
filled place, so none needed editing.
2026-10-10 20:40:43 +02:00
admin 8ef7c3a7e2 R-784 narrowed: the SparkyFitness author agreed (official images, EUR 1/household/month quarterly, 90 days' notice); closes when the operator's e-mail is sent
gates / gates (push) Successful in 6m18s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-10 20:36:56 +02:00
admin ca69e35335 REPORT-testers: say plainly that CI's conclusion could not be read, and what stands instead
gates / gates (push) Successful in 6m3s
Both credential attempts against the Gitea jobs endpoint returned 401 and the
store holds no Gitea API key, so no green is claimed. The positive observable
is the DooPlex run of the same gate entry point at this HEAD: 19/19 green.
2026-10-10 16:28:48 +02:00
admin 86361a79c8 testers: the outreach kit, R-929 (the app count disagrees), STATUS and the report
gates / gates (push) Successful in 6m6s
OUTREACH.md: a personal message, a Facebook group post with a shorter variant,
a forum post, and a table of 15 places with the rules quoted where they are
published. Nothing was posted and no group was joined; the group data was read
from each group's public About page on 2026-10-10.

The rules that matter, measured rather than assumed: Magyar Linux Felhasznalok
(11970, public) has no advertising ban and Felhom is on topic; DIY Smart Home
forbids ads and names an e-mail route; HUP forbids unlicensed advertising; the
prohardver family forbids "tagok, vasarlok gyujtese ... felhivas" without the
operator's permission, which is literally what recruiting testers is.

R-929 (P4): the website's prose says 58 apps, the apps page renders 59 cards,
the catalog holds 60 template directories. Gate 15 cannot catch it because it
compares the two language sets to each other, never to the catalog. Not fixed
here - it needs the catalog skill's exclusion rules. The campaign posts say 58,
matching every prose claim on the site.
2026-10-10 16:25:25 +02:00
admin 3631f26f39 hub 0.146.0 live: STATUS + REPORT-hub-system-page (release and live read-back)
gates / gates (push) Successful in 6m27s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
2026-10-10 16:21:01 +02:00
admin 2db785daf4 manifests: hub 0.146.0
gates / gates (push) Successful in 6m8s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
2026-10-10 16:16:48 +02:00
admin 9fbdee83d9 hub v0.146.0: the System page layout (release)
gates / gates (push) Successful in 6m3s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
2026-10-10 16:13:58 +02:00
admin 5bea5f2ebf marketing + seo: the three-week tester campaign, schedule-post --link, the not-indexed audit
gates / gates (push) Successful in 6m15s
COPY.md section 7: five Hungarian posts for Tue/Thu 19:00 over three weeks, each
with a source comment per claim and one link. The Monday post (2026-10-12, 6.2)
is untouched and no slot shares its day.

fb_probe.py gains --link (default unchanged). Every scheduled post used to
attach the home page's preview card whatever its text said, so a post about
/teszteles would have sent the people who clicked its card to the home page.
build_parser() split out of main() so a test can parse argv. Red-proved: both
new tests fail with "Namespace object has no attribute link" without the flag.

Search Console audit (seo-2026-10-10/not-indexed.md): all seven not-indexed
URLs with a verdict each - four expected by design, two waiting on Google's
crawl queue, one fault on our side. That one is /api/contact, the contact
form's POST endpoint crawled as a page; robots.txt now disallows /api/. The
performance baseline (0 clicks, 47 impressions, position 73, nine queries) is
recorded there to compare against in a month.
2026-10-10 16:13:23 +02:00
admin 9d530b8f4a R-928 filed: concurrent gate runs in the shared clone see each other's decoy plants; register 126
gates / gates (push) Successful in 6m13s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-10 15:59:31 +02:00
admin a263061183 STATUS: the 2026-10-10 decision sheet (S1-S38, T1-T19) and the register-shrink report; R-903 live read-back
gates / gates (push) Successful in 5m55s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-10 15:57:06 +02:00
admin b8db1383bf REPORT-hub-system-page: CI job 1643 green for cf6fec8d
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
2026-10-10 15:47:58 +02:00
admin 92dc41638a website: a tester recruitment page, and test terms 1.1 (the domain)
gates / gates (push) Failing after 13m28s
New page pair /teszteles + /en/testing: who the closed test is for, what a
tester needs (machine + internet quoted verbatim from the FAQ, plus a domain),
what they get (terms section 3, nothing new), what we ask for, and how many
places there are. Every "Jelentkezem tesztelonek" button now goes there.

Operator rulings 2026-10-10, recorded in CONTEXT.md:
  D1 - the tester's domain is in the TESTER'S OWN name; Felhom pays its fee for
       two years and the tester keeps it when the test ends or they leave; DNS
       is managed with a token scoped to that one zone only.
  D2 - the closed test runs with at most 5 households.

Terms 1.1 adds section 4 (the domain) with the D1 text; old sections 4-11 are
renumbered 5-12 and nothing else changed. Section 11 promises the testers an
e-mail before a change, so one is drafted for the operator to send.

Registered in site_gates.py TWINS/URL and listed in sitemap.xml.
2026-10-10 15:47:15 +02:00
admin cf6fec8d87 hub (unreleased): the System page answers 'is anything wrong?' and 'is anything waiting for me?' first
gates / gates (push) Successful in 6m17s
Needs attention, Waiting for you (one card per kernel/Docker/Proxmox set the button may approve), a
7-column Boxes table whose rows open to every old value, and a closed Details (release ids, cancelled
approvals, ring-0 counts, floors, crash guard and root files, Approve now - which now asks first).
Same data, buttons, routes and CSRF field. No deploy. Screenshots in audits/hub-system-page-2026-10-10/.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
2026-10-10 15:38:25 +02:00
admin ec5605d42c register shrink 2026-10-10: 13 rows closed with live evidence (138 -> 125); R-903 phone menu without JS; R-910 pictures; R-912 site gate 21
gates / gates (push) Successful in 6m4s
Closed: R-906 R-907 R-909 R-910 R-911 R-815 R-756 R-570 R-896 R-912 R-903 R-338 R-916.
Updated: R-899 (press set up, dated check 2026-10-11), R-243 (the mail is due 2026-10-11 ~16:06Z, dated check),
R-782 (homepage live; glance question to the operator), R-904 (the TLS sentence is in 01 s7).
Website: site.css v=9 (scripting:none menu), eight dashboard pictures retaken. Evidence: audits/register-shrink-2026-10-10/.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-10 15:27:59 +02:00
admin dee4e0aa0c new-apps report: CI job 1635 green, which settles that the Windows gate reds are the workstation
gates / gates (push) Successful in 6m10s
2026-10-10 14:54:17 +02:00
admin 9255d939e3 nodes.md: the update-harness bench (LXC 9401 on demo-hp) was in no document
gates / gates (push) Successful in 6m6s
A session that needs the swap-0 venue for checklist 5.1 had to find it with
pct list, and a brief this week placed it on the wrong host. Now recorded where
such facts live: which host, why swap is 0, that it is normally stopped, what it
keeps in /opt/upg between runs, and that its images are not pruned.
2026-10-10 14:50:35 +02:00
admin cf1e137129 R-887: three CI jobs lost today, all ending at :45:58 past the hour
gates / gates (push) Successful in 6m0s
1631 (catalog b7f0f7c), 1632 (felhom.eu 970616b7) and 1634 (felhom.eu 29c9cb1e):
every step failure with 0 s after 10.5-14 minutes in set-up, logs absent. A job
never picked up would end at an arbitrary second; the same second-of-the-hour
twice two hours apart points at a periodic sweep or a fixed deadline. Between
them the runner worked — catalog job 1633 succeeded normally on the same tree,
and a shallow clone with no sibling runs the catalog gates green by hand, so the
code is not what is red. The 2026-10-12 due-check's premise is false and the row
now says so.
2026-10-10 14:46:47 +02:00
admin 29c9cb1e9a new-apps report; Monica closed on the operator's word (R-927)
gates / gates (push) Failing after 10m32s
The operator was asked at the end, as the brief said, and ruled: keep Monica
out. R-927 opened and closed in the same session, with the measurements and the
sentence worth keeping — an app is not added because a gap exists, it is added
because the app can be kept. Register 137 -> 138: 2 opened, 1 closed.

Also in here: the two small things seen and not filed (remove leaves hold-logs
in the stack directory, with no secret in it; the catalog clone's pre-push hook
is unarmed, so the gates were run by hand before the commit and by CI after).
2026-10-10 14:34:47 +02:00
admin 970616b72b New apps 2026-10-10: Grocy and LubeLogger on the website; Monica stopped
gates / gates (push) Failing after 11m41s
The catalogue side is app-catalog-felhom.eu b7f0f7c. Here: the evidence, the
website, the register and the operator's view.

Website
- Two cards in the Otthon & Eletmod / Home & Lifestyle section of BOTH apps
  pages, with assets: grocy-logo.svg is grocy's own icon with its single fill
  made white like the other logos, lubelogger-logo.png is the app's own icon
  with its dark background dropped and the mark made white (the rule
  SparkyFitness's PNG follows), and six screenshots of each app's own UI with a
  household's own data, taken headless on the bench from the published template.
- The app count moved 56 -> 58 in 15 places per language set, both languages,
  and the open-source tile 49 -> 51. Checked by asking the same patterns for the
  new number afterwards. marketing/facebook/COPY.md still says 56 and is NOT
  changed: the post it carries is already scheduled.

Evidence
- documentation/audits/new-apps-2026-10-10/ — FIT.md (checklist group 0 for all
  three, with the Hungarian-UI column), the bench and box transcripts, the
  memory samples, the screenshots and the gate runs.

Register: 137 -> 139 rows, 2 opened, 0 closed.
- R-926 after a remove-keeping-backups and restore, nobody has checked what the
  app page shows for an after_install app's generated password. Measured here:
  LubeLogger is safe (its login is derived from the environment at every start,
  the new password signs in, the data is back); grocy's install password still
  signs in from the restored database but the deployed environment no longer
  carries ADMIN_PASSWORD at all. Seven apps are in the class.
- R-927 Monica, stopped at checklist 0.2 with the measurements, waiting on the
  operator.

Gate scripts: the same console trap in nineteen of them and in repo_gates.py
itself, where it ABORTED THE WHOLE RUNNER at the first gate — printing a
non-ASCII character on this workstation's cp1250 console raised
UnicodeEncodeError before the gate had decided anything, and reuse_refs_check.py
died while printing a NOTE. All now reconfigure their own streams. Red-proof
that the remaining script-test failures are not mine: test_due_checks_gate.py
fails the same 5 of 42 with the change reverted.
2026-10-10 12:34:05 +02:00
admin e0be6e7cd6 release 2026-10-10: CI runner restart (operator yes) evidence; report
gates / gates (push) Successful in 6m13s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-10 11:11:31 +02:00
admin a406efc7d5 release 2026-10-10: hub 0.145.0 deployed (security check PASS live), controller 0.305.0 delivered, kernel button offers -22; R-921/R-922 released; R-925 consequences; build skill: sync only the hub when other resources drift
gates / gates (push) Successful in 6m26s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-10 10:02:33 +02:00
admin b4083a06ed manifests: hub 0.145.0
gates / gates (push) Successful in 5m55s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-10 09:40:08 +02:00
admin ca9408f153 hub v0.145.0: the kernel approval rule (operator ruling 2026-10-10, 09 §3 decision 195) + release entry for the security fix, R-922, MAIL-HOLD
gates / gates (push) Successful in 6m3s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-10 09:27:54 +02:00
admin ca584d30b6 kernel night 9→10 read back: demo-hp 7.0.14-22 (~3.5 min down), demo-felhom 7.0.14-23 (~65 s), no false alarm, Approve kernel set not shown (boxes on different kernels)
gates / gates (push) Successful in 5m53s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-10 07:36:10 +02:00
admin 0e9e5260ae gates: run poster-facts last, matching the docstring order
gates / gates (push) Successful in 5m56s
scripts/test_repo_gates_docstring.py pins the numbered list in repo_gates.py's
docstring against the GATES table IN ORDER. I listed poster-facts as 17 but
inserted it before decoy-coverage, so the sets matched and the order did not:
'same set, different order'. Caught on DooPlex, where script-tests runs (it
needs fcntl and cannot run on Windows).

Moved the table entry after decoy-coverage rather than renumbering the
docstring: the gate genuinely belongs last, since it only reports.
2026-10-09 18:15:55 +02:00
admin a08bd3cbd5 architecture: the system poster committed, its facts given a home, and a rule to keep them together
gates / gates (push) Failing after 5m29s
PART A -- the poster. documentation/architecture/felhom-system-poster.html
(307 KB). Secret scan first: ZERO IPv4, zero PEM blocks, zero ssh keys, zero
Bearer. The one EAA... match is base64 inside an embedded "mime":"font/woff2"
blob, not a Facebook token. "token"/"secret"/"password" appear 11 times and
every one is a NAME ("6. ep0 read token", "the hub seal key"); the poster
itself says "Names only; no secret values". All five long base64 blobs are
declared assets: 1 image/png, 3 text/javascript, 1 font/woff2.

It renders with NO network: the source mentions cdn.jsdelivr.net and Google
Fonts, but the loaded requests are only the HTML plus blob:/data: URLs -- the
bundler inlined everything. Measured, not assumed, and it matters: this is a
disaster-recovery document, so needing the internet to draw would be a defect.
No console errors.

The operator's three Claude Design fixes are all present: (a) no "WG" badge,
WireGuard only for the tunnel, no badge on the ep0-copy tile; (b) the box ->
ep0 arrow reads "encrypted on the box, sent through WireGuard"; (c) "Known
gaps" holds two items and NOT the household-keys sentence, which is now a
neutral "By design" note under the ep0 household namespace.

ONE FACT ON IT WAS WRONG. The felhom.eu tile said "served from DooPlex through
Cloudflare". It is not: Cloudflare is DNS only and the traffic goes direct --
measured this morning for the privacy notice, which states exactly that. The
poster would have contradicted a published page. Fixed in place (a label):
"served from DooPlex, Cloudflare DNS only". The first wording overflowed the
fixed-size tile, so it was shortened to fit and the evidence lives in the
facts file instead -- checked by re-rendering, not by hoping.

PART B -- the facts and the rule. DESIGN-PROMPT-...md is renamed
felhom-system-poster.facts.md (one home per fact), with the three fixes folded
in as explicit instructions so a regeneration cannot undo them, plus a new
"Badges" section saying a "WG" chip must never come back.

New rule, section 6 "The system poster stays true", added IDENTICALLY to all
five copies of unprompted-work.md (the four repos and the workspace root on
DooPlex; verified identical by diff before and after) and to
PROMPT-TEMPLATE.md's end-of-session checklist as a FIFTH coupled artifact.

scripts/poster_facts_gate.py WARNS when the facts file has a newer commit than
the poster. It never fails a push, deliberately: a refresh needs Claude Design
and the operator, --no-verify is forbidden here, so a blocking gate would leave
deleting it as the only way out. It compares COMMIT times, not mtimes, because
a checkout rewrites mtimes and every fresh clone would shout.

RED-PROOF -- and it found a real bug in the gate. The first run warned
correctly but exited 1: a single non-ASCII character in its own warning raised
UnicodeEncodeError on this cp1250 console. A gate whose entire contract is
"never fails a push" was failing pushes. Fixed (ASCII output + an encode
guard), and the decoy now asserts BOTH the warning and exit 0. Three branches
proven: facts newer -> warns, rc 0; poster newer -> quiet, rc 0; poster
missing -> "could not tell", rc 2, not a false all-clear.

The decoy itself was seen to fail, twice, on Linux (the suite needs fcntl and
cannot run on Windows): breaking the warning gives STALE_WARNS=False, and
making it exit 1 gives RC_STALE=1. All 80 felhom.eu decoys behave.

PART C -- do box reports pass through Cloudflare? NO. Two channels. DNS from
PUBLIC resolvers (not DooPlex's own, which answers the LAN address):
hub.felhom.eu is a CNAME to dooplex.hopto.org -> 37.191.56.193, not a
Cloudflare address, and no cf-ray comes back. The manifest: an ordinary k3s
Ingress, Cloudflare named only in a DNS setup comment. THE CONTROL that makes
the negative mean something: iso.felhom.eu resolves to 172.67.x / 104.21.x,
real Cloudflare addresses -- so the method does detect proxying.

So nothing is added to the Cloudflare row: the hub path does not touch it.
06-offsite-connectivity.md section 1 claimed the public edge is a
Cloudflare-Tunnel and "DooPlex has no public IP" -- both untrue today. Kept
and marked STALE with the measurement rather than rewritten, because that
paragraph is the reason ep0 exists and the argument needs its premise visible.
total-loss-of-dooplex.md's "today a CNAME to dooplex.hopto.org" is confirmed
correct.

Register: 137 before, 137 after, 0 opened, 0 closed -- every finding here was
small and fixed in the session.
2026-10-09 18:09:50 +02:00
admin e3741ae493 facebook: the first post SCHEDULED for 2026-10-12 19:00 (R-917 -> VERIFY)
gates / gates (push) Successful in 6m5s
Not public. It sits in Planner until Monday evening and can still be changed
or deleted there.

THE POST. Operator chose version 6.2 (kozepes), Hungarian only, 638 Unicode
characters, 0 emoji, 0 hashtags. He chose Monday over today on the reasoning
offered: it was Friday 15:08, the weakest evening of the week for a first
post, and three days in Planner is review time.

  post id   1360018983863273_122096547315511222
  due       2026-10-12 19:00 Europe/Budapest = epoch 1791824400 = 17:00 UTC
  link      https://felhom.eu/

READ BACK, and the hex check recomputed OUTSIDE the probe so it is not the
same instrument twice: is_published False; scheduled time sent == read;
message sha256 887514383eff997c on both sides (COPY.md 6.2 and what Facebook
returned). Present in GET /{page}/scheduled_posts. And from a DIFFERENT
CHANNEL than the API: Planner shows it on H 12 at 19:00 with the link card.

SCENARIO A, the dry check that had to come first. A throwaway scheduled post
WITH THE LINK was accepted -- so `link` is not refused on a scheduled post,
which was the open question. Read back hex-equal and unpublished, seen
PRESENT in the scheduled list, deleted, seen ABSENT in the same list. The
removal proof comes from the LIST, not from an error after DELETE, which is
what R-914 asked for.

CHECKED RATHER THAN COPIED. The post repeats the website's "56 alkalmazas".
The apps page carries 57 <div class="app-card"> while saying 56 -- which
reads as an off-by-one until you read the category line, "6 alkalmazas + 1
beepitett". The 57th card is FileBrowser, built into every box and
deliberately not counted; index.html says "56 telepitheto alkalmazas" too.
NOT-A-FINDING, and a "fix" would have made a live public page wrong.

R-917 -> VERIFY (close when the operator confirms it published and is
pinned). R-914 noted, NOT closed: schedule-post covers text + link only; the
photo path stays unbuilt because the spike could not prove a scheduled PHOTO
stays hidden, and the pin, comment moderation and post-insight read-back are
still missing.

Secret scan on the committed evidence: planted EAA decoy 1 -> 0 after
deletion, 0 access_token, no run.log.
2026-10-09 15:14:55 +02:00
admin 3a77ed73aa facebook: the first post drafted (COPY.md section 6) + fb_probe schedule-post
gates / gates (push) Successful in 5m58s
DRAFTS. COPY.md section 6: two versions of the Page's first post, shortened
from section 2. Hungarian, tegezo, no price. 6.1 = 347 characters, 6.2 = 638
(counted as Unicode characters). Every claim carries a source comment naming
the line of website/index.html it rests on; the first line of each carries the
point alone, because Facebook cuts after about three lines.

Deliberate: ZERO emoji and ZERO hashtags, though the brief allows two of each.
The Felhom design system uses no emoji (the website gate holds it at 0) and
two hashtags would serve no real search.

CHECKED, because the post repeats it: "56 alkalmazas" is CORRECT. The apps
page carries 57 <div class="app-card"> but states 56, which looks off by one
until you read the category line -- "6 alkalmazas + 1 beepitett". The 57th
card is FileBrowser, built into every box and deliberately not counted.
index.html says "56 telepitheto alkalmazas" too. I nearly "fixed" a live page
into being wrong. NOT-A-FINDING.

SCHEDULE-POST. A third sub-command on fb_probe.py, reusing its token loader
(R-453), redaction, Bearer call and evidence writer:

  - the body is READ FROM COPY.md by section name. The Hungarian never passes
    through a shell or an argv string (brief 9.6); the caller names a section.
  - published is ALWAYS "false" and NO argument can change it (brief 9.7).
    The operator's review in Planner is the safety net, so an immediate post
    must be unreachable, not merely not-the-default.
  - check_when refuses a time under Meta's 10-minute floor or over its
    6-month ceiling, BEFORE the call, so a bad time is a readable local
    refusal rather than a Graph error.
  - budapest_to_epoch uses the real tz database. If zoneinfo has no
    Europe/Budapest it REFUSES rather than falling back to a hardcoded
    +01:00/+02:00 -- guessing the offset is how a post goes out an hour wrong
    across a DST boundary.
  - list_scheduled tries /scheduled_posts then feed?is_published=false and
    RECORDS WHICH ANSWERED; when both are refused it returns None so the
    caller says "unproven" instead of claiming a removal it never saw.

TESTS: 30, of which 2 skip on Windows (no tzdata in this interpreter; the
command runs on the Linux host, which has the system zoneinfo).

RED-PROOF of the guard that matters, as the brief requires. Made
schedule_form accept published=..., ran ScheduleForm, and watched
test_no_argument_can_publish_immediately FAIL:
    AssertionError: 'true' != 'false' : published changed published
Guard restored, all 30 green again.

No post has been made. The dry check and the real post come next; the
operator picks the version and the time first.
2026-10-09 15:06:47 +02:00
admin a05345eeb6 R-924: live run + restore test evidence; STATUS and report
gates / gates (push) Successful in 5m55s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-09 15:02:37 +02:00
admin 96f68f1b44 dooplex-offsite: the operator signing keys ride the nightly encrypted copy; restore test proves each key matches its public half (R-924, operator ruling option A)
gates / gates (push) Successful in 6m7s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-09 14:49:08 +02:00
admin fe80548144 website: the header mark had no white fill — wrong source file (and R-916 corrected)
gates / gates (push) Successful in 5m36s
I used assets/logo_notext.svg for the header mark. That file is the
LIGHT-BACKGROUND variant: it has SEVEN #00408d fills and ZERO #ffffff, so on
the dark nav the cloud rendered as a hollow outline. The operator caught it.

logo_notext_white.svg is not the answer either -- it is a white OUTLINE
version, also unfilled. Rendered all four candidates side by side on the real
nav background to see it rather than infer it: only logo.svg (and logo.png)
carry the real artwork -- white cloud, #051343 house and servers, #008ddf
swoosh.

FIX: assets/logo-mark.svg, cut from logo.svg -- keep <defs>, path6 and g2;
drop the five wordmark paths and the two empty <text> elements; viewBox
cropped to the mark (70 0 505 295). Vector, correct fills, no text.
All 18 pages point at it; site.css cache-bust v7 -> v8. The CSS comment now
says which file NOT to swap back in, and why.

AND A CORRECTION THAT REMOVES AN OPERATOR TASK (R-916). That row says the
project has no usable vector master because logo.svg "sets felhom.eu as live
text" in 'M+ 2c'/'Vremena Grotesk', and it waits on "the machine with the
fonts". MEASURED today, while cutting the mark out of that very file:

  - all five wordmark elements are <path> with real d= geometry
  - NO <text> element has any content; the two present are empty leftovers
  - the font-family strings the row cites are Inkscape METADATA left on
    CONVERTED paths (-inkscape-font-specification). A grep for font-family
    finds them and reads as live text -- the likeliest way the original
    diagnosis went wrong.
  - proof from a renderer that lacks both fonts: Chrome draws logo.svg's
    lettering identical to logo.png's, side by side.

NOT re-tested: librsvg specifically -- DooPlex has no rsvg-convert, inkscape
or cairosvg installed today, so the original librsvg/DejaVu observation could
not be reproduced either way. It does not change the structural fact: there
is no font left to substitute. Consequence: the 645x408 PNG is not the only
faithful copy and does not cap picture size.

R-916 state -> READY with "re-check before doing any work: this may need
nothing from the operator at all", rather than closed on my say-so.
2026-10-09 14:28:22 +02:00
admin de52bcbdc8 facebook: the Meta app is LIVE (R-915 closed); website lockup entry
gates / gates (push) Successful in 5m47s
R-915 closed and moved to CLOSED-ITEMS in the same commit. What it had waited
on was R-813's Terms of Service URL, which did not exist until the closed-test
legal set went live this morning.

Filled in the app's Basic settings and verified they persisted across a full
reload (not from the save toast):
  Privacy policy URL              https://felhom.eu/adatkezeles
  Terms of Service URL            https://felhom.eu/feltetelek
  Data deletion instructions URL  https://felhom.eu/adatkezeles
  Category                        "Vallalkozasok es oldalak"

THE APP ICON WAS NOT REQUIRED. The original row listed it among the Live
blockers; Meta answered "All required app settings are complete" with it still
empty. Recorded so the next session does not go hunting for one -- and it
could not be uploaded from here anyway: the icon control creates its file
input only on click, and clicking opens a native dialog the browser tooling
cannot drive.

Published, and READ BACK FROM A FULL PAGE RELOAD rather than the success
toast, because Meta's toasts have lied on this Page before: the badge reads
Published, the string Unpublished is gone, and the page now offers Unpublish.

Nothing was granted. No permission added, no use case changed; the scopes stay
"Ready for testing", which is all a system user needs for the business's own
Page. Going Live changes WHO CAN SEE what the app posts, not what it may do.

R-917 and R-920 are unblocked by this -- both were waiting on posting starting.
R-813's next action (a) is spent.

Also carries the marketing CHANGELOG entry for the header/footer change pushed
in 625d38645c.

CI for the three commits before this one: #875 SUCCESS (after a re-run -- the
first attempt was R-887's lost-job flake, "Set up job" 11m48s then every step
0s), #876 SUCCESS, #877 SUCCESS.
2026-10-09 14:06:35 +02:00
admin 625d38645c website: one brand lockup in the header, and footer links that look like links
gates / gates (push) Successful in 5m54s
HEADER. logo.png carries its OWN "felhom.eu" lettering under the mark, so
putting it next to a typed <span class="logo-text"> said the name twice and
squeezed the mark down to 40px to make room. Now:
  - the mark alone, bigger: assets/logo_notext.svg at 54px (44px under 600px).
    Vector, so it stays crisp. Its two <text> elements are EMPTY, so R-916's
    missing-font problem does not apply to this file -- checked, not assumed.
  - the name beside it is the brand's OWN lettering, cropped from logo.png to
    the new assets/logo-wordmark.png (632x108, tight bbox).

Why an image and not text: the wordmark's face is "M+ 2c"/"Vremena Grotesk"
(R-916). Nothing here has it, and the site deliberately loads NO external
font -- the privacy notice published this morning states exactly that, so
pulling in Google Fonts to match a logo would have made a published claim
false. Using the artwork is also what the Facebook covers already do. The
white/blue split the operator asked for is in the artwork itself.

Accessibility kept: the mark is alt="" aria-hidden (decorative), the wordmark
carries alt="felhom.eu", so the link still has its accessible name.

FOOTER. The legal links were unstyled, so the browser painted them default
blue and PURPLE once visited. They now follow the site's own convention
(.page-kapcsolat .sidebar-card a): --blue-bright, no underline, underline on
hover. :visited is pinned to the same colour deliberately -- a legal link
that changes colour after one read looks like it stopped working. The same
fix applied to .legal a on the two new legal pages, which had --blue instead
of --blue-bright.

18 of 18 pages carry the new lockup; the English pages keep their /en/ logo
href. site.css cache-bust v6 -> v7 on all 18, per the website rules. Verified
rendered in a browser on both a Hungarian and an English page: both images
load, no .logo-text left anywhere, footer links computed rgb(46,168,245).
site_gates OK (nav/footer per language, BOM, cache-busting, twins).
2026-10-09 13:47:22 +02:00
admin eba522f06e secrets: the 12 remaining reused logins as a checklist; repo stays public (operator rulings)
gates / gates (push) Successful in 5m44s
Operator ruled 2026-10-09, after seeing the measurement:
  (a) he rotates the remaining services himself -- CC's scope stopped at the
      Felhom boundary;
  (b) felhom.eu STAYS anonymously readable for now, because making it private
      breaks the website git-sync and the installer tag fetch, which both
      clone with NO credentials (R-110).

The standing consequence of (b): no secret may ever enter this repo again,
which manifest_bearer_gate.py now enforces with no exemption. If (b) is ever
reversed, the 32 <!-- source --> comments served on /adatkezeles must be
stripped in the same change, because they are a map of the repo.

secrets.md now carries the exact checklist -- namespace / secret / key, 12
rows, RE-MEASURED after the Felhom rotation by hashing against the value git
history still serves, which also confirms the three CC rotated are absent
from it.

Two things recorded with it, both learned the hard way the same day:
  - a DATABASE password is not changed by editing the Secret. bookstack-db
    root-password is read at first init and then lives in the engine, exactly
    like umami's POSTGRES_PASSWORD did.
  - check the app can still RESTART before trusting the rotation: umami ran
    124 days at 512Mi and was OOMKilled on every restart attempt.

And the urgency, measured rather than assumed: these are not LAN-only.
nextcloud / paperless / bookstack / qbittorrent .dooplex.hu all resolve in
PUBLIC DNS to the public address and answer HTTPS with a login page. No login
was attempted; reachability is the point.
2026-10-09 13:37:28 +02:00
admin e467785fd3 security: rotate the published secrets and de-git felhom.secret.yaml (R-925, P1)
gates / gates (push) Successful in 5m23s
WHY .gitignore "was not working": it was working. git never consults
.gitignore for a file it ALREADY TRACKS. The rule `*secret*` matched fine --
proved by dropping an untracked copy in and watching check-ignore name
`.gitignore:3:*secret*`. The file had been tracked since feea0606, which is
ironically the commit that de-gitted the Resend key.

WHAT THE EXPOSED VALUE ACTUALLY WAS. Not an analytics password: the GITEA
ADMIN ACCOUNT PASSWORD (is_admin true; /api/v1/admin/users answered 200), in
a repo gitea.dooplex.hu serves anonymously to the internet. That is push
access to every repo -- including the one whose website/ is git-synced live
and whose scripts/ is published by tag to every new box installer (R-110).
Re-ranked P2 -> P1 on that measurement; my first ranking had only measured
the analytics blast radius.

Every committed value was still live. Nothing had ever been rotated.

ROTATED (values never echoed; written to a 0600 file on DooPlex):
  umami-config        APP_SECRET + POSTGRES_PASSWORD. The password was
                      changed INSIDE postgres (ALTER USER) as well as in the
                      Secret -- the env var is only read at first init, so
                      patching the Secret alone would have changed nothing.
  healthchecks-config SECRET_KEY + SUPERUSER_PASSWORD (nothing consumes them,
                      there is no healthchecks Deployment).
  gitea-creds         no longer holds the admin password at all: a SCOPED
                      token (read:package + read:repository).
  gitea admin         new random password; gitea-system/gitea-admin updated.

VERIFIED, not assumed:
  - new admin password -> 200, OLD PUBLISHED PASSWORD -> 401 (the leak is dead)
  - umami: a real beacon returns 200 (so the app authenticates to postgres and
    writes) while a bogus site id still returns 400 (so the 200 means something)
  - hub: "Registry version check: latest = 0.304.0" AND "Template fetched
    (5881 bytes)", no auth failures
  - BOTH token scopes are load-bearing, and the second was found by breaking
    it: a package-only token made the hub log "Template fetch: unexpected
    status 403", because the template fetcher reads a raw file out of the
    felhom-controller repo, not the registry.

AN INCIDENT CAUSED BY THE FIX, recorded because it is the useful part: the
rollout restart needed to pick up the new umami secret put umami into
CrashLoopBackOff and took stats.felhom.eu down (503) for ~4 minutes. Not the
rotation -- at memory 512Mi that pod runs for months but CANNOT RESTART:
startup (Prisma + Next.js) peaks over the limit and is OOMKilled (exit 137).
Raised to 1Gi IN THE MANIFEST, not just live, per .claude/rules/manifests.md
("never bare kubectl set -- the next sync reverts it and the fix silently
disappears").

THE GATE: KNOWN_BACKLOG is removed from manifest_bearer_gate.py, as its own
comment instructed. Red-proofed with a decoy: exit 1 with it, exit 0 without.
An exemption kept this visible for three months and changed nothing.

WHAT REMAINS (operator, and it is bigger than what was fixed): the same
password is still the admin password in ~12 other namespaces -- nextcloud,
paperless, bookstack (a DATABASE ROOT password), tandoor, calibre,
adventurelog, gokapi, qbittorrent, servarr, homepage. Rotating Gitea does not
touch them. Also owed: a kisfenyo Gitea token sits in plaintext in the local
homelab-manifests remote URL and was printed to a session transcript during
this investigation, so it should be replaced regardless (R-580's shape).

NOT a finding: homelab-manifests is private (404 anonymously) and does not
contain the password; ArgoCD's repo credential is a separate token and was
untouched by the rotation.
2026-10-09 13:21:18 +02:00
admin 07773bf58f R-923: STATUS, capability map, session report (break the circle)
gates / gates (push) Successful in 5m38s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-09 13:01:29 +02:00
admin e5b9151e05 hub (unreleased, SECURITY): /preferences and /notify refuse a per-customer key acting for another household (403); red-proved
gates / gates (push) Successful in 5m49s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-09 12:48:54 +02:00
admin d55c590c5a hub (unreleased): R-922 option A — a household's clear deletes its notification address (email_cleared); MAIL-HOLD — a restored hub sends no mail until released; two log lines drop the address; runbooks: mail hold is restore step 1; 07 §6.4 R-921 pre-check; R-921/R-922 narrowed
gates / gates (push) Successful in 5m25s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-09 12:37:29 +02:00
admin 2c48feb325 security: R-925 — live secrets committed to a world-readable Gitea repo
gates / gates (push) Successful in 5m45s
Found while publishing the legal pages: a background security review flagged
the <!-- source --> comments served in website/adatkezeles.html. Chasing what
those comments point AT found something larger.

MEASURED, and the control is what makes it mean anything:
  - manifest_bearer_gate.py itself prints
    "manifests/felhom.secret.yaml:39 KNOWN-BACKLOG committed secret"
  - that file holds live-shaped values, not placeholders: SECRET_KEY (69),
    SUPERUSER_PASSWORD (18), Umami APP_SECRET (66) and POSTGRES_PASSWORD (34),
    plus a username/password pair. Values were never printed, only measured
    by length.
  - gitea.dooplex.hu resolves to 37.191.56.193, the website's public address
  - anonymous curl: 200 and 1686 bytes for that file; 200 for hub internals
  - OFF-NETWORK CONTROL: fetched from outside the operator's network, a real
    path returns the file's first line and a nonsense path returns 404. So
    the 200 is genuine anonymous read from the internet, not a LAN-only ACL.

This contradicts documentation/runbooks/secrets.md:3-4, which states secret
values are never committed and the manifests carry only placeholders. That
promise is false today.

Ranked P2, not P1, and the row says why so the operator can overrule: the
exposed credentials guard analytics and an undeployed healthchecks instance,
NOT household data. Measured: umami-db is a ClusterIP service with no
external IP, so the Postgres password is not internet-reachable. No customer
box, hub token or escrow key is in the file.

NOTHING WAS CHANGED. Making the repo private could break the public day-0
installer path (R-110), and rotation plus repo visibility are operator
decisions on production infrastructure. The row carries the order: rotate
first (de-git alone kills nothing — the runbook says so), then decide
visibility, then CC does the de-git and tightens the gate.

Coupled and easy to miss: the 32 source comments on /adatkezeles are harmless
while the repo is public, but become a map of it the moment it is private, so
that is one change and not two. Their traceability is already kept in
documentation/legal/*-1.0.md.
2026-10-09 12:20:52 +02:00
admin 4c388a398b R-923/R-924: total-loss-of-dooplex runbook (every recovery secret, where it lives, walked on paper), break-glass sheet (names only), Vaultwarden off-site proven (push, restore test, throwaway start); 'off DooPlex' claims corrected; R-924 filed
gates / gates (push) Successful in 5m41s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-09 12:13:41 +02:00
admin 30b932bb10 website: publish the closed-test legal set (R-813 narrowed)
gates / gates (push) Successful in 5m34s
Two new Hungarian pages, live on push: /adatkezeles (privacy notice) and
/feltetelek (what the free closed test is, and is not). Operator rulings of
2026-10-09: no company exists yet, so the operator is named as a PRIVATE
PERSON with no postal address and no phone; publish before the lawyer has
seen it, because the site was collecting data with no notice at all; the full
ASZF, the impresszum and the review wait for the company (R-802, R-809).

- All 18 pages carry the operator, info@felhom.eu and both links in the
  footer. Counted, not assumed: 18 pages found = 18 with both links = 18
  structurally valid. English footers say the legal texts are Hungarian.
- The contact form stopped claiming something untrue. The old consent said
  "az adatokat harmadik felnek nem adjuk ki" while Resend, Cloudflare and
  Google carry the message. Both languages replaced; the link opens in a new
  tab so a filled form is not lost.
- site_gates.py NO_TWIN gains the two pages ON PURPOSE, with the reason in a
  comment: an unreviewed English legal text would be worse than an honest
  pointer from the English footer.
- documentation/legal/{adatkezelesi-tajekoztato,feltetelek}-1.0.md are the
  text of record, DERIVED from the published HTML so they cannot drift. The
  drafts are kept and marked superseded for the closed test.

FOUR LOAD-BEARING CLAIMS WERE MEASURED, not copied from a vendor or a README:

  cookies      zero, and no local storage - checked in the browser WITH A
               POSITIVE CONTROL (a probe cookie WAS visible to the same
               method) after the tracker fired; no Set-Cookie on any response
  beacon       the exact Umami payload: site id, screen, language, title,
               url, referrer - no visitor identifier
  Cloudflare   DNS only: the public A record 37.191.56.193 is not a
               Cloudflare address, so site traffic cannot be proxied
  fsn1         Falkenstein, Germany (Hetzner's own location list)

Also measured: felhom-ep0-copy-gc.timer is installed and RAN SUCCESSFULLY
(2026-10-09 08:00, exit 0), so "deleted within 30 days" is true today where
on 2026-10-08 it was written but not switched on.

Three retentions are stated as having NO deadline, deliberately and with the
operator's word: website statistics, web server logs and contact messages
have no automatic deletion, and the pages say so instead of promising a date
nothing enforces. Every other period is enforced by configuration and cited.

No placeholder survived onto either page (0 of "[[", control: the draft still
has 36). The impresszum and the full ASZF are NOT published.

R-813 -> NARROWED. R-915 unblocked: the operator enters the two URLs in the
Meta app's Basic settings; the Live switch stays a separate decision.
R-917 and R-920 -> DEFERRED on the operator's (c): park, publish as posts
once posting starts.
2026-10-09 12:11:37 +02:00
admin 4cee21acf7 dooplex-offsite: Vaultwarden (the password manager) rides the nightly encrypted copy (R-923); R-923 filed (operator finding); R-922 ruling A recorded
gates / gates (push) Successful in 5m32s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-09 11:53:35 +02:00
admin 81c835827e R-232/R-173: hub restored into a throwaway k3s (runbook §3 steps 4–5 proven, corrected); R-173, R-861, R-518 closed; R-921, R-922 filed; STATUS, capability map, report
gates / gates (push) Successful in 5m23s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-09 10:54:59 +02:00