Finish Persims consolidation

This commit is contained in:
matcha committed 2026-10-04 02:57:00 +00:00
1 parent 447eeaeba4
commit 076d049666
1 file changed
+193
+193
View File
@@ -0,0 +1,193 @@
# Persimmons follow-up candidate — 2026-09-30
Version **0.3.4** fixes popup-memory-only connection state with a non-secret
owner hint and live session validation on every reopen. Vault keys still die with
the popup. A read-only, exact-origin, same-owner handshake lets the signed-in page
say Extension connected without exposing unlocked state or secrets. Actions/Juice
is a compact collapsed divider with technical details under disclosures. A
same-folder Python update helper plus Reload removes repeated manual ZIP handling.
Orange icons, hero/footer copy, crypto, server pinning, origin allowlist, dedicated
host and MCP boundaries are preserved.
Candidate acceptance: **42 Python tests**, **11 Node tests across four files**,
plus real Chromium 1243 against the live Persimmons API and the **real**
`https://wp.phly.cloud/wp-login.php` (not an intercepted target fixture). Candidate
homepage assets were served locally into the Persimmons origin for pre-publication
review. Connect → initialize/unlock → save → destroy popup → refresh both pages →
reopen automatically Connected/Locked → wrong-passphrase rejection → unlock/list
→ fill both fields with **zero POST submissions** → delete all pass. Homepage
handshake, expired/logout session rejection, changed-owner rejection and revoked
host permission also pass. No Tea permission was granted. Synthetic accounts
remain, but successful tests remove their ciphertext and sign out; no provider
credentials or sessions are included in receipts. The normal Chromium permission
prompt was not clicked by automation: the harness pregrants the exact permission;
the user's accepted prompt is the human evidence.
Package SHA-256: `d98ce727ebdedd9ceaec226960103baa58f8a5b65a0b8e31155b5fdea7334996`.
Initial and pre-publication fetch: HEAD/origin-main both
`26fec5fadd444ca2ccfe70c7eeb9ee6688bb7de4`, ahead 0 / behind 0; initial clean,
pre-commit dirty only with this task. No delegation. Build-generated host vault
module remains byte-for-byte copied from the accepted source.
Deployment remains a separate required receipt: dispatch
**Launch independent Persimmons**, `.gitea/workflows/persimmons-launch.yml`,
`matcha/teahub`, ref **main**, no inputs, after canonical publication. The local
reviewed `tea_workflow_dispatch` allowlist does not include this workflow; do not
extend it through its own running control plane or bypass it with provider secrets.
Check the live `/healthz` source SHA and asset/package bytes after the run, then
repeat the browser check without `PERSIMMONS_LOCAL_UI=1`.
User retest: use **Update extension** on the homepage, save the helper once, run
`python3 update-extension.py "/path/to/existing/persimmons-extension"`, then
`chrome://extensions` → Persimmons → **Reload** (do not uninstall). Sign in at
Persimmons; open the WordPress login URL, Connect once, unlock, save a disposable
credential, close/refresh/reopen, unlock, select/Fill without submit, and Delete.
Refresh Persimmons to see Extension connected. Future updates reuse the same
helper command/folder; 0.3.4 also offers popup **Reload installed files**.
Remaining: Chrome Web Store private/unlisted distribution needs explicit approval,
review and a verified matching store identity. No Store upload/publication was
attempted. True self-download of unpacked extension source is unavailable; Reload
alone rereads files. Helper browser acceptance is Linux-only. Detailed update
mechanics, platform notes and official references are in
[persimmons-extension/README.md](../persimmons-extension/README.md#034-connection-controlled-acceptance-and-updates).
---
# Persimmons taste-test receipt — 2026-09-30
Accepted: <https://persimmons.app> is live. Homepage, health, extension download,
exact-origin preflight and real Chromium encrypted-vault flow pass.
## Deployment and acceptance
- Runtime source: `54f0ff75f7b6a89d69dc4a211b44467ffc35be03`.
[Final launch Action 617](https://teahub.xyz/matcha/teahub/actions/runs/617), job 619,
succeeded; complete deployment/check cycle: 52.814 seconds.
- Before deploy: explicit fetch; worktree HEAD = upstream = runtime source;
ahead 0, behind 0, dirty false. Initial canonical source was `a80a64f`.
AGENTS and factory checkpoint read; no delegation.
- Fly app `persimmons-app`, `iad`; one shared CPU / 512 MiB;
machine `48e729dc5796e8`, release 2, health passing.
Encrypted 1 GiB volume `vol_rkgqyxm5k2gxm064` persists `/data`.
- Image `registry.fly.io/persimmons-app:deployment-01M3QY0KQ70X44T1EA7CYETDE0`;
digest `sha256:c99e5711c0dffee68816bd9059e81ce4c9bee6873e6f9b03198d4abae96a234f`.
- Cloudflare apex A `66.241.124.82`, AAAA `2a09:8280:1::1a0:f8e1:0`;
TTL 60, DNS-only. Fly-managed Let's Encrypt RSA/ECDSA certificates are verified
and active. No additional hostname or Cloudflare Worker is needed.
- `/`, `/healthz`, app JS, sign-in JS and extension ZIP: 200/nonempty.
Health reports the runtime source above. Final extension 0.3.2 matches the
tested package byte-for-byte: SHA-256
`41dd24474ad35fca6d37378b641c0ded300450bc39145315a2d1d256a87d0430`.
- Preflight on `/api/human-vault/items` and `/api/human-vault/items/read`: 204,
credentials true, exactly one ACAO:
`chrome-extension://kiolgjoohhgdohcafgelhikpgkbmckbg`. Untrusted origins: 403,
no ACAO. No wildcard callers.
- Live disposable HTTP flow: register/login 200, extension Web Crypto ciphertext
create 201, logout/login, persisted read 200, delete 200, logout 200.
- Real Chromium 1243: homepage and independent signup pass; actual pinned popup
has Persimmons permission and **no Tea permission**; session cookie transport,
unlock, encrypted save, explicit fill, lock, unlock/delete and logout rejection
all pass. Fill used a locally intercepted HTTPS form; it contacted neither
WordPress nor Tea. Successful probes delete their ciphertext and sign out.
- Ten Node tests and seven Python host/vault/MCP tests pass. Canonical MCP tests
assert exactly `persimmons_list` and `persimmons_juice_list`, with no human-store
access. Connected agent inventory exposes only the metadata tool, no reveal tool.
## Scope and preserved boundaries
The host reuses the accepted `tea/web/🍊/index.html` design, with taste-test controls
for independent sign-in and extension download. Repository-token management and
Juice remain on the Tea fallback; this round does not migrate those stores or the
full repository-management UI. No Tea/StreetPulse runtime dependency was added.
No neighboring service was restarted, redeployed, or changed. Tea source/UI and
human-vault routes remain available as fallback.
Build copies `tea_mcp/human_vault.py` byte-for-byte; both copies have SHA-256
`8651aed1f8351477cdfd737a9f0d0b38b2e6e7f68edde964980e520a4c9f4f81`.
Route prefix is `/api`; empty POST reads append `/read`. Real Chromium omitted
Origin on permitted extension GET requests, which the accepted handler correctly
rejected. The POST adapter carries Chromium's genuine Origin into the unchanged
read handler; it never invents a caller header or weakens the HTTPS/session/owner
checks. The initial HTTP-only launch ([614](https://teahub.xyz/matcha/teahub/actions/runs/614))
was corrected before final browser acceptance.
Independent accounts use scrypt password verifiers, throttled same-origin auth
POSTs, and revocable 12-hour opaque Secure/HttpOnly host-only sessions. Account
passwords are separate from local vault passphrases. No account recovery, local
key sync or old-vault migration is added. Wrapped keys are namespaced by origin
and account. The separate extension Actions/Juice controls retain their explicit
Tea permission/session flow. The new host has no MCP endpoint.
Existing Actions `FLY_INFRA` / `CLOUD_DNS` secrets stayed inside the runner.
[Preflight 610](https://teahub.xyz/matcha/teahub/actions/runs/610) proved zone reads;
[611](https://teahub.xyz/matcha/teahub/actions/runs/611) created/deleted a unique TXT
probe (both 200). No existing DNS records were replaced. Browser shared libraries
and fonts were extracted under `/tmp`; no worker packages were installed.
## Exact human taste-test steps
1. Open `https://persimmons.app`. Follow **Sign in / create account**, choose a
disposable username and a password of at least 12 characters, and create the
account. The homepage should say **Signed in to Persimmons**.
2. Download the Chromium extension from the homepage, extract the ZIP, and use
`chrome://extensions` → Developer mode → **Load unpacked** → extracted
`persimmons-extension` folder. Verify ID `kiolgjoohhgdohcafgelhikpgkbmckbg`.
Update/reload the existing same-ID extension if already installed; retain the
same browser profile. Existing Tea keys remain separate.
3. In that browser profile, open an existing allowed HTTPS login form at
`https://wp.phly.cloud` or `https://teahub.xyz`. This test does not change either
service. Use only the existing disposable-credential test account.
4. Open the extension. Under **My vault · human accounts**, click **Connect / list
this origin** and allow `persimmons.app`. Enter a distinct vault passphrase of
at least 12 characters, then **Initialize / unlock My vault**. The passphrase
and decrypted keys stay in the extension.
5. Enter the disposable account username/password and **Encrypt and save account**.
Close and reopen the popup, reconnect, unlock, select the account, then click
**Fill**. Check the two fields; the extension does not submit the form.
6. Lock the popup and verify Fill is unavailable. Unlock and delete the encrypted
disposable item. Sign out on Persimmons; reconnect must fail safely. Sign in
again to verify the same independent account owns the vault.
7. Agent inspection must expose only connection/Juice metadata through the existing
accepted MCP inventory. Never paste passwords, vault passphrases, cookies or
ciphertext into chat, logs, screenshots, or issue receipts.
Keep the browser profile and vault passphrase: local keys have no recovery or sync.
No existing credential or wrapped-key migration is attempted in this round.
## Repeat automated checks
Run `python persimmons/build.py`, then
`node --test persimmons-extension/tests/*.test.mjs` and
`python -m unittest tests.test_persimmons_host tests.test_human_vault`.
`tests/persimmons-host-browser.cjs` repeats the live disposable-account browser
check from repository root. It requires Playwright and Chromium; optionally set
`PERSIMMONS_PLAYWRIGHT_MODULE` to an installed Playwright module path and
`PERSIMMONS_CHROMIUM` to the executable. Synthetic account verifiers remain;
failed early browser probes' unused sessions expire within 12 hours. No real
provider credentials were used.
Provider mechanics: [Cloudflare DNS API](https://developers.cloudflare.com/api/resources/dns/subresources/records/methods/list/)
and [Fly custom-domain validation](https://docs.fly.io/networking/custom-domain/).
## 0.3.5 golf pass — 2026-09-30
Generic popup copy now shows the current site and Connect, then Unlock, then
saved accounts / Save for this site. Settings appears only after connection;
Juice remains collapsed and appears only when unlocked on its supported Tea
origin. Secondary token requests are lazy. Provider hints are absent elsewhere.
The homepage removes unused provider/repository controls, hides Get when the
extension responds, and shows Update only after a numeric version comparison
against the build's version.json. CSV import is not shipped; the extension README
specifies the bounded local, selective, deduplicating, ciphertext-only next step.
Crypto, origin allowlists, owner/session validation and MCP access are unchanged.
Validation: 38 Persimmons Python tests plus the human-vault checks pass; six Node
test files cover crypto, current-origin behavior, no-reveal, connection ownership,
popup visibility and homepage version states. Chromium acceptance is inconclusive:
local UI navigation and a subsequent browser launch timed out on this worker.
No successful real-browser result is claimed for this pass. Initial and
pre-publication canonical base: bc1ad9ff8337d18da7ce52704eecbf0f6051d75c,
ahead 0 / behind 0, no unrelated worktree edits. No delegation.