Skip to content

P9a-5b: the legal pages go live from the platform #290

Closed

Description

@FlexOr2

Parent: #173

P9a-5b: the legal pages go live from the platform

Caller: #173, slice row P9a-5: "The tunnel line and hal's apex move, his sentence stands, hal's exit is named, the live body equals built/, and an item on marketplace's board drops the legal-texts skill's sentence that hal still assembles and serves the pages (marketplace#561's follow-up)." After P9a-5a, which makes platform's copy hold every sentence hal serves and the ruled 30-day sentence, and the sections' owner.

Ruled

How the go works (hal at origin/main e9cfd360)

  • The edge stays hal's. Cloudflare's redirect ruleset (external/cloudflare.tf:278-342, fleet.yaml:3-8) answers every request to hallucinai.de and www at the edge, before any tunnel: the four pages and /_rechtliches/… pass to the origin, every other form of a page goes 302 to its exact path, and everything else, / included, goes 302 to https://auth.hallucinai.de/. Moving the record changes none of that. So no path hal serves at the apex stops answering: hal's nginx (legal/nginx/default.conf) answers exactly the five paths platform's Ingress routes, try_files $uri.html for the pages and /favicon.ico (404, as platform's), and alias for /_rechtliches/. One unverified difference: a file in hal's git-ignored legal/assets/ on the PC beyond platform's assets/ (an older appkit-<version>/) stops answering; the committed pages link only appkit-0.15.0 and legal-2.css, and Cache-Control: no-cache makes a cached page ask again.
  • The record moves by one catalog key. tunnel: platform on the legal entry's "@" host (fleet.yaml:43): catalog.py's _tunnel accepts it (only target and the wildcard are refused), external/cloudflare.tf:17-22 points the apex's proxied CNAME at the tunnel platform, external/tunnel.tf drops the apex's line from hal's ingress, the publish phase skips ready for a host on another tunnel, and www keeps hal's tunnel record (a redirect-only name), which never reaches an origin. cloudflare.redirect.serve needs the apex as an enabled host, so the legal entry stays enabled: hal's legal unit keeps running and serving nothing, the rollback target until P11. This is hal#1100's and hal#1148's mechanism; hal's freeze admits it.

What it builds

  1. The tunnel line. infrastructure/cloudflared/cloudflared.yaml gains - hostname: hallucinai.de to http://traefik.traefik.svc.cluster.local:80, before the final http_status:404, without a path: the edge and the Ingress each already admit only the five paths. checksum/config follows, computed as tests/cloudflared/ingress_from_pods_built_from_its_template.sh does.
  2. The cloudflared cell. For a line without a path, the cell today asks / and, for a host an Ingress routes, fails on 404 (:92, :115, :123-126); the apex's Ingress routes no /. The cell asks such a host on the first path of its Ingress rule instead of /; hopin and skat route / and stay as they are.
  3. The comment at infrastructure/legal/legal.yaml:104-106 drops "and no tunnel line sends the host here yet".
  4. The hal script's end. tests/legal/legal_sections_assets_and_headers_equal_hals_at_commit.sh loses the stylesheet and header comparisons, hal_commit and hal's fetch, since hal serves nothing after the go and platform's copies are the owners. The appkit check stays with its own pin: the wheel's URL and sha256 (today hal's pin, v0.15.0, 710bed31…) move into the script, renamed tests/legal/appkit_assets_equal_their_release_wheel.sh; it still fails when assets/appkit-<version>/ differs from the wheel's appkit/static/ or assets/ holds anything else. Weighed: deleting it, which drops the only proof that ten vendored files equal a release, or keeping hal's pin, which keeps a predecessor as a source of truth.
  5. AGENTS.md is not changed (the operator, 09.11.2026, platform carries the fleet document set: AGENTS.md within its budget, an architecture overview and runbooks #134 comment 6738858275: no lane changes it). The head names on platform carries the fleet document set: AGENTS.md within its budget, an architecture overview and runbooks #134 the sentences this makes false: "No tunnel line names the host, so hal keeps the public address." (P0 class R, destination item: Platform on k3s and Flux: from an empty PC to every app live, with hal archived #1 card line 1, which the 08.11.2026 ruling replaces for these pages; the ruling stands in P9: legal pages, person export and erasure, AI keys and expiry checks move from hal #173's body), and the assets/ sentence ending "until hal no longer serves the apex" (class D); the hal script's clause if P9a-5a left one.
  6. docs/personal-data.md: the "The promise:" lists gain allgemein#server-protokolle, so a lane changing retention finds the one general promise (the gate of The speech section takes hal's last ruled sentence; platform owns the legal sections #324, F3).

Size: three production files (cloudflared.yaml, legal.yaml's comment, ci.yml's step), about 6 changed lines, plus the two test scripts and docs/personal-data.md.

The live go, in order

# Step Who
1 This slice lands; on the PC a delegated agent, through k3s's own kubeconfig, sees tunnel and legal Ready at the landed revision and the cloudflared pod rolled to the new checksum/config; a throwaway client Pod in cloudflared gets 200 from Traefik with Host hallucinai.de for the three pages, each body's sha256 equal to built/ at the landed main, and records the in-cluster ETag of /datenschutz; the Pod is deleted on exit. Until hal moves the record, the line serves nothing. agent
2 hal's commit: tunnel: platform on services.legal.hosts[0] in fleet.yaml, and its docs' sentences that say hal serves the apex. hal's head
3 The operator's apply, below. If hal#1148's checkout of ~/srv/skat has not run, its block from hal#1148's pull request comes first, since every hal apply refuses without it; the apply also waits for speech-runtime's GPU test, as hal#1148 and hal#1168 do. operator
4 The live check, below. agent; hal check hosts hal's head
5 Open the cross-repository items below. head

The operator's block (he answers yes at the plan, which shows the apex record moving to the tunnel platform and hal's apex line leaving hal's ingress):

cd ~/srv/hal && hal update && hal apply

Rollback: hal's head reverts step 2; the operator runs the same block. The record returns to hal's tunnel and hal's still-running legal unit answers, with the text of hal's last apply. platform's tunnel line stays and serves nothing. hal's frozen legal/sections/allgemein has no server-logs section, so after a rollback the public page lacks the ruled 30-day log sentence until the record returns to the platform (the gate of overnightworks/hal#1199).

Proof

CI. cluster, part core: the cloudflared cell finds the apex's line pointing at Traefik's web and a client Pod in cloudflared reaching the route with nginx's answer, checksum/config matches, hopin's and skat's lines unchanged; the five-paths cell unchanged (three pages and every asset with the committed checksums, nginx's headers, Traefik's 404 for /). checks: the appkit script with its own pin.

Live, after step 3, from outside, by a delegated agent with curl, at the landed main:

  • curl -fsS https://hallucinai.de/<page> | sha256sum equals sha256sum infrastructure/legal/built/<page>.html for impressum, datenschutz and nutzungsbedingungen;
  • the outside ETag of /datenschutz (a W/ prefix ignored) equals the in-cluster one of step 1, so the platform served it, not hal;
  • every /_rechtliches/… the pages reference answers 200 with the committed file's sha256;
  • each answer carries default.conf's four headers, no nel, report-to or reporting-endpoints header; no body holds /cdn-cgi/, __cf_email__, data-cfemail, email-decode or challenge-platform, and legal@hallucinai.de stands literally (hal#110 C2-C4);
  • the edge is unchanged: / and /foo give 302 to https://auth.hallucinai.de/, /impressum/ and https://www.hallucinai.de/impressum give 302 to https://hallucinai.de/impressum, /favicon.ico gives 404;
  • each page's answer carries strict-transport-security exactly once: Cloudflare's zone adds it and neither nginx's default.conf nor Traefik adds a second (required by hal's docs/external.md; asked by hal's head for The platform serves the legal pages at the apex hal#1199);
  • a browser at 390 and 1440 px opens /datenschutz, requests hallucinai.de only and reports no CSP violation (hal#110 C5);
  • hal check hosts exits 0 (hal's head).

Trace (main 0bf0c46; hal origin/main e9cfd360)

  • infrastructure/cloudflared/cloudflared.yaml:10-15 (lines), :37 (checksum/config).
  • tests/cloudflared/ingress_from_pods_built_from_its_template.sh:85-131.
  • infrastructure/legal/legal.yaml:104-106 (comment), :108-150 (Ingress, five paths).
  • tests/legal/legal_sections_assets_and_headers_equal_hals_at_commit.sh:23-31 (stylesheet, headers), :33-56 (wheel); .github/workflows/ci.yml:72-73, :336-338, :496-503.
  • AGENTS.md:692-696 (D), :703 (R row of P0 part c, base line 700).
  • hal: fleet.yaml:3-8,39-43; src/hal/stack/catalog.py:501-513 (_tunnel), :583-598 (_check_serve); external/cloudflare.tf:17-22,153-162,278-342; external/tunnel.tf:7-10; legal/nginx/default.conf; hal#1148's trace (the publish phase skips ready on another tunnel).

Risk

Material: a public legal page and a public route. Opus review at high and a cross-provider final gate. The first review drives:

# Sentence Cell Driven by
1 The apex's line points at Traefik's web and rolls cloudflared cloudflared cell, checksum/config CI, PC step 1
2 A line without a path is judged on a path its Ingress routes; hopin and skat unchanged cloudflared cell CI
3 Only the five paths reach nginx; everything else gets Traefik's 404 five-paths cell CI
4 The live body equals built/ for each page curl and sha256 live
5 The platform serves the apex, not hal ETag outside equals in-cluster live
6 Every referenced asset answers with the committed bytes curl per asset live
7 Headers, no injected script, literal address hal#110 C2-C4 live
8 The addresses never redirect; the edge's redirects are unchanged curl of /, /foo, /impressum/, www live
9 No request leaves hallucinai.de, no CSP violation, at 390 and 1440 px browser live
10 The rollback restores hal's answer review of hal's revert path; not driven review
11 The appkit files equal the pinned wheel, and nothing reads hal appkit script CI

Deliberately untouched

Cross-repository items, opened at step 5

  • hal, owner hal's head (hal-af): "hal's apex host names tunnel: platform, hal's legal/ takes no further change (a change of a shared section goes to platform, hal#1154 moves to platform's board), and hal's legal unit, legal and appkit steps and hal legal leave with hal's archive in P11, the unit staying the rollback target until then." Step 2's commit is its first part; hal#110 names platform for what remains. The item also moves the pointer in hal's docs/keycloak.md that calls hal's legal/sections/allgemein/nutzungsbedingungen.html "the central terms page" (the gate of The platform serves the legal pages at the apex hal#1199).
  • songmaker, owner songmaker's head: "songmaker's privacy part refers to the general part's 30-day period for its server logs instead of stating size rotation and no fixed maximum, and the vendored ACE-Step fork writes no log file that outlives 30 days." It is songmaker#1714 finding 6 with a pointer to this item; the wording is the operator's yes in songmaker's repository. Its Audit-Log: wird derzeit ohne feste Frist gespeichert beside the general part's 30-day sentence needs the same owner's decision (the gate of The speech section takes hal's last ruled sentence; platform owns the legal sections #324, F2).
  • presentator, owner presentator's head: "presentator's privacy part refers to the general part's 30-day period for its server logs instead of „Eine Aufbewahrungsdauer ist nicht festgelegt“." Its wording is the operator's yes in presentator's repository.
  • marketplace, owner marketplace's head: "The legal-texts skill names platform as the owner that assembles and serves the pages and holds the shared sections, and drops the sentence that hal still does until platform's assembler lands." (plugins/atelier/skills/legal-texts/SKILL.md:21-24, marketplace#561's follow-up.)

Done when

hallucinai.de's three pages are served through platform's tunnel line, with each live body equal to built/ at main and the platform's ETag; the edge's redirects are unchanged; the hal script no longer reads hal; the head has named on #134 the sentences of AGENTS.md this makes false; and the four cross-repository items are open with their owners, hal's naming its exit in P11.

version = 1
now = "Cut from #173 on 09.11.2026 as the second half of P9a-5; hal's catalog mechanism for another tunnel (hal#1100, hal#1148) carries the apex unchanged."
next = "The tunnel line, the cell and the script's end have landed (#333, ab4d602) and step 1 of the live go passed at 7ba3a15: hal's head's commit (overnightworks/hal#1199), then the operator's hal update && hal apply, the live check and the four items."
done_when = "hallucinai.de's three pages are served through platform's tunnel line, each live body equal to built/ at main with the platform's ETag; the edge's redirects are unchanged; the hal script no longer reads hal; the head has named on #134 the sentences of AGENTS.md this makes false; the hal, songmaker, presentator and marketplace items are open, hal's naming its exit in P11."

scope = [".github/workflows/ci.yml", "docs/personal-data.md", "infrastructure/cloudflared/cloudflared.yaml", "infrastructure/legal/legal.yaml", "tests/cloudflared/ingress_from_pods_built_from_its_template.sh", "tests/legal/appkit_assets_equal_their_release_wheel.sh", "tests/legal/legal_sections_assets_and_headers_equal_hals_at_commit.sh"]

whole = "One public route: the tunnel line, the cell that judges it, and the end of the hal comparison land together, and the live go after them is one hal commit and one apply."

size = "S"

Activity

  1. added theissue type on Nov 9, 2026
  2. FlexOr2 commented on Nov 9, 2026

    @FlexOr2
    MemberAuthor

    Landed in #333 as ab4d602. Reopened: its Done when also needs the live go (the tunnel line on the PC, hal's catalog flip and the live check).

  3. reopened this on Nov 9, 2026
  4. FlexOr2 commented on Nov 9, 2026

    @FlexOr2
    MemberAuthor

    Landed code: #333 (ab4d602). Freed #325 (dispatched, its blocker on this item dropped since it needed only the code) and #277 (deferred until this goes live).

  5. FlexOr2 commented on Nov 9, 2026

    @FlexOr2
    MemberAuthor

    Live go, step 1 held on the PC at R = 7ba3a15 (a descendant of ab4d602):

    • tunnel and legal Ready (ReconciliationSucceeded) at R, no reconcile by hand.
    • cloudflared's pod cloudflared-65b5f48ff8-c9cxj Ready since 19:37:35Z; checksum/config 523b0e28…49a9 equals the sha256 of config.yaml at R and of the live ConfigMap.
    • From a throwaway Pod in cloudflared (deleted on exit), GET through Traefik's web with Host: hallucinai.de: impressum, datenschutz, nutzungsbedingungen each 200 at the first try, each body's sha256 equal to built/<page>.html at R.
    • In-cluster ETag of /datenschutz: "6af20540-1315f".

    Note for step 4: #344 (design v0.18.0, #325) changes the built pages' asset paths; if it lands before the live check, the check compares with built/ at the then-current main and takes the ETag anew in-cluster.

    Next: step 2, hal's head's commit (tunnel: platform on services.legal.hosts[0] in fleet.yaml).

  6. FlexOr2 commented on Nov 9, 2026

    @FlexOr2
    MemberAuthor

    Step 2 is overnightworks/hal#1199 (hal's head, build running; review Opus high, gate Opus xhigh). Step 3's preconditions per hal's head: hal#1148's ~/srv/skat checkout has run, speech's GPU window is done; the apply also carries hal#1193 step 1. hal check hosts in step 4 is the operator's. Next: hal#1199 on hal's main, then the operator's block.

  7. FlexOr2 commented on Nov 9, 2026

    @FlexOr2
    MemberAuthor

    Step 1 re-run at bb9e579 (R, main) after #344 (a1da90f) changed the built pages.

    • Kustomizations tunnel and legal: lastAppliedRevision main@sha1:bb9e579..., Ready True both. a1da90f is an ancestor of R.
    • Deployment legal: rolled out, pod legal-66b8ff89c5-9dbn8, 1/1 Ready, started 2026-11-09T20:14:57Z.
    • Deployment cloudflared: checksum/config = 523b0e2806a230f2ccd169f28126505606d4f2110bccb04acb2e7aad300449a9 = sha256 of config.yaml at R (also equals the live ConfigMap's); pod cloudflared-65b5f48ff8-c9cxj Ready.
    • Client Pods in cloudflared (curl image of CLIENT_IMAGE, restricted context), GET http://traefik.traefik.svc/, Host hallucinai.de, status 200 each; served sha256 equals built/<page>.html at R:
      • impressum: equal, 89f73f1ca0050423c28e79b037a3af10814ca739318f12ed2cceeea16ccce1d8, ETag "6af229c1-5f5"
      • datenschutz: equal, 10fd1d18176b8984c2558d745c9ad604c18f9f385c3cc8c274527b92c4ddf849, ETag "6af229c1-1315f"
      • nutzungsbedingungen: equal, 885f4b635615f9c1ce2585c37b6aedb577def72a63b7fe46698afbe7c332ed3f, ETag "6af229c1-2e73"
    • /datenschutz response header names: Accept-Ranges, Cache-Control, Content-Length, Content-Security-Policy, Content-Type, Date, Etag, Last-Modified, Referrer-Policy, Server, X-Content-Type-Options. Strict-Transport-Security absent.
    • The three Pods are deleted (NotFound afterwards).
  8. FlexOr2 commented on Nov 9, 2026

    @FlexOr2
    MemberAuthor

    Step 4, the outside check, at 21:16 UTC on 09.11.2026 (origin/main's built files hash as in step 1, so main did not move for them). The earlier empty-body 404s were observed between about 21:10 and 21:12 UTC, before this check.

    1. Held: bodies of /impressum, /datenschutz, /nutzungsbedingungen have sha256 89f73f1c...ce1d8, 10fd1d18...df849, 885f4b63...ed3f, each equal to the built file.
    2. Held: outside ETags "6af229c1-5f5", "6af229c1-1315f", "6af229c1-2e73" equal step 1's (no W/ prefix), so the platform served them.
    3. Held: 10 asset URLs (legal-2.css, design.css, 8 fonts the stylesheet's url() names, which include the 4 the pages link) answer 200, each sha256 equal to the committed file.
    4. Held with one note: all 13 answers carry Content-Security-Policy, X-Content-Type-Options and Referrer-Policy with default.conf's values; the 3 pages carry Cache-Control "no-cache, no-transform". The 10 assets carry "max-age=14400, no-transform" instead (Cloudflare edge rewrites static files; nginx sets no-cache). No nel, report-to or reporting-endpoints header; no body holds /cdn-cgi/, cf_email, data-cfemail, email-decode or challenge-platform; legal@hallucinai.de stands literally (1, 5, 1 occurrences, equal to the built files).
    5. Held: / 302 -> https://auth.hallucinai.de/; /foo 302 -> https://auth.hallucinai.de/; /impressum/ 302 -> https://hallucinai.de/impressum; https://www.hallucinai.de/impressum 302 -> https://hallucinai.de/impressum; /favicon.ico 404.
    6. Held: strict-transport-security appears once on each of the 3 pages (max-age=31536000; includeSubDomains; preload).
    7. Held: 30 plain requests over about 70 s: 30 x 200, 0 x 404; 3 x --http1.1: 3 x 200; 3 with a cache-busting query: 3 x 200; sizes constant (1525, 78175, 11891 bytes).
    8. Held: headless Chromium (Playwright, installed headless shell) at 390 and 1440 px opened /datenschutz (200): 7 requests, all to hallucinai.de; 0 console messages, 0 page errors, 0 failed requests, 0 securitypolicyviolation events. Screenshots in the session scratch directory.
    9. hal check hosts: not mine (hal's head).
  9. FlexOr2 commented on Nov 9, 2026

    @FlexOr2
    MemberAuthor

    Journal, 09.11.2026, after step 4:

    • hal check hosts, run by the operator: no findings (7 hosts) (hal's head; The platform serves the legal pages at the apex hal#1199 is closed with it).
    • The assets' Cache-Control: max-age=14400 at the edge is the zone's default browser cache TTL, which overrides nginx's no-cache on static file types; it was the same on hal, and hal's head keeps the zone as it is. The rule that makes it harmless holds on the platform now: a changed stylesheet takes a new name (legal-1 became legal-2), and the design files carry their version in the path. The pages themselves are never cached.
    • The window of empty-body 404s (about 21:10 to 21:12 UTC) lay between hal's apply dropping its apex line and the record's move reaching the edge; nothing on the platform changed in it.
  10. FlexOr2 commented on Nov 9, 2026

    @FlexOr2
    MemberAuthor

    Done when is met. The slice landed as PR #333 (ab4d602); the live go ran on 09.11.2026: hal's commit overnightworks/hal#1199 (b08960ed), the operator's hal update && hal apply, the outside check (comment 6751670562: every line held) and hal check hosts with no findings. The sentences of AGENTS.md this makes false are named on #134. The four cross-repository items are open with their owners: overnightworks/hal#1202 (hal's legal unit, steps and hal legal leave with the archive in P11; the unit stays the rollback target), overnightworks/songmaker#1714 (finding 6, sharpened in comment 6751744517, with the open Audit-Log line), overnightworks/presentator#988 and overnightworks/marketplace#575.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions