194 lines
12 KiB
Markdown
194 lines
12 KiB
Markdown
# 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.
|