Qualify durable purchase and media primitives and preserve app launch paths

This commit is contained in:
archipelago
2026-10-06 20:50:44 -04:00
parent a876dc3d0b
commit b52214f7a0
31 changed files with 4417 additions and 83 deletions
@@ -151,3 +151,49 @@ subsequent combined isolated Rust run also passed its independent golden fixture
test, establishing agreement across both implementations. Node caller/serving
integration and live acceptance remain open. No fixture or Rust source changed
between the frozen compilation inputs and the successful run.
## Immutable serving and rental caller work
The next local source connects explicit producer/project approval to the fixed
`indeedhub-api` installation pin and stores a separate immutable serving mapping
before returning the signed registration receipt. It does not insert filenames
into the legacy mutable share catalog. Its canonical ordered-array terms hash has
an independently generated Node.js fixture. Original Cloud source deletion does
not change the saved snapshot, registration receipt or rental terms.
A peer GET to `/content/{registered_id}/rental/{purchase_uuid}` now requires the
existing node proof signed for that exact path and the original
`X-Content-Capability`. The node verifies its own durable seller `ReceiptSaved`
record, authenticated buyer, immutable content/hash/size/terms and settlement
amount. Invalid ranges reject before a rental starts. First successful durable
stream authorization records one rental window; reopen and range requests keep
that same deadline. Stream reads use bounded 64 KiB buffers, reject clock rollback
and stop new reads at expiry. HEAD and preflight do not start a window.
This is a server access window, not DRM. Bytes already delivered cannot be
revoked. A crash after the lease is fsynced but before the first network byte still
consumes elapsed time: local persistence and remote byte delivery are not one
atomic operation. The player must display the persisted expiry and reuse the
original purchase/capability on reconnect, not create another payment.
Seven registered-media tests and three route/stream tests passed in
`/tmp/archy-registration-rental-batch-tests.log`; its overall result was 1,834
passed, one failed legacy missing-file expectation, and five existing skips.
All 383 captured source/build/fixture hashes remained unchanged. The expectation
was corrected separately and awaits the next full run. Do not describe that batch
as a clean combined suite or live playback acceptance.
The subsequent, not-yet-tested performance refinement persists the already
verified snapshot's signed hash and inode/device/ctime/size attestation during
registration. Ordinary first-open/range requests reuse it. A missing cache streams
the original signed hash under a per-registration lock; buyer leases use separate
per-purchase locks. Large verification reads do not hold the global metadata lock
or start a rental while queued. An identical concurrent cache writer is accepted
only after exact readback and file/directory fsync. Three additional tests cover
lock independence, cache reconstruction and mismatched-cache refusal.
Owner-session/CSRF approval RPC, producer-signed exact selection, native Cloud
picker/consent bridge, app receipt consumption, and player reconnect/expiry UI are
being connected next. Their source is not yet deployed; app registration and
publication flags remain disabled pending complete qualification. No real payment,
announcement, media publication or node deployment was performed by this work.
+109
View File
@@ -0,0 +1,109 @@
# Installer-owned IndeeHub registration identity
Status: source compiled and eight installer/orchestrator tests passed in the
combined isolated backend run. That run has one unrelated FIPS binding test
failure (1,821 passed, one failed, five existing skips), so combined qualification
is not clean. The separate container manifest test passed. No deployment
or actual-node acceptance. This adds an installation prerequisite; it does not
enable registration or publication.
The IndeedHub API manifest explicitly opts in with
`container.media_registration_identity: true`. The field defaults to false and
is omitted from serialized ordinary manifests. Only opted-in apps read the
existing node identity or receive registration identity variables.
The production install/reconcile environment chokepoint loads the existing node
key, verifies its derived public key matches `identity/node_key.pub`, and asks the
private installation store for a stable pin. Missing or mismatching identity
files fail; no node key is generated, repaired or replaced. The helper runs on a
blocking worker and uses bounded cross-process locking plus durable no-replace
writes.
The public identity values injected are:
- `ARCHIPELAGO_REGISTRATION_NODE_PUBLIC_KEY`: exact existing Ed25519 public key.
- `ARCHIPELAGO_REGISTRATION_NODE_DID`: its matching did:key identity.
- `ARCHIPELAGO_REGISTRATION_AUDIENCE`: one persisted UUID for this installed app.
These are public identity bindings, not secret signing keys. They are derived
from authenticated installation state. Manifest plaintext duplicates are replaced
by the authoritative pins; derived/secret-backed attempts to override these names
are rejected. Existing native-signing user identities are unrelated to this node
receipt-signing identity. `NODE_IDENTITY_PUBKEYS` is not used for this purpose.
No `_ENABLED` setting is written. No unrelated app receives these values.
## Persistence and recovery
The node keeps private 0600 records beneath the 0700 directory
`<node-data>/app-registration-pins/`:
- `<app-id>.json`: version, app ID, node public key/DID and stable app audience.
- `<app-id>.initialized.json`: version, app ID and canonical pin-record SHA256.
Provisioning returns only after both files and their directory are fsynced.
Interrupted initial provisioning after pin persistence finishes its marker on
retry without changing the audience. A missing pin with a surviving marker is
an error requiring recovery of the original pin, not permission to generate a
replacement. Damaged, unreadable, symlinked or mismatched files remain untouched.
A node identity change also requires an explicit migration; it does not silently
repin an existing app.
`load_existing` is the future bridge/RPC lookup: it never creates files or app
identity. It requires matching complete persisted records. The bridge must bind
the actual installed frontend/backend relationship: IndeedHub's UI app is
`indeedhub`, while its API and this stored registration scope are `indeedhub-api`.
Arbitrary apps must not select another installed scope by sending its name.
The audience survives app upgrade, ordinary restart, repeated reconciliation,
failed install retry and reinstall that preserves the app database. This change
contains no pin deletion API or uninstall hook. It does not alter uninstall
choices, persistent app data, original Cloud files, wallet data or outstanding
media snapshots/rentals.
Explicit full data deletion is a separate operator decision. A future reset
workflow must coordinate deletion of app database/intents and pin state, and must
preserve or resolve outstanding node media/payment obligations before allowing a
new audience. Removing only one pin file is not a supported reset. Merely
uninstalling/reinstalling an app must not rotate its audience. If all installation
records are externally destroyed, this store cannot distinguish that from a
first installation; restore them along with the original app database rather than
re-enabling registration against a new audience.
## Prepared local checks
The patch adds five isolated store/env tests, three production-orchestrator
chokepoint tests and one manifest test. They cover stable retry/reload, distinct
app audiences, concurrent provisioning, key preservation, corruption/missing-pin
and foreign-key rejection, interrupted marker completion, symlink rejection,
authoritative/idempotent environment rendering, no implicit enablement, unrelated
apps without identity, and existing-key/public-key consistency. Fixtures use
private temporary directories and mock runtime calls only.
The combined run used `scripts/test-backend-isolated.sh`; all five store/env and
three orchestrator tests passed. Log:
`/tmp/archy-indeehub-executor-combined-tests.log`. All 377 captured source/build
input hashes remained unchanged through the run; provenance is recorded in
`/tmp/archy-indeehub-executor-combined-provenance.json`. The single failure is
`fips::dial::tests::purchase_post_serializes_once_and_binds_the_actual_bytes_to_the_peer`.
Do not treat this as a clean combined suite. The container crate manifest test
still needs its scoped isolated run in the next coordinated slot. There is no
node deployment, catalog publication or app registration from this change.
Qualification update: the scoped isolated container run passed
`manifest::tests::media_registration_identity_is_explicit_and_preserved` (one
passed, zero failed, 82 filtered), with all 11 container/workspace input hashes
unchanged. Log: `/tmp/archy-registration-container-manifest-test.log`. The later
combined backend batch passed all installer tests again; its overall 1,834 passed,
one failed legacy missing-file expectation and five existing skips is not a clean
combined suite. Source remains undeployed.
## Combined qualification after resumed integration
The full isolated backend rerun passed 1,848 tests with zero failures and five
existing skips. All 385 recorded source, build and fixture hashes remained
unchanged. Evidence: `/tmp/archy-qualified-candidate-backend-rerun-tests.log` and
`/tmp/archy-qualified-candidate-backend-rerun-provenance.json`. Earlier failed
runs remain recorded. This qualifies the current backend primitives and Browse
path repair locally; production build and live deployment checks are next.
Complete purchase callers, app registration/publication and timed playback
acceptance remain open. No real payment or public publication was performed.
+19
View File
@@ -277,3 +277,22 @@ leave animation, and the song catalog loaded after bridge initialization. Hidden
iframe checks now use interval polling because animation-frame polling stops
when hidden. Timeouts were not increased. These browser passes do not establish
physical companion acceptance or replace the remaining lifecycle checks.
Publication review must also inventory the Yaya demo's visual assets in local
platform commits. A node-restricted promotion does not make a tracked asset or
Git commit private after publication. This worktree is not authorization to push
private demo source or derived private assets to either public mirror; retain
private delivery and prepare a separately reviewed public-safe contribution if
those assets are not approved for public distribution. No source publication was
performed during the resumed deployment and qualification work.
## Combined qualification after resumed integration
The full isolated backend rerun passed 1,848 tests with zero failures and five
existing skips. All 385 recorded source, build and fixture hashes remained
unchanged. Evidence: `/tmp/archy-qualified-candidate-backend-rerun-tests.log` and
`/tmp/archy-qualified-candidate-backend-rerun-provenance.json`. Earlier failed
runs remain recorded. This qualifies the current backend primitives and Browse
path repair locally; production build and live deployment checks are next.
Complete purchase callers, app registration/publication and timed playback
acceptance remain open. No real payment or public publication was performed.
+20
View File
@@ -581,3 +581,23 @@ unchanged backend/session/app containers and rollback at
Evidence: `/tmp/archy-payment-switch-dev-deploy.log`. Framework is reachable and
healthy but runs a different backend/UI revision; this incremental deployment
has not changed it.
Read-only real-attempt validation: Yaya's existing `lnd.paymentstatus` RPC returns
`failed`, `Insufficient channel balance`, and 2 sats for the operator's reported
Lightning attempt. This verifies the deployed compatibility UI's recovery lookup
against the actual existing backend, rather than only fixtures. Private evidence:
`/tmp/archy-payment-switch-incident/yaya-failed-lightning-rpc-result.private.json`.
The check did not pay, retry a payment, change a receipt, or infer seller invoice
cancellation. Browser interaction with the operator's own saved attempt remains
separate from this read-only RPC verification.
## Combined qualification after resumed integration
The full isolated backend rerun passed 1,848 tests with zero failures and five
existing skips. All 385 recorded source, build and fixture hashes remained
unchanged. Evidence: `/tmp/archy-qualified-candidate-backend-rerun-tests.log` and
`/tmp/archy-qualified-candidate-backend-rerun-provenance.json`. Earlier failed
runs remain recorded. This qualifies the current backend primitives and Browse
path repair locally; production build and live deployment checks are next.
Complete purchase callers, app registration/publication and timed playback
acceptance remain open. No real payment or public publication was performed.