c31f0a1a516ae176710e145ff8ce7564dc8610b4
256 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
c0a2953bea |
website: the share card's wordmark is the brand's own, with the blue .eu
gates / gates (push) Successful in 6m15s
The old card's lettering was plain white and in some other face. The card now takes assets/logo-wordmark.png - the same file the sidebar shows - scaled to the old lettering's ink height and alpha-composited in its place, so felhom is white, .eu is blue, and the drawn outline is there. The cloud mark beside it is still the old card's pixels, which were always right. og:image ?v=3. |
||
|
|
655f5f66f8 |
hub v0.147.0 (code): the operator's answers S4, S6, S10, S29, S30, S32, S33
gates / gates (push) Successful in 6m0s
- S4 / R-242: GoldenVouchChecker - a published golden unvouched for 2 h raises golden_not_vouched (operator only) - S6 / R-244: the delete cascade de-references app_log_issues; one-time sweep flag -sweep-app-log-residue=count|apply - S10 / R-266: read_failed storage entry shows "read failed", not 0 % - S29 / R-250: host-key scan IPv4 first, ~2 min ladder, "safe to press Save again" error - S30 / R-246: stale_at retired (reader, setter, badge) - S32 / R-521: storage_reconnected ends the storage_disconnected cooldown on both channels - S33 / R-402: host page "Last full check (off-site)" line; two wire-gate allowlist entries removed Each with a test seen failing first. Not built or deployed yet (operator-attended deploy). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS |
||
|
|
d328147322 |
website: the share card shows the product, not just the words
gates / gates (push) Successful in 6m13s
The operator went to post the link and found the card out of date: it was the 2026-07-18 design - a headline and two lines of text on a dark field, nothing of the product, and older than everything the site has become since. - og-image.png and og-image-en.png rebuilt around the laptop, with the hero's own poster frame on its screen. - scripts/make_og_card.py: the headline, logo and button are lifted as PIXELS from the previous card and composited with `lighter` onto flat --bg-0, because the site's font is a woff2 and nothing here can draw a glyph with it. A new headline therefore CANNOT be made with this script - new words go back to the design tool and this takes that card as its source. The lede lines are gone; the laptop says what they said. - ?v=2 on every og:image and twitter:image (20 pages): a scraper caches by URL, so a new picture at the old URL would reach nobody. A card already attached to a post still does not change - that post must drop the preview and re-add the link after a re-scrape. |
||
|
|
02be8ea7f0 |
website: the reviewer's findings - consent error, reply time, sitemap, voice, clip
gates / gates (push) Successful in 6m12s
A page-by-page review of the live site (1440px and 390px) found six defects and
two editorial questions. The operator answered three questions; the answers and
the evidence are in REPORT-review-2026-10-12.md.
Fixed:
- The contact form showed its consent error before any submit, on both pages:
#privacyError sits outside any .form-group and the hide rule was scoped to
.form-group. Scoped to the page. Checked: load (none) -> submit unticked
(shown) -> tick (gone), with no message sent.
- The consent checkbox is the site's own control now: 24px box, keyboard focus
ring, and a second <label for="privacy"> at 44x44 round it for touch.
- The contact page promised a reply within 24 hours while /feltetelek 1.1 §4
promises no reply time. Now 1-2 days usually, and no promise during the test.
- sitemap.xml was missing /szolgaltatasok and /en/services: 18 -> 20 URLs.
- The pre-shell mobile-menu script still ran on 20 pages and logged
"[mobile-menu] Missing elements" on every one. Removed.
- The sidebar's tester button was btn-outline while the hero's was btn-primary.
- The home page's "Mit tud a doboz ma?" was three bare links; each card now
carries 2-3 of the services page's own items, word for word.
- A plain Facebook link in the footer of all 22 pages. No script, widget or
pixel: the only external hosts any page refers to are still felhom.eu and
stats.felhom.eu.
Voice (operator ruling: "I" everywhere a person speaks): contact, tester and FAQ
pages in both languages, and the home and services pages that repeat the same
promises. An inclusive "we" (you and I, talking) stays plural, and the legal
texts are untouched. Each FAQ answer exists twice (JSON-LD + visible) and gate 18
holds them equal - it caught the five answers whose markup split the sentence.
Hero clip rebuilt: Immich first, so the poster is a wall of real photographs;
the Jellyfin scene starts after the demo's library wall (eleven pieces of poster
art whose licence cannot be quoted from a first-party source); 1.3s of blank
screen cut from the OnlyOffice scene. The film that plays, Caminandes 3:
Llamigos, is CC BY per Blender's own video platform ("licence": {"id": 1,
"label": "Attribution"}) - NOT public domain as website/CHANGELOG.md said
yesterday. That sentence is corrected in place and the film is credited under
the hero caption.
New gate 24: sitemap.xml lists every public page once, with its twin's hreflang
pair, and lists nothing else. Decoy: site/sitemap-missing-page, the exact shape
the reviewer found by hand.
site.css ?v=30; hero clip and poster ?v=2.
|
||
|
|
b0ef27e914 |
website: the laptop screen moves - six real apps behind the cut-out frame
gates / gates (push) Failing after 7m17s
The operator recorded the six scenes and ruled on their length: use them whole, "they had been cut as I liked them". Jellyfin, Tandoor, OnlyOffice, Immich, RomM, Paperless, 0.6s crossfades, 36.6s looping at 904x556. - hero-clip.mp4 (1 134 KB) + hero-clip.webm (1 295 KB) + hero-poster.webp (53 KB), one set for both languages: the recordings are the same on / and /en/. - The hero <video> sits in the frame's cut-out hole at z-index 1, the frame above it at 2. No autoplay attribute: the page's script starts it when the hero is on screen, pauses it when it leaves, and never starts it under prefers-reduced-motion. With JS off the poster stays. - make_hero_clip.py reads each scene's own length (ffprobe) instead of cutting every one to a fixed window, and the xfade offsets count from the running sum minus one fade per transition already made. - site.css ?v=26 on all 22 pages. NOT verified: playback in this workstation's Chrome, whose media pipeline loads nothing at all today (a 1 KB generated WAV blob stalls the same way, with no error) - which rules the clip out as the cause. Geometry, layering and the poster frame were verified in the browser. Jellyfin, Paperless and RomM were filmed on those projects' own public demo sites; the films in the Jellyfin scene are public-domain prints. |
||
|
|
7733d7b754 |
website: prepare the moving laptop screen - the cut-out frame and the clip builder
gates / gates (push) Failing after 14m28s
The operator asked for the laptop's screen to show a few seconds of real apps
running. His decision: he records the raw clips, the assembly is built here. So no
Playwright and no new dependency - ffmpeg 7.1.5 is already on DooPlex.
NOT ON THE PAGE YET. The live hero still shows the still picture; this commit is the
two finished pieces plus the measurements behind the format choice.
scripts/make_hero_clip.py
NN-appname.ext in -> scaled and centre-cropped to the screen's 1.626:1, crossfaded,
out as mp4 (h264) + webm (VP9) + a webp poster. Runs on DooPlex; Windows has no
ffmpeg. Not part of any build, gate or deploy: the site has no build step, so the
output is committed like any other picture. Proven end to end against six
placeholder scenes built from the repo's own app screenshots (21s loop -> mp4
480 KB, webm 609 KB, poster 83 KB).
WHY NOT A GIF - measured, six crossfaded scenes:
904x556 mp4 331 KB | webm 411 KB | GIF 2676 KB for HALF the length
1130x696 mp4 775 KB | webm 1196 KB | webp 2551 KB
A GIF is ~11x the mp4 for the same seconds and dithers to 256 colours on a dark UI.
website/assets/hero-laptop-frame.webp
The laptop render with its SCREEN CUT OUT to transparency, so a clip plays under the
bezel with the glass reflection over it. The reflection is PAINTED: lifting the
bright pixels out of the AI-drawn screen dragged a ghost of the drawn UI along.
Hole: left 11.041% top 12.345% width 79.817% height 64.305%, ratio 1.626:1. Two
pixels of slack - a tight rect showed the drawn sidebar's highlight, a loose one
showed page background at the top left; both were seen in the browser.
The page will load it as <video muted loop playsinline preload="none"> with the first
frame as poster, started only on scroll-into-view and never under
prefers-reduced-motion. First paint: frame 59 KB + poster ~80 KB against today's single
57 KB still; the ~330 KB clip comes after, or never if the visitor does not scroll
there. No "loading" graphic needed - the poster IS the loading state.
The recording brief is in E:\felhom-video\README.txt (outside the repo: the raw files
are large and the repo is public).
|
||
|
|
42c2d84c7c |
gates: re-anchor the ascii-hungarian-text decoy on the renamed link label
gates / gates (push) Failing after 7m19s
Its anchor was "Who is behind it" in en/index.html, which became "More about me" when the home line went first person. The suite refused to build the decoy rather than skip it, which is the behaviour that makes an anchor change visible. |
||
|
|
bb69a73330 |
website: four more notes - first person, the globe's well, the touching tables, the submenu label
gates / gates (push) Failing after 5m21s
1. THE HOME PAGE SPOKE ABOUT THE OPERATOR IN THE THIRD PERSON ("Ha irsz, o valaszol")
while the page it links to is in the first ("Ha irsz, en valaszolok"). Both home
pages now read "Nagyfenyvesi Viktor vagyok, a Felhom mogott en allok" / "I am Viktor
Nagyfenyvesi, and I am the one behind Felhom", and the link after it is "Rolam
bovebben" / "More about me" rather than repeating the question the sentence has just
answered. The legal pages keep the formal third-person name, which is their job.
2. 36px OF DEAD SPACE UNDER THE LANGUAGE GLOBE, and most of it was A LEAK GATE 22
COULD NOT SEE. The old chrome's
nav { position: fixed; top/left/right: 0; padding: 20px 0;
backdrop-filter: blur(12px); border-bottom: 1px solid var(--line);
z-index: 200 }
is a BARE ELEMENT selector, so it matched <nav class="sidebar"> too - and .sidebar
declares none of those, so all of them were in force on the sidebar. Scoped
body:not(.shell); the footer row's own padding went 16px -> ~8px.
Gate 22's first half compares selectors present in BOTH stylesheets, and `nav` is not
a selector shell.css ever writes, so this shape was outside its field of view. It now
has a SECOND HALF: an unscoped bare nav/header/main/aside rule in site.css is a
failure, because those elements ARE the shell (<nav class="sidebar">,
<header class="mobile-topbar">, <main class="content">). It convicted a second live
one on its first run: R-903's `@media (max-width:900px) and (scripting: none)
nav { position: static }` had been overriding the sidebar's own position on a phone
with scripting off. `footer` is deliberately NOT on the list, with the reason beside
it: the shell carries the website's own footer.
Decoy site/bare-element-rule-reaches-shell, seen to convict.
3. THE COMPARISON TABLE AND THE TWO CARDS under "Miert a sajatod?" were touching: .vs
ends on its own border and .band opens with a 2px blue rule, so they read as one
block. 2rem between them.
4. "MINDEN ALKALMAZAS" -> "AZ ALKALMAZASOKROL" / "About the apps" on all 22 pages. Every
app is on that one page, so the first submenu item is not a filter - it is the top of
the page, where the intro and the "Fontos tudnivalok" box are. The en-nav-drift decoy
was re-anchored on the new label.
Checked at 390px and 1440px on all 21 pages: no sideways scrolling, footer inside the
content column, the renamed item on every page. site.css?v=25.
|
||
|
|
0ef0b106f6 |
website: the operator's seven notes - a services page, the hero, and 100 dead links
gates / gates (push) Failing after 6m51s
Reported from his own screens. Five defects, two design.
1. THE CATEGORY ANCHORS WERE DEAD - all 100 of them. The sidebar's five app-category
links pointed at #fajlkezeles-irodai and friends; the ids are #fajlkezeles and
friends. The sidebar is copied into every page, so one wrong fragment was wrong
twenty times, and a dead fragment raises no error anywhere: the browser stays put.
New gate 23 resolves every in-site #fragment against the page it names (360 today).
It convicted two more on its first run: the home page's four hero tiles pointed at
/alkalmazasok#immich, which no page had ever carried, and the FAQ's contact button
pointed at a home-page section that had moved out. Every app card now carries its
slug as an id - taken from the card's own logo file, which gate 21 already ties to
the catalog, so the ids cannot drift from it silently.
Decoy site/dead-fragment puts the operator's own bug back and the gate convicts.
2. SZOLGALTATASOK IS A PAGE: /szolgaltatasok + /en/services, registered in TWINS, URL
and SHELL. The ten capability items moved VERBATIM out of the home page; the home
keeps the promise sentence, the three group names as links and a button, and is 345
Hungarian / 434 English words shorter. The .caps rules stopped being .page-index-
scoped, because the block now lives on a page with a different body class.
3. THE HOME HEADLINE is back in the hero column beside the picture, two lines with the
second in --blue-bright at clamp(2.1rem, 4.4vw, 3.2rem). M3 had moved it into
.page-header - the INNER pages' heading - so it shrank to 2.1rem and the domain
badge was stranded beside it.
4. THE HERO PICTURE is the real dashboard in a laptop. The frame is the operator's own
supplied render; the screen is dashboard-start-{hu,en}.webp composited into it, so a
visitor sees a real box's Launcher rather than a drawing of one - the supplied
screens are AI-drawn and misspell app names. 57 KB, named dashboard-laptop-<lang>
so gate 19 holds it to the page's language.
5. .page-lede HAD NO CSS AT ALL on 16 pages: a bare paragraph, full width of the
content column, hard against the box beneath it. 760px measure, centred over the
box, air beneath; left-aligned on /szolgaltatasok, which has no centred box.
6. THE SIDEBAR LOGO: the wordmark shipped at 0.67x the mark's width where the real
lockup (assets/logo.png, measured: mark 492px wide, wordmark 631px) has it at 1.28x.
Mark 112px, wordmark 25px tall, 28px less vertical padding.
7. SCROLLBARS are the page's own now. The first attempt missed the viewport's: it is
painted from <html>, and a `body.shell ::-webkit-...` rule only reaches scrollers
inside the page.
Also: the two Latin font subsets are preloaded. With font-display: swap the page
reflowed after first paint - measured at 1339px on /alkalmazasok#media.
Checked at 390px and 1440px on all 21 pages: no sideways scrolling, footer inside the
content column everywhere, drawer opens with all 13 items. site.css?v=24.
|
||
|
|
a7480172ab |
gates: site gate 22 - the media-aware CSS leak check the phone bug needed
gates / gates (push) Failing after 12m29s
The two defects the operator found on his own phone are fixed and live since
5aeb36b5; this is what pins them so they cannot come back silently.
site_gates.py gate 22 parses site.css and shell.css into
(media context, selector, declarations) and fails on any property site.css
declares on a selector shell.css also styles that nothing overrides - neither
shell.css itself nor a `.shell ...`-scoped reset. site.css loads first, so
"later wins" is per PROPERTY, not per rule. Today: 689 site rules vs 119 shell
rules, 9 shared selectors, 0 leaks. .hamburger-box / .hamburger-line are an
explicit allow-list with the reason beside them.
It is media-aware precisely because the check it replaces was not. The STOP-1
leak diff excluded @media blocks and reported "exactly six" leaking
declarations; the real number is forty, and the worst of them
(@media (max-width: 900px) .nav-links { position: fixed; right: -100% })
parked the drawer's menu off-canvas and shipped.
Two decoys in test_gate_decoys.py, both the exact shape that went live, both
seen to convict:
site/shell-css-leak-in-media the body:not(.shell) scope taken back off that
one rule - the gate names the media query, the
selector and `right: -280px`
site/footer-outside-main <main> closed early on gyik.html - gate 3b's line
They plant and restore BYTES, with the anchor translated to the file's own line
ending: these files are CRLF in a Windows worktree and LF in a Linux one, and
replace_in's text-mode round trip would have rewritten a whole file on one side.
Also: CHANGELOG entries for both areas, the M3 report corrected where it quoted
its own wrong "exactly six", and one plain-language STATUS line.
|
||
|
|
5aeb36b5bd |
website: fix the phone menu and the footer column - both live defects
gates / gates (push) Successful in 6m42s
Reported from a real phone. Both were mine, both shipped in the switch. 1. THE PHONE MENU WAS EMPTY. The drawer slid open correctly but had no items in it. site.css's OLD mobile nav was still reaching the shell's sidebar: under @media (max-width: 900px) it sets .nav-links to position:fixed; right:-100%, which parked the menu off-canvas INSIDE the drawer. Measured at 390px and 860px: position fixed, right -280px. The cause is a hole in my own check. At STOP 1 I diffed the two stylesheets' declaration sets and found "exactly six" leaking declarations - but that diff EXCLUDED @media blocks. Re-run media-aware, the real number is FORTY, and the worst of them only apply below 900px, which is why desktop looked right and a phone did not. A check that silently skips part of its subject is not a check; this one reported a confident, wrong number. Fixed at the source rather than per-property: every selector belonging to the website's OLD chrome (nav, .nav-links*, .mobile-overlay, .hamburger, .logo*, .lang-globe-li - 29 occurrences) is now scoped `body:not(.shell)`. Scoped, not deleted, so a future non-shell page still works. .hamburger-box and .hamburger-line are deliberately left unscoped: the shell's burger uses them. Leaks after the fix: 40 -> 0. 2. THE FOOTER RENDERED AS A SECOND COLUMN at the top right on 16 pages. body is a flex row on a shell page, and my insert only moved the footer inside <main> when the page ENDED with </main>; pages with scripts after it fell through and left the footer as a direct child of body, i.e. a flex sibling of the sidebar. Moved inside <main> on all 16, each move asserted to have landed inside. Both are now gated: gate 3b requires every shell page's footer to be INSIDE <main class="content">, red-proofed by putting one outside and watching it convict. site.css?v=23 / shell.css?v=23. |
||
|
|
f92e81ee14 |
gates: re-anchor four site decoys to the shell markup
gates / gates (push) Successful in 6m33s
The decoys plant a known defect and assert the gate convicts, so when the markup
they anchor on changes they must be rebuilt rather than deleted - which is exactly
what test_gate_decoys.py refused to let pass ('the decoy's anchor is gone or
ambiguous').
en-nav-drift drifts a SIDEBAR entry now, and expects gate 3b's message
rather than gate 3's - the website's <nav> is gone
leftover-text-switch anchors on <details class=lang-globe>; the old nav's
<li class=lang-globe-li> wrapper no longer exists
lang-attr <html lang=en class=no-js>, the progressive-enhancement hook
ascii-hungarian-text anchors on the new English home's own link text; its old
'Contact form' link went when the page became a real twin
The other decoys in that section still anchor correctly and were left alone -
checked each one against the new files rather than rewriting the lot.
|
||
|
|
6059505216 |
website: M3 goes live - the whole site switches to the controller's shell at once
gates / gates (push) Failing after 13m11s
Part D. Every public page now wears the controller's frame around the website's
own content. One commit, as asked: never half old, half new.
20 pages switched (12 Hungarian incl. the hidden prices page, 8 English)
website/preview/ deleted entirely - A, M1, M2 and M3 studies all gone
robots.txt: the Disallow: /preview/ line removed with them
site.css?v=22 / shell.css?v=22 on every page
PROVED before pushing, not after:
* HEAD TAGS: title, meta description, keywords, author, robots, canonical, every
hreflang, all seven Open Graph tags, all four Twitter tags and the JSON-LD
captured on all 19 pages before the switch and compared after. The ONLY
difference anywhere is the dash substitution inside the two FAQ pages'
FAQPage JSON-LD - verified by applying the same substitution to the "before"
copy and getting an exact match. Nothing else moved.
* VISIBLE TEXT: identical to the live pages word for word, legal texts identical
with no substitution permitted at all.
* No page is left noindex (the two download pages' noindex,follow is their own,
pre-existing and unchanged), no page mentions /preview/, every page has a
footer, no page overflows at 390px.
THE HEAD-TAG DIFF EARNED ITS PLACE. The home page was about to ship carrying
`noindex, nofollow` from the preview, and had lost meta keywords, meta author, all
seven Open Graph tags, all four Twitter tags and the LocalBusiness JSON-LD -
because its head was hand-built while every other page carried its live one over.
The diff caught it; nothing on the rendered page would have. The generator now
uses the live head for EVERY page including the home one.
szolgaltatasok-nonpublic.html was converted too. It is in no menu and was not in
the brief's list, but leaving one page on the old chrome would have left the site
half-switched - which is the one thing part D was not allowed to do.
scripts/site_gates.py: SHELL is now the real page set; MOCKUPS is empty; gate 3's
old nav/footer loop keeps working for any page added later WITHOUT the shell, and
skips the ones that have it.
|
||
|
|
58e308352f |
website: the shell keeps the footer - it is the only route to the legal pages
gates / gates (push) Failing after 11m54s
Caught BEFORE the switch, not after. Stripping the website's chrome also stripped <footer>, and the shell has none of its own. Every one of the 19 pages had lost: the link to the Adatkezelesi tajekoztato and the Feltetelek, the operator's name, info@felhom.eu, and the copyright line. The legal pages are in no menu, so they would have become unreachable from navigation entirely. The footer is now carried VERBATIM from each live page into the bottom of the content column. Verified on all 19: footer present, legal link present, e-mail present, and the footer sits INSIDE <main class=content> rather than becoming a flex sibling of the sidebar. Gate 3b now checks the footer as well as the sidebar across the shell set, so the guarantee gate 3 used to give is not lost in the move. Red-proofed: removing one page's footer convicts. |
||
|
|
0b34be8449 |
website: M3 part C - all 18 remaining pages moved into the shell
gates / gates (push) Successful in 8m50s
Staged under /preview/m3/. Nothing live. 19 shell pages in total with the home.
Each page keeps its own <head> byte-for-byte apart from two additions (shell.css
and the no-js/js hook), so title, meta description, canonical, hreflang, Open Graph
and JSON-LD all survive the move untouched. The body loses the website's
<nav>/<footer> and the old hamburger script, and gains the shell.
PROVED, not assumed - a word-level diff of every page's visible text, live vs
shell, with the nav and footer removed from both:
* 18 of 18 pages: visible text IDENTICAL after the one allowed substitution
* adatkezeles and feltetelek: identical with NO substitution permitted at all.
The legal texts are reviewed documents; the frame changed, the words did not.
That check earned itself immediately. The first version of the page-header
transform rebuilt the block from its <h1> and first <p> and SILENTLY DROPPED the
rest: the "Fontos tudnivalok" / "Good to know" disclaimer banner on both apps
pages and the 404's English line - 168 words across three pages. Nothing looked
wrong on the page. The diff found it.
Em dashes: 318 replaced with the Hungarian gondolatjel across 16 pages (gyik and
en/faq 104 each). The FAQ pages' JSON-LD is swept with the SAME substitution, so
gate 17's equality with the visible answers still holds - it does, on both.
scripts/site_gates.py:
* SHELL now holds all 19 pages.
* is_en(): a page is English if it is a TWINS value OR lives under an en/
directory. Without the second half the dash-language, <html lang> and
no-Hungarian gates all judged preview/m3/en/* as Hungarian - 30 false fails.
* norm_block() also drops `is-open` and `aria-expanded`, because the shell
renders the nav group containing the active page open, exactly as the
controller does, and that legitimately differs per page.
The last change LOOSENS a check, so it was red-proofed BOTH ways: a one-character
difference in one menu label still convicts, and a state-only difference (the
active marker moving to another item) correctly does not.
One generator now owns the shell. The home page's content comes from m3.py and its
shell from the same function every other page uses, so the two cannot drift - which
they already had, and gate 3b caught it.
|
||
|
|
80659232bc |
website: M3 part A - the controller's shell, and the home page inside it
gates / gates (push) Successful in 6m58s
The direction the operator chose: the controller's FRAME around the website's own
content. Staged at /preview/m3/, noindex, nothing live.
website/assets/shell.css - 117 rules COPIED VERBATIM from felhom-controller
style.css @ dcd89364a4 (sidebar, mobile top bar, off-canvas drawer, and the
component atoms the restyled pages use: btn, alert, app-info-card, launch-*,
stack-detail-card, form-*). Exactly ONE rule is not verbatim and says so:
body.shell { display:flex; min-height:100vh }, which lives in the controller's
base rather than in a component, scoped to .shell so other pages are untouched.
The generator NAMES every rule it copies and REFUSES to write the file if one has
disappeared upstream. That is not ceremony: it already caught two things this
session. It refused because .sidebar::-webkit-scrollbar does not exist (only the
-track override does), and because prefers-reduced-motion is split across FIVE
separate blocks in the controller - reading only the first would have silently
lost four rules. The M1 round lost a rule exactly this way.
The bare `body { flex-direction: column }` that broke M1's phone layout is copied
this time, by name, as are body.nav-open and the no-js/js pair.
Load order is deliberate: shell.css AFTER site.css. Thirteen selectors exist in
both files with different meanings (.nav-links, .page-header, .lang-globe*, .ico)
- a horizontal site nav there, a vertical sidebar here. Later wins, and a page
that does not load shell.css is completely unaffected.
website/preview/m3/index.html - the home page in the shell. Content is /preview/'s
cleaned text; body carries `shell page-index` so the existing .page-index content
rules (caps, flow, vs, band, who-mini) are reused rather than duplicated. Six
sections, left-aligned headers, the controller's cards. Head tags (title, meta
description, canonical, hreflang) are already the FINAL values, so the switch in
part D needs no head edit.
Four changes from the operator's mockup, each with its reason in the generator:
1. the active item follows the page (the mockups show Inditopult active on all)
2. Teszteles is ALSO a primary button at the top of the lower group - it is the
one action we want and the mockup buries it at the bottom
3. the Alkalmazasok categories are anchors on /alkalmazasok: real URLs, no
JS-only state
4. ADDED GYIK. It is in today's nav; dropping it silently would take a page out
of navigation, which is not a change a restyle gets to make.
scripts/site_gates.py - gate 3 extended rather than duplicated, as asked: a SHELL
set whose pages must carry an IDENTICAL <nav class="sidebar"> after the active
marker is normalised. RED-PROOFED: a one-character change to one menu label on a
second shell page convicts. It also prints "DIFFER" rather than a reassuring
"identical" count when it fails - a false reassurance printed beside a conviction
is the exact defect this repo files rows about.
documentation/design/design-system.md - new "Shell" section: what is shared (tokens
+ shell + atoms), what each side owns, how a change flows (controller first, the
website's copy the same week), and that the cross-repo gate is deliberately NOT
built yet.
|
||
|
|
063ba83e41 |
website: two hidden mockups - M1 "the site is the dashboard", M2 hybrid
gates / gates (push) Failing after 7m1s
Design studies only. Nothing live changes, nothing is linked from a live page, both
carry noindex and /preview/ is already Disallow-ed in robots.txt. felhom-controller
was read ONLY (baseline dcd89364a4); nothing in it was touched.
M1 website/preview/m1/ - the website wearing the controller's shell
index (Indítópult) welcome card + all 58 launcher tiles
alkalmazasok the catalog in the site's own five buckets, vanilla search
mentesek the three backup levels, every number marked "minta"
hogyan / teszteles / kapcsolat today's copy inside the dashboard shell
M2 website/preview/m2/ - short hero beside a window holding a clickable launcher
Real data, not invented:
* 58 apps from app-catalog-felhom.eu @ 8ea72aa: real names, logos, Hungarian
taglines, use cases and first steps out of each .felhom.yml app_info.
* Tile colours reproduce the controller's OWN tileColor (funcmap.go): FNV-1a 32
of the slug -> hue, 45% 38%. No brand_color exists in the catalog, so every
tile here is the colour a real launcher would paint.
* Page copy is today's live website only.
* Category labels are the five buckets alkalmazasok.html already uses. None invented.
The 58 is now measured, not quoted: 60 templates minus plant-it (abandoned) and
wger (hidden) = 58 offered, which is exactly what the site's prose says. See the
R-929 note in the audit folder.
Mockup rules honoured:
* No value pretends to be live - every sample wears a "minta" badge.
* No control does nothing: the disabled sidebar entries (Tárhely, Megosztás,
Rendszermonitor, Beállítások) say "a saját dobozodon működik" rather than
404-ing, and the contact form's submit is disabled with the same kind of hint.
The consent text is the live one, unchanged.
* App panels open with :target, so they work with JavaScript switched OFF and
their text is real HTML a crawler can read - not JS-built content.
* No login form anywhere. No external request, no AI or stock image.
CSS: website/preview/mockup.css is three labelled blocks so the shared-design
report can count them - adapted base (font URLs repointed /static -> /assets),
188 rules copied VERBATIM from the controller, and the mockup-only rules. The
burger is the website's own three-span control, copied rather than hand-rolling an
SVG: the shared sprite carries no i-menu.
scripts/site_gates.py gains a MOCKUPS set, with the reasoning in a comment. The
mockups keep every correctness check (BOM, emoji, banned strings and CDN hosts, no
<style>, cache-busting, <html lang>, clean tail, dashboard-picture language, the
picture-viewer rules) and are excluded from exactly the three chrome-consistency
checks a dashboard-shell study must fail by construction: nav/footer identical to
index.html, the NO_TWIN language globe, and analytics - the last deliberately, so a
hidden mockup cannot pollute the real stats. Delete the set with the directories.
site_gates.py green.
|
||
|
|
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.
|
||
|
|
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. |
||
|
|
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.
|
||
|
|
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 |
||
|
|
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. |
||
|
|
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. |
||
|
|
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.
|
||
|
|
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.
|
||
|
|
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 |
||
|
|
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
|
||
|
|
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 |
||
|
|
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. |
||
|
|
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 |
||
|
|
97d3c29f9c |
facebook: Page details — categories added, hours and Messenger FAQ refused by Meta
gates / gates (push) Successful in 5m24s
Second Facebook task of the day. Page settings changed by hand in the operator's Chrome; every edit read back from a channel other than the one that made it, because Meta's toasts have lied here before (2026-10-08: "A modositas nincs mentve" arrived with a partial save). - Contact (B1) was ALREADY SET, by the operator, before this run: Graph reads emails ["info@felhom.eu"] and phone "+36702378499". Verified, not typed. - Place (B2) already city-only Budapest, as the operator chose. Service area REFUSED: Facebook offers the field but its picker has no "Magyarorszag", only cities. Control: "Szeged" returns Szeged. Left unset rather than narrowed to Budapest, which would shrink a coverage claim nobody authorised. - Categories (B3) DONE: Informatikai vallalat (kept first, the only one shown) + Internetes ceg + Szoftverceg. Facebook's Hungarian list has no IT-support, IT-consulting or cloud category; eleven terms searched, and the one true match is a repair counter, which the fences rule out. - Hours (B4) CANNOT be set and need not be: Facebook requires a street address first, which the fences forbid. Measured on the rendered page with controls present -- Zarva 0, Nyitva 0 while Budapest 1, Informatikai vallalat 1. The Page will never show "Zarva". - Messenger FAQ (B5) REFUSED -> R-920: the automation does not exist for this Page. Catalogue holds exactly three templates; search "kerdes" returns none while the control "uzenet" returns two. COPY.md section 5 is written anyway, questions verbatim from gyik.html and answers condensed from each question's own answer, and waits like section 2 does (R-917). - Link preview correct in both languages, re-scraped once each; only the expected fb:app_id warning, deliberately not fixed. Both report HTTP 206 where a plain curl gets 200 -- Facebook's scraper, preview complete. fb_probe.py read now also reports emails, phone, category_list, location, single_line_address and hours, ONE FIELD PER CALL: a batched fields= list fails whole when any member is unreadable, which would let one refused field hide the other five. Refusals are logged verbatim and never retried; "null" and "not returned" are logged apart. hours is never returned by Graph, which is why B4's read-back had to come from the rendered page. Also corrects the "Business & legal" header, which read 12 rows (P2 5) over a section holding 11 (P2 4); with R-920 it is 12 (P2 4, P3 1, P4 7). Only the section this commit edits -- the other drifting headers belong to a session that owns the register. No post, no invite, no money, no app or portfolio change, website unchanged. |
||
|
|
02a54e26f5 |
dooplex-offsite: failure mail survives the shared config's unset variable (found by the live dry run); Part B push + restore evidence
gates / gates (push) Successful in 5m6s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS |
||
|
|
1707c928a9 |
dooplex-offsite: nightly encrypted copy of Gitea + DooPlex secrets to ep0, restore test, failure mail (R-232 b/h)
gates / gates (push) Successful in 5m4s
Part A plan + readings, Part E read-backs (R-861 a, R-518) in audits/dooplex-survival-2026-10-09/. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS |
||
|
|
69fa9cf784 |
ep0-copy-gc: read ep0's real {"data": [...]} namespace answer; any other shape aborts (found on the first live dry run, guard held)
gates / gates (push) Successful in 4m31s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS |
||
|
|
e9e6300cfc |
Spike: Facebook Page reached after the operator's Page click; scheduled post + photo created, read back byte-equal, deleted
gates / gates (push) Successful in 4m35s
Read phase passes (Page 1360018983863273, CREATE_CONTENT/MODERATE/ANALYZE, page token PAGE expires_at 0, three insights metrics alive on v26.0). Write test: removal check accepts Meta's code-10 'Object does not exist' (fixed without a row, 4 tests); run 1 evidence kept. R-914 READY, R-915 narrowed to Live mode. |
||
|
|
ff276ed7d9 |
Spike: Facebook Page access probe — key valid and non-expiring, reaches no Page (R-914, R-915 opened)
gates / gates (push) Successful in 4m34s
scripts/facebook/fb_probe.py (stdlib, read + write-test, no real-post command) with tests; read run twice: SYSTEM_USER, expires_at 0, /me/accounts empty, so D/E did not run and nothing was posted. Findings, redacted evidence, CONTEXT decision home, STATUS item, scripts CHANGELOG, REPORT-facebook-page-api.md. |
||
|
|
fe0dc0d03f |
Decision sheet D1-D10: hub CHANGELOG, architecture notes (01, 04, 05, 07, 08, 10), register (VERIFY states, R-912), STATUS, report; decoy suite runs in a git worktree
gates / gates (push) Successful in 4m32s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS |
||
|
|
87af859fc3 |
hub: operator actions for a box (D1, R-314/R-279/R-177, decision 185)
Host page "Operator Actions" card: run off-site backup now, run a check now
(fixed job list), stop / extend (1-30 days) a deletion countdown. POST
/hosts/{id}/operator-action validates against the CLOSED list before
storing (unknown -> 400, no row), stores operator_actions(id, customer_id,
action, arg, requested_at, requested_by, done_at, outcome, message), logs
who pressed (channel + address) and bumps the box's intent. The report ACK
lists pending rows as operator_actions until the box's
operator_action_results closes them (matched on id AND reporting
customer); each closed row becomes a hub-minted operator_action event
(stored, never dispatched). Unanswered after 24 h: expired. A customer
RESET cancels pending rows. Wire gate: new root + field-by-field mirror
(controller report.OperatorAction) — needs the controller commit first.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
|
||
|
|
42519a776a |
gallery.js v2: when the last 'next' turns off, focus moves to the close button instead of the page behind (seen in the live check)
gates / gates (push) Successful in 4m29s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb |
||
|
|
79c53b5f1a |
website: one picture viewer (assets/gallery.js) for app and dashboard pictures — declared data-gallery sets, a click on the big picture closes, JS-off still opens the file; site gate 20 + 4 decoys; demo-hp language read back (hu); R-908 (old Resend key in homelab-manifests history); 131 -> 132
gates / gates (push) Successful in 4m25s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb |
||
|
|
aaac24b05c |
website: the dashboard shown — 4 real screenshots per language on the home page, 2 on the technology page (controller 0.303.0, demo-hp household guest, privacy-scanned); site gate 19 (pictures in the page's language) + decoy; R-906, R-907 (dashboard defects seen); 129 -> 131
gates / gates (push) Successful in 4m12s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb |
||
|
|
0b6758d440 |
R-902 search: contact-mailer source NOT FOUND (DooPlex disks, web editor + history, 10 Gitea repos, build cache); binary kept in git; replacement plan; decoy suite takes a lock (two sessions' runs left a decoy planted)
gates / gates (push) Failing after 11m42s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb |
||
|
|
83e6167145 |
ep0-copy-gc: fail-safe guards (partial ep0 list aborts, one deletion per run, HOLD file) — from the commit security review; still not installed
gates / gates (push) Successful in 4m0s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS |
||
|
|
05becb04d0 |
R-901: a deleted customer's audit rows go 1 year after the deletion (hub, unreleased); ep0-copy removal job written, not installed (decision 181); both times in the privacy draft
gates / gates (push) Successful in 4m9s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS |
||
|
|
aa843a2fa0 |
decoy suite: fake register ids R-903..907 -> R-99903..99907 (the real register reached R-903; the hook refused the push)
gates / gates (push) Successful in 3m55s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb |
||
|
|
803af4798d |
website: the language switch becomes a globe like the dashboard's (Magyar / English list, current marked, no JS); site.css v3; gate 13 checks the globe from one LANGS list; 5 decoys
gates / gates (push) Successful in 3m54s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb |
||
|
|
67b3fd23d1 |
website refresh: true numbers (56 apps), claims checked against the capability map, ten missing apps, an English twin of every public page (public, choice B), 404 page; site gates 13-18 + 11 decoys; R-902 opened
gates / gates (push) Failing after 13m1s
Part A: claim table documentation/audits/website-refresh-2026-10-08/claims.md; "100% open source" corrected from the licence read; unbacked claims cut (firewall, RAID, snapshots, new-machine restore, self-managed mode, household VPN, "never lost"). Part B: dawarich, docmost, grimmory, homebox, karakeep, mealie, metube, radicale, recipe-importer, sparkyfitness cards; plant-it and wger cut (not offered). Part C: /en/ twins, nav language switch, hreflang both ways, sitemap with xhtml:link, og-image-en.png. Part D: site_gates.py twins/lang/same-apps/no-Hungarian/FAQ-JSON-LD/tail. Operator ruling 9 + choice B in 10-localisation.md §11, §10.7. Register: R-902 (contact mailer source in no repo); R-813, R-784, R-559 annotated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb |
||
|
|
ab3b7ea2f4 |
hub v0.143.0 (code): the kernel lane — the day-before household mail, the night instruction, the operator's kernel set (R-836, decision 172)
gates / gates (push) Successful in 2m47s
KernelDue / KernelNotify (09-20 h Budapest, one per 20 h, max 3, registered
address, only an accepted mail counts) / os_update.kernel {kver, tonight}
(no mail, no step) / layer kernel ingest + operator events / Approve kernel
set after every ring-0 box booted it healthily after a night stage / two
System page cells. 11 §5.11 written; §5.10 status corrected (proven).
Installer uninstall knows the two GRUB generators (unreleased).
Evidence: audits/kernel-lane-2026-10-07/ (red-proofs, boot timing).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
|
||
|
|
f5400268a7 |
CHANGELOG: R-444 hub half (unreleased), R-502 full-run gate
gates / gates (push) Successful in 2m41s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS |
||
|
|
a411cde7c4 |
R-444: hub half — the System page shows each box's last disk trim
sysfacts reads the agent's top-level guest_disk_trim stanza (schedule + per-guest last attempt: vmid, last_attempt_at, ok, bytes_trimmed, mounts, duration_seconds, last_ok_at, error) into a field-by-field mirror. The System page's new 'Last disk trim' column shows the last successful trim and the GiB it freed; amber when the newest attempt failed (error shown) or last_ok_at is older than 14 days (judged on the success time, never the attempt time); '—' when the agent sends no stanza. wire_contract_gate: SUBTREE_MIRRORS checks guest_disk_trim field by field BOTH ways against sysfacts.DiskTrim; decoys (ok renamed, last_ok_at dropped) in test_gate_decoys.py. Decision 139. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS |