halkyon/packages/halkyon_app/lib/testing.dart

36 lines
1.7 KiB
Dart
Raw Permalink Normal View History

/// Fakes of halkyon_app's boundaries, and a frame and dependencies built on
/// them, for an app's tests and this package's own: nothing here reaches a
/// server, the system's secure storage or the file system.
library;
// The fakes of the envelope's cipher and of shared spaces' keys and pins.
export 'package:halkyon_content/testing.dart';
feat(app,learn,todo): the assistants in Settings and on the operator's screen ADR 0021, step 2's app half. halkyon_app asks the module's assistant endpoints (ServerpodAssistantGateway, ServerpodAssistantOperatorGateway) and a person's own provider directly (halkyon_llm), behind AssistantRepository: an AssistantChoice is a GrantedAssistant, asked through the instance, which counts it, or a PersonalAssistant with the person's own key, which the instance never sees. assistant_messages.dart turns a conversation into the endpoint's models and back. AssistantsCard, for an app's settings: what is granted and left of its limits, agreed to once on a sheet saying what goes where, the person's use by UTC month, the instance's privacy page, and their own assistants where the operator allows own keys (kept ones stay listed, unasked, where it doesn't). AssistantGrantsCard on InstanceOperatorScreen: grants by handle with their limits in the pricing's unit, changed and taken back after asking, everyone's use by month; a found account's menu grants too. Nothing shows where nothing is offered or can be read. package:halkyon_app/assistant_models.dart holds the models in pure Dart. Learn keeps own assistants in the person's settings (ownAssistants, schema 12, SettingsOwnAssistants); SettingsRepository.update refuses (OwnAssistantRefused) to write a key where the settings would not be sealed (SettingsGateway.seals). Learn depends on halkyon_llm directly. Todo wires the gateways; a member offers no assistant. No feature asks an assistant yet (step 3). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-25 18:59:41 +01:00
// What asks a person's own key's provider, as the assistants' repository
// takes it, so an app's tests need no dependency of their own on
// halkyon_llm.
export 'package:halkyon_llm/testing.dart' show FakeLlmClient;
feat(app): sign in with a password and TOTP on the device ADR 0017, step 3: halkyon_app's side, which Learn and Todo take. - The account's cryptography on the device (`SodiumAccountCrypto`): halkyon_keys and SRP's client half, each step on an isolate of its own. sodium hands out results as views of native memory its finalizers free once the isolate that made them ends, so everything crossing back is copied first: a view read freed memory and crashed the process. - `PasswordGateway` on the module's endpoints (steps without a session through a client holding none; an authenticator set up with a session granted but not yet the device's), and `PasswordRepository` running the flows: signing in (M2 checked, the keys opened before anything is trusted), signing up, a password for someone signed in, an account never finished, the authenticators, recovery codes, changing the password, a new recovery phrase, and getting back in. - The unlocked keys in the system's keyring per instance and person (`SecureAccountKeyStore`), gone once another person signs in or nobody, and with the instance's removal. - The screens: the start screen's Sign in and Create an account (and when GitHub sign-in ends), the sign-in sheet (codes, recovery codes, an account never finished, a lost authenticator), the account's setup (the recovery phrase shown once, three random words typed back before anything reaches the instance; the authenticator's QR code, drawn with pub.dev's qr; the recovery codes), getting back in, and the account section (`AccountSecuritySection`). - `FileSaver` moves from Learn into halkyon_app, for the phrase and the codes in Todo too; `AppDependencies` names it and `passwords`. - halkyon_keys rebuilds account keys from the secret keys a device kept; the key proof's message is in halkyon_base_client, checked against the register's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-20 15:42:45 +02:00
export 'src/testing/fake_account_crypto.dart';
feat(base,app,learn,todo,train,meditate): agent accounts with tokens ADR 0044's step 6a (D42, D43, D45): accounts for programs, such as AI assistants, that an identified person makes from the Profile. halkyon_base keeps them on the instance's register, which its members ask: an agent is an account (agent_account: its owner, its name, its public keys, set by itself once) with one token (agent_token: 32 random bytes, kept as their SHA-256 alone, shown once). agents.create, mine, newToken, revoke, delete and setKeys serve its owner; agentSignIn.signIn exchanges the token for an ordinary server-side session of a day, with the scopes identified and agent, at most 60 sign-ins an hour from a network. Revoking a token or making a new one ends the agent's sessions; a token unused for 90 days lapses in every service's pruning. Up to 5 agents a person, where the operator didn't switch them off (AGENTS=off; said on the privacy page and in instance.basics). An agent makes no agents, creates or owns no shared space, is invited and raised as a Viewer alone, is never handed a space on, is named no operator and granted no assistants; each refusal has its test. Deleting a person deletes their agents first; an agent's public profile names whose agent it is. In the apps, every Profile has an Agents card (halkyon_app's AgentsSection): made with a name and a handle, its token shown once to copy, a new token, the token taken back, deleted. Learn's Share sheet marks an agent among the members and offers it no role above Viewer. The migrations, the module's and each host's (Learn, Meditate, Todo, Train), are additive alone: CREATE TABLE "agent_account" with a unique index on "agentId" (one row an agent account) and one on "ownerId" (a person's agents, and deleting them with the person), and CREATE TABLE "agent_token" with unique indexes on "agentId" (one token an agent) and "tokenHash" (the sign-in finds the token by its hash). No existing table is touched, so the server before the deploy keeps working on the migrated database. Whats-New: Make agents in your Profile: accounts for programs such as AI assistants, which sign in with a token and see only what you share with them. Whats-New-De: Leg in deinem Profil Agenten an: Konten für Programme wie KI-Assistenten, die sich mit einem Token anmelden und nur sehen, was du mit ihnen teilst. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-11 19:55:27 +01:00
export 'src/testing/fake_agent_gateway.dart';
feat(app,learn,todo): the assistants in Settings and on the operator's screen ADR 0021, step 2's app half. halkyon_app asks the module's assistant endpoints (ServerpodAssistantGateway, ServerpodAssistantOperatorGateway) and a person's own provider directly (halkyon_llm), behind AssistantRepository: an AssistantChoice is a GrantedAssistant, asked through the instance, which counts it, or a PersonalAssistant with the person's own key, which the instance never sees. assistant_messages.dart turns a conversation into the endpoint's models and back. AssistantsCard, for an app's settings: what is granted and left of its limits, agreed to once on a sheet saying what goes where, the person's use by UTC month, the instance's privacy page, and their own assistants where the operator allows own keys (kept ones stay listed, unasked, where it doesn't). AssistantGrantsCard on InstanceOperatorScreen: grants by handle with their limits in the pricing's unit, changed and taken back after asking, everyone's use by month; a found account's menu grants too. Nothing shows where nothing is offered or can be read. package:halkyon_app/assistant_models.dart holds the models in pure Dart. Learn keeps own assistants in the person's settings (ownAssistants, schema 12, SettingsOwnAssistants); SettingsRepository.update refuses (OwnAssistantRefused) to write a key where the settings would not be sealed (SettingsGateway.seals). Learn depends on halkyon_llm directly. Todo wires the gateways; a member offers no assistant. No feature asks an assistant yet (step 3). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-25 18:59:41 +01:00
export 'src/testing/fake_assistant_gateway.dart';
export 'src/testing/fake_auth_gateway.dart';
feat(todo,app): files attached to tasks and comments Halkyon's ADR 0043, D1, D3, D5 and D8: any file up to 100 MB, attached to a task's description or to a comment, sealed as everything of Todo's. Server: the attachment table, synced and sealed as the others, with the sealed file's hash readable for the store; todoFiles hands halkyon_base its rows, readable by their space's members, and takes sealed files alone; the files no attachment names go daily. Its tests hold downloads to the row's space, refuse a readable file and prune what no live row names. Migration attachments: CREATE TABLE "attachment" with its indexes and the foreign key to its space, cascading as every synced table's. App: AttachmentRepository seals each file for its row, keeps it sealed and opened in the person's folder, uploads it after each sync and fetches it as it shows, both held back by Without files on mobile data but for a file tapped. Under the description and a comment's text, a row of them: pictures as thumbnails opening full-size, other files as chips opening in the system's app, else saved; the paperclip beside the description and in the comment's composer adds them, the composer holding them until it is sent. A task deleted takes its files and its comments' along, a comment its own. halkyon_app opens a file in the system's app (FileOpener): on Android through its plugin and a FileProvider of its own class, sharing the cache's halkyon_opened/ folder alone; on the desktop as a file: URI. Whats-New: Attach files to a task's description or a comment with the paperclip: pictures show as thumbnails, other files open in their app. Whats-New-De: Hänge mit der Büroklammer Dateien an die Beschreibung einer Aufgabe oder an einen Kommentar: Bilder erscheinen als Vorschau, andere Dateien öffnen sich in ihrer App. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-11 01:17:22 +01:00
export 'src/testing/fake_file_opener.dart';
export 'src/testing/fake_file_picker.dart';
export 'src/testing/fake_instance_checker.dart';
feat(app,learn,todo): the operator's "This instance" card, screen and badge (ADR 0021, step 1) Whoever operates the instance approves, refuses and suspends accounts and names other operators in the app (D21 to D24, D34): - halkyon_app: InstanceOperatorRepository on ServerpodInstanceOperatorGateway (the module's instanceOperator endpoint; refusals as OperatorFailed: notFound, isOperator, lastOperator, notAllowed for 401 and 403, failed), in AppDependencies. OperatingCubit counts the accounts that wait: asked as the person's app opens, after every change, and every 5 minutes only while they operate the instance, so nobody else's app keeps asking. InstanceOperatorCard (or its tiles) and WaitingAccountsBadge show nothing at all for anyone else. InstanceOperatorScreen, laid out as Settings: the accounts that wait, each showing its four words to read out before Approve (D33), Refuse for new ones after asking; who operates, Take back after asking, the last always kept; Name an operator by handle; Find an account by the start of its handle, with Suspend after asking and Name as operator. English and German texts ("Admin" as the role word in German). - Learn: the card right after the Sync card in Settings, which the cogs' count leads to as their dot leads to Sync; the count on the Settings cogs of Home and Profile. - Todo: the tiles in the account sheet and the count on its button. Todo's server is a member, whose `operating()` is always null, so nothing shows there until it holds the register. Tests: the gateway's mapping, the repository, both cubits with their denials, the card, the badge and the screen; Learn's Settings shows the card and the count to an operator and neither to anyone else. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-25 15:55:28 +01:00
export 'src/testing/fake_instance_operator_gateway.dart';
feat(app,ui): sync waits on mobile data and asks first The developer's request of 10 Nov 2026, decided in ADR 0042: on mobile data every app holds its sync back, rows and files alike, and asks. halkyon_app becomes an Android plugin, its first native code, registered in every app by Flutter: HalkyonAppPlugin.java says which network the device is on and whether it is metered as Android has it (no NET_CAPABILITY_NOT_METERED: cellular, a phone's hotspot, Wi-Fi marked metered). Java, so it applies no Kotlin Gradle Plugin. MobileDataGate, one per device, holds the setting (Ask first, Sync without files, Sync everything; kept in <app support>/mobile_data.json), the network, and the person's answer, which holds until the device moves to another network or off a metered one. SyncService asks it before each sync: held back, nothing goes, the status counts what waits and asks; an answer or Wi-Fi syncs at once, and syncing now while held back is Sync now. Each app's frame shows the banner above every tab, in halkyon_ui's new NavigationFrame.banner slot (On mobile data · 3 changes waiting, with Not now, Without files and Sync now); the Sync card in Settings chooses the setting on a phone and says when files wait for Wi-Fi. Learn's files neither go up nor come down while held back. Whats-New: On mobile data the app no longer syncs by itself: a banner asks first, and Settings › Sync chooses whether to ask, sync without files, or sync everything. Whats-New-De: Mit mobilen Daten synchronisiert die App nicht mehr von selbst: Ein Hinweis fragt zuerst, und unter Einstellungen › Synchronisierung wählst du, ob sie fragt, ohne Dateien oder alles synchronisiert. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-10 23:38:17 +01:00
export 'src/testing/fake_network_watch.dart';
export 'src/testing/fake_oidc_browser.dart';
feat(app): sign in with a password and TOTP on the device ADR 0017, step 3: halkyon_app's side, which Learn and Todo take. - The account's cryptography on the device (`SodiumAccountCrypto`): halkyon_keys and SRP's client half, each step on an isolate of its own. sodium hands out results as views of native memory its finalizers free once the isolate that made them ends, so everything crossing back is copied first: a view read freed memory and crashed the process. - `PasswordGateway` on the module's endpoints (steps without a session through a client holding none; an authenticator set up with a session granted but not yet the device's), and `PasswordRepository` running the flows: signing in (M2 checked, the keys opened before anything is trusted), signing up, a password for someone signed in, an account never finished, the authenticators, recovery codes, changing the password, a new recovery phrase, and getting back in. - The unlocked keys in the system's keyring per instance and person (`SecureAccountKeyStore`), gone once another person signs in or nobody, and with the instance's removal. - The screens: the start screen's Sign in and Create an account (and when GitHub sign-in ends), the sign-in sheet (codes, recovery codes, an account never finished, a lost authenticator), the account's setup (the recovery phrase shown once, three random words typed back before anything reaches the instance; the authenticator's QR code, drawn with pub.dev's qr; the recovery codes), getting back in, and the account section (`AccountSecuritySection`). - `FileSaver` moves from Learn into halkyon_app, for the phrase and the codes in Todo too; `AppDependencies` names it and `passwords`. - halkyon_keys rebuilds account keys from the secret keys a device kept; the key proof's message is in halkyon_base_client, checked against the register's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-20 15:42:45 +02:00
export 'src/testing/fake_password_gateway.dart';
export 'src/testing/fake_public_profile_gateway.dart';
export 'src/testing/fake_screen_guard.dart';
export 'src/testing/fake_simplelogin_gateway.dart';
refactor(app): the device's speech recognition moves from Learn into halkyon_app, with dictation into a text Learn's `SpeechInput` and `DeviceSpeechInput` (ADR 0021, D67) are halkyon_app's now, and its `FakeSpeechInput` is in `testing.dart`, so Meditate's dream journal (ADR 0038, D15) listens through the same code. Learn imports them from there and behaves as before: its composer and its tests are unchanged but for the imports, and `DeviceSpeechInput()` asks for what it asked before. `DeviceSpeechInput` takes three options, off by default: - `preferOnDevice`: on Android, recognition on the device where it can (Android 12 on), else offline; should that fail before a word is heard (not a pause), it listens as Android otherwise does from then on. - `pauseFor`: how long a pause may last before the recogniser stops. - `listenFor`: how long one listen may last at most. `Dictation` writes what is heard where the cursor stands (`DictationInsertion`: in place of a selection, set apart by a space), shows the words so far, and listens again after each pause while it is on, stopping by itself after three listens running heard nothing. speech_to_text moves from Learn's pubspec to halkyon_app's, the lock unchanged. Todo, Train and Meditate link the plugin now; their generated plugin registrants (macOS, Windows) say so. An app declares the microphone itself, and Todo and Train declare none, so nothing there can listen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-03 14:41:07 +01:00
export 'src/testing/fake_speech_input.dart';
feat(app): sign in with a password and TOTP on the device ADR 0017, step 3: halkyon_app's side, which Learn and Todo take. - The account's cryptography on the device (`SodiumAccountCrypto`): halkyon_keys and SRP's client half, each step on an isolate of its own. sodium hands out results as views of native memory its finalizers free once the isolate that made them ends, so everything crossing back is copied first: a view read freed memory and crashed the process. - `PasswordGateway` on the module's endpoints (steps without a session through a client holding none; an authenticator set up with a session granted but not yet the device's), and `PasswordRepository` running the flows: signing in (M2 checked, the keys opened before anything is trusted), signing up, a password for someone signed in, an account never finished, the authenticators, recovery codes, changing the password, a new recovery phrase, and getting back in. - The unlocked keys in the system's keyring per instance and person (`SecureAccountKeyStore`), gone once another person signs in or nobody, and with the instance's removal. - The screens: the start screen's Sign in and Create an account (and when GitHub sign-in ends), the sign-in sheet (codes, recovery codes, an account never finished, a lost authenticator), the account's setup (the recovery phrase shown once, three random words typed back before anything reaches the instance; the authenticator's QR code, drawn with pub.dev's qr; the recovery codes), getting back in, and the account section (`AccountSecuritySection`). - `FileSaver` moves from Learn into halkyon_app, for the phrase and the codes in Todo too; `AppDependencies` names it and `passwords`. - halkyon_keys rebuilds account keys from the secret keys a device kept; the key proof's message is in halkyon_base_client, checked against the register's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-20 15:42:45 +02:00
export 'src/testing/memory_account_key_store.dart';
export 'src/testing/memory_account_wait_store.dart';
feat(app): sign in with a password and TOTP on the device ADR 0017, step 3: halkyon_app's side, which Learn and Todo take. - The account's cryptography on the device (`SodiumAccountCrypto`): halkyon_keys and SRP's client half, each step on an isolate of its own. sodium hands out results as views of native memory its finalizers free once the isolate that made them ends, so everything crossing back is copied first: a view read freed memory and crashed the process. - `PasswordGateway` on the module's endpoints (steps without a session through a client holding none; an authenticator set up with a session granted but not yet the device's), and `PasswordRepository` running the flows: signing in (M2 checked, the keys opened before anything is trusted), signing up, a password for someone signed in, an account never finished, the authenticators, recovery codes, changing the password, a new recovery phrase, and getting back in. - The unlocked keys in the system's keyring per instance and person (`SecureAccountKeyStore`), gone once another person signs in or nobody, and with the instance's removal. - The screens: the start screen's Sign in and Create an account (and when GitHub sign-in ends), the sign-in sheet (codes, recovery codes, an account never finished, a lost authenticator), the account's setup (the recovery phrase shown once, three random words typed back before anything reaches the instance; the authenticator's QR code, drawn with pub.dev's qr; the recovery codes), getting back in, and the account section (`AccountSecuritySection`). - `FileSaver` moves from Learn into halkyon_app, for the phrase and the codes in Todo too; `AppDependencies` names it and `passwords`. - halkyon_keys rebuilds account keys from the secret keys a device kept; the key proof's message is in halkyon_base_client, checked against the register's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-20 15:42:45 +02:00
export 'src/testing/memory_file_saver.dart';
export 'src/testing/memory_instance_store.dart';
export 'src/testing/memory_look_store.dart';
export 'src/testing/memory_pending_changes_store.dart';
export 'src/testing/memory_sign_in_addresses.dart';
export 'src/testing/memory_whats_new.dart';
export 'src/testing/test_app.dart';