<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>cat/goq</title>
<subtitle>turns a linux box into a private steam streaming appliance: plug in, tap your key, play from another computer</subtitle>
<id>https://src.rest/cat/goq/</id>
<link href="https://src.rest/cat/goq/"/>
<updated>2026-10-17T17:17:02-06:00</updated><entry>
<id>999923be4117e5a43f54e1e3d274e6eb6532b79c</id>
<title>build(website): deploy goq.sh to src.rest pages as well</title>
<link href="https://src.rest/cat/goq/commit/999923be4117e5a43f54e1e3d274e6eb6532b79c/"/>
<author><name>cat</name></author>
<updated>2026-10-17T17:17:02-06:00</updated>
<content type="text">.forge/sites declares the site so forge site deploy publishes website/ to
https://pages.src.rest/sites/cat/goq/site/. The build step is the static-site
gate, scripts/verify-website.sh, the same check website.yml runs before the
Cloudflare deploy. The page links its stylesheet, script and release manifest
relatively, so it works under that path with no changes.</content>
</entry>
<entry>
<id>36df5982091d9c182144d24dd590207dc16711ee</id>
<title>ci: the complete gate runs on your machine for src.rest</title>
<link href="https://src.rest/cat/goq/commit/36df5982091d9c182144d24dd590207dc16711ee/"/>
<author><name>cat</name></author>
<updated>2026-10-17T17:17:02-06:00</updated>
<content type="text">forge attest runs .forge/ci in a clean worktree of each commit and signs the
result into refs/notes/ci; forge push sends it with the branch. It runs what
ci.yml&#39;s legs run: scripts/verify-demo-build.sh with every stage, the
website gate, and the Decky plugin gate with the pinned pnpm 9.4.0.

Cargo&#39;s target directory lives in ~/.cache/goq/target, outside the worktree,
so runs don&#39;t rebuild every dependency from source. target/ in the worktree
links to it, because the shell tests read target/debug/sigil directly.

forge resets its CI worktree with git clean, which removes the portal-dist/
that src-tauri/build.rs generates while tracked files keep their mtimes, so
with a warm target directory cargo would skip that build script and
tauri::generate_context! would find no frontendDist. .forge/ci touches
portal/runtime-files.txt so the script always runs.</content>
</entry>
<entry>
<id>69f58398b0d7f3657d82e4c5d7e6e16cce452142</id>
<title>Merge pull request #144 from FelineStateMachine/fix/hero-release-note</title>
<link href="https://src.rest/cat/goq/commit/69f58398b0d7f3657d82e4c5d7e6e16cce452142/"/>
<author><name>FelineStateMachine</name></author>
<updated>2026-07-25T19:13:37-06:00</updated>
<content type="text">fix(website): the hero shows a download button and a link, nothing else</content>
</entry>
<entry>
<id>95470b2ccdcf8092a3f7089189624854b554cf1f</id>
<title>fix(website): the hero shows a download button and a link, nothing else</title>
<link href="https://src.rest/cat/goq/commit/95470b2ccdcf8092a3f7089189624854b554cf1f/"/>
<author><name>Dami</name></author>
<updated>2026-07-25T19:13:21-06:00</updated>
<content type="text">The release note under the download had grown into a paragraph: version,
platform, the Gatekeeper explanation, and an instruction to verify the SHA-256 —
all of it repeating what the button already says or what belongs on the release
page. The unavailable states were no better, explaining which platform comes
first. A landing page hero is not the place for it.

Both notes are now just &quot;release history&quot;.

Removing the only reader of `#portal-release-status` made three things dead:
that element, `portalManifestReason`, and `portalManifestStatus`. They are gone
rather than left assigned and never read. `build.note` goes with them.

This also removes the element whose absence used to freeze the download button,
since `updatePortalDownload` no longer looks it up at all.</content>
</entry>
<entry>
<id>7ad5cad3939a1ec21c43915db3a28cb8e1aa4cb1</id>
<title>Merge pull request #143 from FelineStateMachine/release/enable-portal-download</title>
<link href="https://src.rest/cat/goq/commit/7ad5cad3939a1ec21c43915db3a28cb8e1aa4cb1/"/>
<author><name>FelineStateMachine</name></author>
<updated>2026-07-25T19:06:28-06:00</updated>
<content type="text">release: enable the Portal download for v0.1.1</content>
</entry>
<entry>
<id>1de232333c472857cef5e848056bcc10203ea24a</id>
<title>release: enable the Portal download for v0.1.1</title>
<link href="https://src.rest/cat/goq/commit/1de232333c472857cef5e848056bcc10203ea24a/"/>
<author><name>Dami</name></author>
<updated>2026-07-25T19:06:14-06:00</updated>
<content type="text">Flips website/portal-release.json to the published v0.1.1 build, which is what
takes goq.sh&#39;s download button out of its disabled state.

The runbook asks for the artifact to be verified before this flip rather than
after, so the bytes were checked as a stranger receives them: SHA-256 recomputed
against the published checksum, `gh attestation verify` clean, and the app
inside the mounted DMG reports Signature=adhoc with identifier sh.goq.portal.
`spctl --assess` rejects it, which is the documented and expected result for an
ad-hoc build that is deliberately not notarized.

The Sigil install note also stops calling the signed channel pending, since
v0.1.1 published it and install-sigil now pins that tag.</content>
</entry>
<entry>
<id>6b547ee1bdfe9bf4c78f68d4c2ff432bedbf9176</id>
<title>Merge pull request #142 from FelineStateMachine/release/v0.1.1</title>
<link href="https://src.rest/cat/goq/commit/6b547ee1bdfe9bf4c78f68d4c2ff432bedbf9176/"/>
<author><name>FelineStateMachine</name></author>
<updated>2026-07-25T19:04:36-06:00</updated>
<content type="text">release: v0.1.1</content>
</entry>
<entry>
<id>d52cfbb32e6a0f867b336f4b0f4325719692882b</id>
<title>release: bump the Tauri bundle version to 0.1.1</title>
<link href="https://src.rest/cat/goq/commit/d52cfbb32e6a0f867b336f4b0f4325719692882b/"/>
<author><name>Dami</name></author>
<updated>2026-07-25T17:39:17-06:00</updated>
<content type="text">verify-portal-release.py requires tauri.conf.json&#39;s version to equal the release
tag. It carries its own version field rather than inheriting from Cargo.toml, so
the v0.1.1 bump missed it and the Portal release policy job refused the tag.</content>
</entry>
<entry>
<id>70624d07885df3b90d70152910d8b2b1058bd368</id>
<title>release: v0.1.1</title>
<link href="https://src.rest/cat/goq/commit/70624d07885df3b90d70152910d8b2b1058bd368/"/>
<author><name>Dami</name></author>
<updated>2026-07-25T17:05:55-06:00</updated>
<content type="text">Ships the two fixes that made a real session usable, both found by running the
published v0.1.0 against live hardware rather than through the proof harness.

Control v2 rejected the host&#39;s first input acknowledgement and tore the session
down, so clicking to control always disconnected. Shadow-mode adaptive then
detached the viewer for failing to recover from a reduction it had never been
allowed to apply, which ended sessions ~25 seconds in on the configuration the
activation guide writes.

`website/install-sigil` pins one immutable tag, so the bootstrap moves to
v0.1.1 in the same commit as the crate versions. The Bazzite product contract
test asserts tag and version agree; its fixture and its deliberate mismatch case
move with them.</content>
</entry>
<entry>
<id>ad308aae214cc4e7b93bc76a75273bec36a6d3f9</id>
<title>Merge pull request #139 from FelineStateMachine/fix/portal-control-v2-input-ack</title>
<link href="https://src.rest/cat/goq/commit/ad308aae214cc4e7b93bc76a75273bec36a6d3f9/"/>
<author><name>FelineStateMachine</name></author>
<updated>2026-07-25T17:02:04-06:00</updated>
<content type="text">fix: control v2 disconnected instantly, then shadow mode detached the viewer</content>
</entry>
<entry>
<id>5c7eb5555b402f200513aae5bbf9d49eb5a2b1ea</id>
<title>fix(host): shadow-mode adaptive no longer detaches viewers it cannot help</title>
<link href="https://src.rest/cat/goq/commit/5c7eb5555b402f200513aae5bbf9d49eb5a2b1ea/"/>
<author><name>Dami</name></author>
<updated>2026-07-25T16:32:39-06:00</updated>
<content type="text">With the input-ack disconnect fixed, the session survived long enough to reach
the next failure: the host detached the viewer after ~25 seconds with
reason=&quot;adaptive_recovery_detach&quot;.

`RecoveryMutation::Detach` applied unconditionally. In shadow mode the
controller computes a lower bitrate and never applies it, so a viewer under
sustained pressure cannot recover -- the only remedy is switched off -- and the
recovery state machine escalates to detach on schedule. Shadow mode disabled the
remedy and kept the punishment.

This is the documented default, not an exotic configuration.
`docs/sigil-host-activation.md` step 5 writes
`encoder_backend = &quot;external-gst-launch&quot;`, which is exactly what selects shadow
mode, so a host provisioned by following the guide detaches any viewer that
experiences sustained pressure. On the reference host that is 2560x1600@60 at
12000 kbps to a Wi-Fi client.

Detaching is an action, so it is now gated on actuation being available, and
says so when it declines. The duplicated actuation predicate becomes one
`encoder_actuation_available` helper used by both the coordinator and the
feedback session.</content>
</entry>
<entry>
<id>17d02c28dbf3e1862286c4af3e9a2976f3134e62</id>
<title>Merge pull request #136 from FelineStateMachine/ci/pipeline-ergonomics</title>
<link href="https://src.rest/cat/goq/commit/17d02c28dbf3e1862286c4af3e9a2976f3134e62/"/>
<author><name>FelineStateMachine</name></author>
<updated>2026-07-25T16:27:23-06:00</updated>
<content type="text">ci: split the complete demo gate into parallel cached legs</content>
</entry>
<entry>
<id>e912535d8e336ad6f29bd8f95ba6d284ec723d20</id>
<title>Merge pull request #138 from FelineStateMachine/fix/docs-activation-truth</title>
<link href="https://src.rest/cat/goq/commit/e912535d8e336ad6f29bd8f95ba6d284ec723d20/"/>
<author><name>FelineStateMachine</name></author>
<updated>2026-07-25T16:27:11-06:00</updated>
<content type="text">docs: stop overclaiming non-root setup and couch-only pairing</content>
</entry>
<entry>
<id>4f7f481f717d125bb9fca4835f5c3649c1f930b2</id>
<title>fix(portal): control v2 disconnected the session on its first input ack</title>
<link href="https://src.rest/cat/goq/commit/4f7f481f717d125bb9fca4835f5c3649c1f930b2/"/>
<author><name>Dami</name></author>
<updated>2026-07-25T16:27:08-06:00</updated>
<content type="text">Clicking to control always dropped the whole session and forced a reconnect.

`set_input_ack_negotiated` is called only inside the
`if control_protocol == ControlProtocol::V1` branch in connect.rs. The control
v2 path negotiates InputAck with the host but never records that in the session
diagnostics, so `observe_ack` still saw `negotiated == false` and rejected the
host&#39;s first acknowledgement with &quot;Host sent an input acknowledgement that was
not negotiated&quot;. That marks the pointer feedback terminal/malformed, and the
frontend treats a terminal feedback envelope as fatal and disconnects.

The host emits that first ack the moment the input v2 stream opens, to prime
pointer feedback, so every control attempt hit it. Control v2 could not have
worked.

Both rejection paths in `run_input_feedback_v2` also broke silently. A fatal
disconnect left nothing in the log to explain itself, which is why this looked
like a transport fault: the host reported only &quot;connection lost&quot; once Portal
had already torn the endpoint down. They now name the mismatch.

Verified against a live Bazzite host running the published 0.1.0: input v2 is
accepted and the session survives instead of dying ~8ms later, and the
rejection no longer appears.</content>
</entry>
<entry>
<id>d5d0ea10f828116ae0a758a6b958cebe2a1e5db1</id>
<title>docs: drop the root claims instead of qualifying them</title>
<link href="https://src.rest/cat/goq/commit/d5d0ea10f828116ae0a758a6b958cebe2a1e5db1/"/>
<author><name>Dami</name></author>
<updated>2026-07-25T16:13:00-06:00</updated>
<content type="text">goq.sh said &quot;non-root Bazzite setup&quot; and the activation guide said to run it
&quot;not as root&quot;. Activation step 1 needs sudo for groupadd, usermod, three udev
rules and modprobe, so both claims were wrong in the way that strands someone
mid-setup. Explaining the exception in prose just draws attention to a promise
being broken, so neither surface makes the claim now. Step 1&#39;s commands say
`sudo` on their own line; that is the documentation.

Also drops two stale claims: the Decky plugin was advertised as needing no SSH
or keyboard, but it revokes a paired Portal and cannot create an invitation, so
first pairing still needs a shell; and the release note still called the signed
channel pending after v0.1.0 published it.</content>
</entry>
<entry>
<id>1af9ebe47dcdd84c5f79a1bfd6d7960fcdb2f83e</id>
<title>ci: write Cargo caches only from main and share redundant entries</title>
<link href="https://src.rest/cat/goq/commit/1af9ebe47dcdd84c5f79a1bfd6d7960fcdb2f83e/"/>
<author><name>Dami</name></author>
<updated>2026-07-25T15:31:23-06:00</updated>
<content type="text">A cache entry belongs to the branch that wrote it, so saving from pull
requests gave every open pull request its own full set. The first run of the
split gate wrote 9.4GB across eight entries against GitHub&#39;s 10GB per-repo
ceiling, which meant two or three concurrent pull requests would evict each
other&#39;s entries continuously and quietly send the legs back to cold builds --
undoing the speedup the split just bought.

Legs now restore with actions/cache/restore and save with actions/cache/save
gated to `github.event_name == &#39;push&#39;`, both at the digest already pinned for
actions/cache, so no new action enters the trust set. Pull requests read
main&#39;s entries through restore-keys and write nothing, so the repository holds
one set instead of one per branch.

Loopback cases 1-3 are all debug-profile builds of the same binaries and were
storing three near-identical 767MB copies. They now share one entry, with case
1 nominated as its writer and case 4 owning the release entry, so no two
concurrent matrix legs race to reserve the same key.

Together that takes main&#39;s steady-state footprint from 9.4GB to roughly 6.3GB.

The policy checker gains the matching invariants: a step-level `if` is now
permitted only on a cache save and only with an approved push-gated condition,
an unconditional save is rejected outright, a restore must be paired with a
save under the same key and paths, the restore must carry the id the save
condition reads, and the combined read-write cache action may only ever cache
the one-megabyte cargo-zigbuild binary. Suite grows from 51 tests to 59.</content>
</entry>
<entry>
<id>8941f0b20bbeaecf6b7b87dfd1a84624325e3f99</id>
<title>ci: split the complete demo gate into parallel cached legs</title>
<link href="https://src.rest/cat/goq/commit/8941f0b20bbeaecf6b7b87dfd1a84624325e3f99/"/>
<author><name>Dami</name></author>
<updated>2026-07-25T14:58:24-06:00</updated>
<content type="text">The gate ran as one serial 30-minute job with no Cargo caching, so every
pull request recompiled the workspace roughly eight times over: the zigbuild
cross target, the workspace test build, a second full build under
clippy-driver, two feature-flip checks, a debug build, a release build for
the release-profile loopback, and release feature flips for demo-direct-node
and demo-auth-bypass. A documentation-only pull request paid the full thirty
minutes for checks it could not affect.

Ordering made it worse. The cross build ran first and `cargo fmt --check`
ran seventy lines later, so a missing newline cost a complete gate to learn
about.

verify-demo-build.sh is now the ordered union of named stages, and `--stage`
runs one. Passing no argument still runs every stage, so the release and
hardware-UAT workflows are unchanged. `--stage quick` is about five seconds.

CI runs those stages as parallel legs behind the required `Complete demo
gate` summary job, each restoring its own Cargo cache. The summary job fails
unless every leg succeeded or was a leg the audited docs-only scope may
skip; the lint and repository-test legs always run, which is what keeps the
website, docs, and README claim contracts covered on a docs-only diff.

verify_ci_cross_build_policy.py previously pinned the single job byte for
byte, which blocked speeding the gate up as effectively as it blocked
weakening it. It now asserts invariants instead: legs cannot suppress their
own failures, always-run legs carry no `if`, skippable legs carry exactly
the audited condition, the summary job depends on every other job so a new
job cannot be added outside the gate, the docs-only path allowlist is pinned
exactly, and no step can poison the toolchain. Its suite grows from 26 tests
to 51.

Structural checks cannot prove a stage still reaches a check, so
scripts/tests/demo-gate-stages.sh executes the real gate against stubbed
tools and asserts both that every check in a required inventory runs and
that the per-stage runs spend exactly the same commands as the default
complete run.</content>
</entry>
<entry>
<id>c9ba9802ae8027571a73f35c49b6763a6373f289</id>
<title>Merge pull request #135 from FelineStateMachine/fix/portal-dist-prebuild</title>
<link href="https://src.rest/cat/goq/commit/c9ba9802ae8027571a73f35c49b6763a6373f289/"/>
<author><name>FelineStateMachine</name></author>
<updated>2026-07-25T14:24:19-06:00</updated>
<content type="text">fix(release): make the Portal macOS package actually build and ship signed</content>
</entry>
<entry>
<id>d548572a3110f017d0e1146a3ed79c5a076834bb</id>
<title>fix(release): make the Portal macOS package actually build and ship signed</title>
<link href="https://src.rest/cat/goq/commit/d548572a3110f017d0e1146a3ed79c5a076834bb/"/>
<author><name>Dami</name></author>
<updated>2026-07-25T14:23:47-06:00</updated>
<content type="text">Three defects in a path that had never run end to end. Found by running
scripts/package-macos-client.sh locally rather than one CI dispatch at a time.

`portal-dist` is src-tauri/build.rs output and is deliberately not committed,
but `cargo tauri build` validates frontendDist before cargo runs any build
script, so on a clean checkout the directory never exists when tauri looks for
it. Every Portal job failed with &quot;Unable to find your web assets&quot;. It only
worked on a developer machine because an earlier build had left the directory
behind. Run `cargo check -p portal` first, which executes the build script and
writes the payload.

The .app was never signed. The script asserts `Signature=adhoc` and relies on
&quot;the linker&#39;s ad-hoc signature&quot;, but that covers only the Mach-O; the bundle had
no _CodeSignature, so `codesign --verify --deep --strict` failed with &quot;code has
no resources but signature indicates they must be present&quot;.

Signing has to happen during bundling, not after. The DMG is built from the
.app, so signing the .app once the DMG already exists would publish a DMG
containing an unsigned bundle -- which arm64 macOS refuses to execute, and which
none of the existing assertions would have caught, because they inspect the .app
and only checksum the DMG. Export APPLE_SIGNING_IDENTITY=- for the ad-hoc build.
`-` is the ad-hoc pseudo-identity rather than an Apple credential, so the guard
that refuses real credentials in ad-hoc mode still means what it says.

Verified locally from a clean bundle directory: the script exits 0 and emits
client_signing=adhoc with all three assets, and the app *inside the mounted DMG*
passes `codesign --verify --deep --strict` reporting Signature=adhoc, no
authority chain, and no TeamIdentifier.</content>
</entry>
<entry>
<id>86cb5c2723b2b2e2aa1d74d1a389c3b4885aa42a</id>
<title>Merge pull request #134 from FelineStateMachine/fix/drop-hero-notarization-note</title>
<link href="https://src.rest/cat/goq/commit/86cb5c2723b2b2e2aa1d74d1a389c3b4885aa42a/"/>
<author><name>FelineStateMachine</name></author>
<updated>2026-07-25T13:23:53-06:00</updated>
<content type="text">fix(website): drop the duplicate notarization note from the hero</content>
</entry>
<entry>
<id>d4c104b044173ff1ad1f800f8452657098afdaa9</id>
<title>fix(website): drop the duplicate notarization note from the hero</title>
<link href="https://src.rest/cat/goq/commit/d4c104b044173ff1ad1f800f8452657098afdaa9/"/>
<author><name>Dami</name></author>
<updated>2026-07-25T13:23:36-06:00</updated>
<content type="text">The hero release-note repeated something the start-note already says: &quot;ad-hoc
signed rather than Apple-notarized, so macOS blocks the first launch until you
allow it.&quot; Saying it twice bought nothing and made the download area noisy, so
the hero keeps only the release status and the history link.

Remove the gate line that required the phrase in index.html with it. A grep
asserting a static string appears in a static file it was committed alongside
cannot fail for any interesting reason, and it forced the wording to live in one
exact spot forever.

The check that matters is kept: verify-website.sh still fails if any surface
claims developer-id/notarized/stapled. Forbidding a false claim is the direction
with real consequences; mandating the disclaimer&#39;s exact placement is not.

`#portal-release-status` stays -- updatePortalDownload() early-returns without
it, which is what froze the download button.</content>
</entry>
<entry>
<id>e96de5b92800b7d569dee4e9f1db8451af05edbf</id>
<title>Merge pull request #133 from FelineStateMachine/fix/release-build-and-order</title>
<link href="https://src.rest/cat/goq/commit/e96de5b92800b7d569dee4e9f1db8451af05edbf/"/>
<author><name>FelineStateMachine</name></author>
<updated>2026-07-25T13:21:11-06:00</updated>
<content type="text">fix(release): make the Portal release build run, and correct the runbook order</content>
</entry>
<entry>
<id>73d4319096e45db165aad83236380e0d2eba40da</id>
<title>fix(release): make the Portal release build run, and correct the runbook order</title>
<link href="https://src.rest/cat/goq/commit/73d4319096e45db165aad83236380e0d2eba40da/"/>
<author><name>Dami</name></author>
<updated>2026-07-25T13:20:23-06:00</updated>
<content type="text">Two defects blocked the first release; neither had ever been executed.

`cargo tauri build --locked` is not a valid invocation. tauri-cli 2.11.3 has no
`--locked` flag on `build`; cargo arguments go after `--`. All four Portal jobs
died with &quot;unexpected argument &#39;--locked&#39; found&quot; before compiling anything, in
both `scripts/package-macos-client.sh` and the preview matrix.

`docs/release-credentials.md` also had signing and the Portal build in the wrong
order. The Portal job refuses to start unless the draft holds exactly the two
Sigil candidate assets, and calls its own output the five-asset *pre-signature*
contract, so the enforced order is build → Portal → sign → promote. The runbook
said sign → Portal, which makes the Portal precondition fail on a draft that
already carries the .minisig. Following the document was enough to wedge the
release.</content>
</entry>
<entry>
<id>4519001f4ef8765c47c331df5af43408acbb0a99</id>
<title>Merge pull request #132 from FelineStateMachine/fix/website-download-wiring</title>
<link href="https://src.rest/cat/goq/commit/4519001f4ef8765c47c331df5af43408acbb0a99/"/>
<author><name>FelineStateMachine</name></author>
<updated>2026-07-25T11:43:16-06:00</updated>
<content type="text">fix(website): restore the download status element and the notarization gate</content>
</entry>
<entry>
<id>9255f35cb597fc49977b184f7246c353cc5e0e57</id>
<title>fix(website): restore the download status element and the notarization gate</title>
<link href="https://src.rest/cat/goq/commit/9255f35cb597fc49977b184f7246c353cc5e0e57/"/>
<author><name>Dami</name></author>
<updated>2026-07-25T10:29:54-06:00</updated>
<content type="text">&quot;nit: remove terrible ui warning&quot; deleted two things, and only one of them was
a UI nit.

`#portal-release-status` is not decoration: `updatePortalDownload()` in
dither.js bails at `if (!button || !note || !os || !arch) return;`. With the
span gone the function returned before touching the button, so the download was
frozen at &quot;no macos arm64 build yet&quot; forever -- including after v0.1.0 is
promoted and portal-release.json flips to available. The button would never
have gone live.

`verify-website.sh` also requires the literal &quot;portal is not notarized by
apple&quot;, which is why every deploy from main has failed since that commit. The
gate exists because macOS blocks the first launch of an ad-hoc signed build and
the site is supposed to say so rather than let it surprise people.

Both restored on the one existing release-note line, as a single inline clause
instead of the three-clause paragraph that was there before, so the disclosure
is present without the wall of text.</content>
</entry>
<entry>
<id>0d391ba757e8fbef9e1bb829482ce4ceca2d9b6f</id>
<title>Merge pull request #131 from FelineStateMachine/release/v0.1.0-pins</title>
<link href="https://src.rest/cat/goq/commit/0d391ba757e8fbef9e1bb829482ce4ceca2d9b6f/"/>
<author><name>FelineStateMachine</name></author>
<updated>2026-07-25T10:23:38-06:00</updated>
<content type="text">release: open the Sigil bootstrap channel for v0.1.0</content>
</entry>
<entry>
<id>69f67d998e43d06ab5df85e0a2f175a4b9f7d925</id>
<title>nit: remove terrible ui warning</title>
<link href="https://src.rest/cat/goq/commit/69f67d998e43d06ab5df85e0a2f175a4b9f7d925/"/>
<author><name>Dami</name></author>
<updated>2026-07-25T10:21:29-06:00</updated>
<content type="text"></content>
</entry>
<entry>
<id>8eb315666b1e1ba77f592549020e5bfdf4a670aa</id>
<title>release: open the Sigil bootstrap channel for v0.1.0</title>
<link href="https://src.rest/cat/goq/commit/8eb315666b1e1ba77f592549020e5bfdf4a670aa/"/>
<author><name>Dami</name></author>
<updated>2026-07-25T10:19:43-06:00</updated>
<content type="text">Replace both `unconfigured` trust pins in one commit, which is the only shape
`verify-sigil-bootstrap.py` accepts: it treats a half-configured channel as an
error rather than a partial rollout, so the repository key and the bootstrap&#39;s
embedded key and tag move together or not at all.

- `release/sigil-minisign.pub` becomes the offline Minisign public key
  3247504746CF2DB4. The private half was generated off-runner, is passphrase
  protected, and never enters CI: `Sigil Release` builds an unsigned draft,
  the operator signs it offline, and `promote-signed-draft` verifies that
  detached signature against this file as checked out from the tag.
- `website/install-sigil` pins the same key and `release_tag=v0.1.0`, so the
  public bootstrap installs exactly one immutable tag verified against exactly
  one key.

`sigil_bootstrap_verification=ok`, `sigil_bootstrap_channel=open`,
`website_static_gate=ok`, `portal_release_tests=ok`, 29/29 shell tests.

Do not merge to main until v0.1.0 is promoted. A merge deploys goq.sh, and the
install command would then point at a release that does not exist yet.</content>
</entry>
<entry>
<id>5c6fb7357de7484fddf43c5963ea781494f30c7d</id>
<title>Merge pull request #130 from FelineStateMachine/fix/release-manifest-language</title>
<link href="https://src.rest/cat/goq/commit/5c6fb7357de7484fddf43c5963ea781494f30c7d/"/>
<author><name>FelineStateMachine</name></author>
<updated>2026-07-25T10:14:50-06:00</updated>
<content type="text">Stop blaming notarization for the missing Portal download</content>
</entry>
<entry>
<id>78f9065c00de64f42ca794124c05d52323d93e4d</id>
<title>docs(website): stop blaming notarization for the missing Portal download</title>
<link href="https://src.rest/cat/goq/commit/78f9065c00de64f42ca794124c05d52323d93e4d/"/>
<author><name>Dami</name></author>
<updated>2026-07-25T10:14:23-06:00</updated>
<content type="text">The download manifest told visitors there was &quot;no signed and notarized public
Portal release&quot; yet, implying notarization is the bar the project is working
toward. It is not: Portal is deliberately ad-hoc signed and GitHub-attested,
and `verify-website.sh` fails the build if any surface claims Developer ID
notarization. Reading it as a pending step misrepresents the trust model on the
one surface a prospective downloader actually sees.

State what is true -- no release promoted yet -- and name the signing posture
directly, so the string stays accurate once the download goes live.</content>
</entry>
</feed>
