feat: deliver portable Flect foundation - #30
Open
robinbraemer wants to merge 17 commits into
Open
Conversation
…cle, and release notes
…eptance boundaries
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Intent
Establish Flect's canonical user-quality and proof model, make it mandatory agent context without duplicating its source of truth, baseline every user-important outcome against observable evidence, and deliver the implemented portable product foundation. The change must preserve Effect as the application and UI-shaping architecture; keep Guardian, accepted App Agent, Preview App Agent, and Shaper trust domains separate; provide browser-portable OPFS/Git, sandboxed Bash/Bun, capsule, extension, product-capability, sharing, import, authentication, recovery, accessibility, performance, AXI/CLI/MCP, and native-host behavior through shared typed controllers; keep external control opt-in and credentials private; document ownership without duplicate sources of truth; include the T3Code-inspired composer and high-quality Markdown/activity UX; ship truthful README/release media and product SDK/reference examples; and preserve deterministic safe-mode, acceptance, rollback, and offline recovery. Robin explicitly instructed the agent to continue unattended, not ask for approval during PR work, close completed issues, and deliver to main only after complete real-browser, native, documentation, and no-mistakes verification.
What Changed
Risk Assessment
Testing
Build, targeted controller/broker tests, product-quality coverage, and the production Chromium Shape–Use journey were exercised; visual evidence was captured and generated worktree artifacts were removed.
/var/folders/1y/cjgf53nj31n_dxsspqnjfjvc0000gn/T/no-mistakes-evidence/01KZ3PK1KQ03602VMVTMWQH4XZ/flect-shaper-workbench-harness.png)/var/folders/1y/cjgf53nj31n_dxsspqnjfjvc0000gn/T/no-mistakes-evidence/01KZ3PK1KQ03602VMVTMWQH4XZ/flect-shaper-ready-harness.png)Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
🔧 **Review** - 13 issues found → auto-fixed (8) ✅
server/control-broker.ts:454- Duplicate command IDs overwrite the first pending Deferred. Two concurrent submissions with the same ID leave one request waiting forever and can misroute completion; reject duplicates or share the existing waiter at this broker boundary.server/control-broker.ts:292- Revocation appends a sentinel after already queued commands, so a blockednextCommandcan still receive and execute a queued command after control is disabled. Drain/reject queued commands at the broker revocation boundary.server/control-broker.ts:320- The broker state is published before the descriptor is persisted. If descriptor creation fails, status remains enabled with no discoverable bearer or descriptor. Persist first or roll back the in-memory grant on failure.src/lib/workspace-control-bridge.ts:132- Non-disable commands are forked without tracking their fibers. Disabling control only fails pending waiters; an already running command continues mutating workspace state after revocation. Track and interrupt active command fibers at the shared revocation boundary.src/lib/workspace-control-bridge.ts:138- Reconcile failures are swallowed while the controller snapshot remains enabled. A failed enable/disable can leave the bridge permanently out of sync and with no later state change to retry. Preserve the failure and retry or explicitly restore the controller state.src/shell/persistent-workspace-fs.ts:240- Role filesystem mutators update the in-memory mirror before OPFS and do not restore it when persistence fails; the replacement path also snapshots the new tree outside its rollback block. A failed write can appear successful in the current turn and disappear on reload. Use one transactional mutation helper for all mutators.src/capabilities/product-capability-registry.ts:137- A product reservation is validated for scope but its current decision lifecycle is not rechecked beforeexecute. Revocation or expiry betweenreserve/authorization and execution still reaches the product adapter, despiteinspectReservationenforcing this invariant elsewhere.src/capabilities/product-capability-broker.ts:196- Decision-store load warnings are discarded at broker initialization and during contextual loading. Corrupt or unavailable durable grants therefore fail closed silently instead of surfacing the required recoverable warning in the protected interface.src/lib/runtime.ts:300- The authoritative intent requires “provide ... extension ... behavior through shared typed controllers,” but the live capability adapter implementssetTextas a no-op. Portable extensions can pass capability checks and report successful intents while producing no interface change; wire this to the controller or return an explicit unsupported result.src/sharing/share-repository.ts:387-acceptCandidateperforms three guarded ref mutations without rollback. If the second move or final removal fails after the first move succeeds, the installation is left with inconsistent refs and later Keep/Reject operations can be permanently stale. Add an atomic/journaled repository acceptance boundary with compensation.src/lib/workspace-controller.ts:1641- Keep promotes the extension catalog and finalizes share state beforekernel.acceptpersists the canonical revision. A storage failure atkernel.acceptleaves durable extension/share state accepted while the shaping proposal remains pending, violating candidate/accepted separation. Commit through one acceptance transaction or journal and compensate side effects on failure.src/lib/workspace-controller.ts:790- Capsule presentation state is updated in memory and then capsule persistence errors are swallowed. Durable OPFS quota or write failures can therefore lose accepted/candidate capsule bindings on reload without exposing the required actionable recovery or export path.src/lib/workspace-controller.ts:4746- Failed commands are recorded in the journal but never replace the cached accepted receipt. A retry with the same command ID is returned as a successful duplicate even though the original command failed, contradicting idempotent “original result” semantics. Define and cache a terminal failure receipt or retain an explicit pending result.🔧 Fix: Harden control, persistence, capability, and acceptance boundaries
7 issues (6 errors, 1 warning) still open:
src/lib/workspace-control-bridge.ts:172- A normal command is forked before its fiber is registered. If a disable command is consumed before registration, revocation sees no active fiber and the command can mutate workspace state after disable. Register work atomically with dispatch or serialize the boundary.src/lib/workspace-control-bridge.ts:207- Direct control revocation shuts down the broker, but the bridge only catches the resulting polling error and never interrupts tracked commands or clears its enabled state. Route broker revocation through a shared signal that interrupts active fibers and reconciles the bridge.src/capabilities/product-capability-broker.ts:712-withReservationexecutes arbitrary product I/O while holding the broker's synchronized state lock. A slow or hung adapter blocks revocation, expiry checks, and all other capability operations. Move execution outside the lock while preserving a bounded lease/version or cancellation boundary.src/lib/runtime.ts:300- The intent requires “provide ... extension ... behavior through shared typed controllers,” but the live adapter rejects every approvedset-textintent as unsupported. Enabled portable extensions therefore cannot change interface state. Confirm whether this containment is explicitly authorized; otherwise wire the adapter to the controller boundary.src/lib/workspace-controller.ts:1568- Terminal share transitions still have partial-commit paths: Keep mutates Git refs before installation persistence, so a save failure occurs before rollback metadata exists; later rollback can also delete the old source archive without restoring it. Reject has the same ref-before-store ordering, andrestoreCandidateis itself an uncompensated multi-ref sequence. Use a journaled or compensating repository boundary covering all pre-state and archives.src/lib/workspace-controller.ts:1806-kernel.acceptcommits the canonical revision beforeupdateCapsulePresentationpersists capsule state. A capsule-store failure therefore returns a failed command after acceptance is durable, leaving stale bindings and no proposal to retry; reject and rollback use the same ordering. Include capsule persistence in the transition journal or return an explicit degraded recovery result.src/lib/workspace-controller.ts:739- Capsule load corruption or I/O failures are caught and replaced with{}while the snapshot still reports the configured durable store. Restart can silently lose accepted/candidate capsule, extension, and permission-review state. Surface the failure as degraded persistence or restore a known-good binding.🔧 Fix: Harden revocation, leases, and transactional acceptance
9 issues (6 errors, 3 warnings) still open:
src/lib/workspace-control-bridge.ts:103- AllrunNextand snapshot-publication failures are treated as confirmed revocation. A transient transport outage therefore dispatches local disable and permanently turns control off instead of retrying. Distinguish broker revocation from temporary unavailability.src/lib/workspace-control-bridge.ts:85- Revocation swallowstransport.disablefailures and then clearsenabled. If the broker is still live during a transient failure, its descriptor/token remain active while the bridge stops consuming commands. Only clear local state after confirmed cleanup or keep retrying.src/capabilities/product-capability-broker.ts:694- The expiry timestamp is read before acquiring the synchronized broker state. Waiting on the lock can let the decision expire before validation, while the stale timestamp still registers a lease and executes the product operation. Read time inside the synchronized validation boundary.src/lib/runtime.ts:424- The intent requires “provide ... extension ... behavior through shared typed controllers,” but the adapter callsShapingKernel.proposedirectly with no extension ID, role, binding, controller authorization, or operation evidence. Candidate-bound calls can therefore propose against the active document, and the shared controller workflow is bypassed.src/lib/runtime.ts:424-SandboxResultpermits up to 20 intents, but eachset-textintent independently callskernel.propose. The first intent creates a proposal; the second sees that proposal and fails, leaving a partial revision while the extension call reports failure. Validate and commit the batch atomically through the controller boundary.src/extensions/portable-extension-host.ts:353-PortableExtensionHost.callrecords only denied-capability and sandbox failures. Live adapter failures, including unsupported or partially applied interface intents, do not increment the extension failure count or trigger bounded disable behavior. Route all execution failures through the catalog failure policy.src/lib/workspace-controller.ts:1841- Keep finalizes shared state before capsule persistence, butfinalizedShareis only available to the innerkernel.acceptcatch. If capsule persistence fails at line 1841, the outer catch restores withundefined, leaving share refs/install state accepted while the kernel proposal remains pending. Preserve transaction metadata through every post-side-effect failure and compensate all stores.src/lib/workspace-controller.ts:1892- Reject persists extension-catalog removal before capsule and kernel rejection. If either later step fails, no extension snapshot is restored, leaving the candidate catalog cleared while the proposal remains. Capture and restore extension, capsule, and share pre-state around the entire reject transition.src/lib/workspace-controller.ts:1630- Successful Keep and Reject no longer remove obsolete share archives. The content-addressed candidate store has no listing or garbage collection, so repeated updates/imports accumulate unreferenced OPFS data and can eventually exhaust storage. Clean up only after commit with reference-aware retention.🔧 Fix: Harden control, extensions, and share transitions
3 issues (1 error, 2 warnings) still open:
src/lib/runtime.ts:385- Kernel state conflicts and persistence failures are all mapped toCapabilityAdapterFailure, then recorded as extension execution failures. Invoking an accepted extension while a proposal is active can therefore mark a healthy extension failed; preserve typed conflict/persistence errors and only record package failures for actual extension faults.src/extensions/portable-extension-host.ts:360- The kernel proposal is applied beforecatalog.recordSuccesspersists the extension test result. If catalog persistence fails, the command fails after creating a proposal, leaving shaping state and tested/catalog state inconsistent. Commit these effects transactionally or expose an explicit recoverable degraded result.src/lib/workspace-controller.ts:1801- The authoritative intent requires “preserve deterministic safe-mode, acceptance, rollback, and offline recovery.” The changed acceptance/rejection handlers restore capsule state, extension state, and shared refs sequentially; if an early restore fails, later compensations are skipped, leaving the proposal and durable stores inconsistent. Use a durable journal/transaction or an explicit degraded-recovery marker covering the whole transition.🔧 Fix: Preserve typed extension errors and degraded recovery
2 errors still open:
src/lib/workspace-controller.ts:1636- Keep/Reject can still strand shared Git state: if installation persistence fails and its nested ref rollback also fails,finalizeShareActivation/discardShareActivationthrow before returning pre-state, so outer compensation receivesundefinedand cannot restore refs or enter degraded recovery. Preserve transaction metadata through nested rollback failures at the shared transition boundary.src/lib/workspace-controller.ts:1780- The required criterion is “preserve deterministic safe-mode, acceptance, rollback, and offline recovery.”enterDegradedRecoveryswallowskernel.enterSafeModefailure at line 1780 and only updates in-memory state; if the same interface-store outage prevents durable safe-mode persistence, reload can restore a pending proposal while other stores remain partially compensated. Persist a durable recovery marker/journal that startup honors.🔧 Fix: Preserve rollback metadata and durable recovery markers
3 errors still open:
src/lib/workspace-controller.ts:1572- Keep still loses rollback metadata whenshareRepository.acceptCandidatepartially mutates refs and its own rollback fails: metadata is recorded only afteracceptCandidatereturns at line 1587. The outer compensation then receivesundefined, cannot restore the refs, and does not enter degraded recovery. Record the transaction pre-state before the repository mutation or make the repository boundary return recoverable transaction metadata.src/lib/shaping-kernel.ts:713- The required criterion is “preserve deterministic safe-mode, acceptance, rollback, and offline recovery.” When safe-mode persistence fails,markRecoveryfailure is swallowed at line 713; only in-memory state becomes safe, so a later reload after storage recovers can restore the old pending proposal without a durable recovery marker. Make recovery marking durable before the risky transition or provide a boot-visible fallback marker.src/lib/shaping-kernel.ts:759- The required criterion is “preserve deterministic safe-mode, acceptance, rollback, and offline recovery.” The three-failure recovery path inrecordExtensionFailurepersists a safe-mode state directly at line 759 but never callsmarkRecovery; if that persistence fails, the state transition is discarded and repeated extension failures never establish durable safe mode. Route threshold recovery through the shared recovery-marker boundary.🔧 Fix: Preserve pre-mutation rollback and durable recovery markers
2 errors still open:
src/lib/workspace-controller.ts:1579-finalizeShareActivationrecords post-accept refs beforeacceptCandidateruns. If a ref move fails after the repository’s own rollback succeeds, outer compensation still tries to restore from the expected post-accept state, fails its guards, and unnecessarily enters degraded recovery. Return rollback status from the repository boundary or make compensation recognize already-restored pre-state.src/lib/workspace-controller.ts:1802- The required criterion is “preserve deterministic safe-mode, acceptance, rollback, and offline recovery.”enterSafeModenow aborts before updating in-memory state whenmarkRecoveryfails, whileenterDegradedRecoverydiscards that failure at line 1802. A marker-write failure can therefore leave a pending, non-safe workspace and later reload the partial state. Preserve local safe mode while surfacing the durable-marker failure or provide an independent boot-visible recovery marker.🔧 Fix: Preserve rollback status and local safe-mode recovery
1 error still open:
src/lib/shaping-kernel.ts:762- The required criterion is “preserve deterministic safe-mode, acceptance, rollback, and offline recovery.” At the third extension failure,markRecoveryis a hard prerequisite; if marker creation fails, the state transition is aborted, so the extension is not disabled and safe mode is not entered. Apply the local safe-mode transition even when marker persistence fails, while surfacing degraded recovery.🔧 Fix: Preserve safe mode when recovery marker writes fail
✅ Re-checked - no issues remain.
🔧 **Test** - 1 issue found → auto-fixed ✅
src/lib/workspace-controller.ts:751-bun run buildfails during TypeScript compilation with errors inworkspace-controller.tsand typed test doubles. This prevents the standard Playwright production workflow from starting and must be fixed before release verification.bun run check:qualitybunx vitest run scripts/product-quality-coverage.test.tsbunx vitest run src/lib/workspace-controller.test.ts -t 'answers Use questions and applies only a typed edit-tool handoff|uses an explicit warm Shape and candidate Use workbench|rejects stale failure handoffs and injects only correlated evidence|routes user and outside commands through one idempotent state machine|rejects stale sequences and outside attempts to enable control|enforces the role-scoped agent command policy before claim|creates a preview from Shaper and accepts it through typed commands|does not let a stale kernel event re-enter safe mode after restore|keeps unsent drafts reactive and outside public snapshots'bunx vitest run src/components/agent-rail.test.tsx src/components/composer.test.tsx src/components/message-content.test.tsx src/components/activity-card.test.tsx src/components/role-aware-shell.test.tsxbunx vitest run src/lib/workspace-control-bridge.test.ts server/control-broker.test.ts server/control-descriptor.test.ts server/mcp-adapter.test.tsbunx vitest run src/axi/command.test.ts src/axi/program.test.ts src/axi/output.test.tsbunx vitest run src/lib/operation-journal.test.ts src/lib/role-continuity.test.ts src/lib/shaping-kernel.test.tsbun run buildbunx vite buildchrome-devtools-aximanual flow: shape → candidate Use → Markdown showcase → Safe mode → Restore interfacechrome-devtools-axi consolechrome-devtools-axi network🔧 Fix: Fix build type errors and affected test doubles
✅ Re-checked - no issues remain.
bun run buildbunx vitest run src/lib/workspace-control-bridge.test.ts src/lib/workspace-controller.test.ts src/lib/runtime.test.ts src/sandbox/capability-broker.test.ts src/capabilities/product-capability-registry.test.tsbun run check:qualitybunx playwright test tests/e2e/flect.spec.ts --project=chromium -g "tests a candidate, returns to Shape"Production browser navigation and visual screenshots of App Agent and Shaper states viabrowser-harness✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.