Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions app/application.ml
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ let select_destination state destination =
;;

let feed_day_limit = 7
let sync_error_card_lifetime = Core.Time_ns.Span.of_sec 5.
let sync_error_card_lifetime = 5.

let initial_state =
{ favorites = Journal_routes.Favorites.create ~graph_generation:(-1)
Expand Down Expand Up @@ -5284,9 +5284,9 @@ let start
let startup_loading_key state = Journal_startup.Presentation.loading_request state.startup_presentation in
let prev_startup_loading_key = ref None in
let arm_startup_loading_timer key =
let started = Core.Time_ns.now () in
let started = Mtime_clock.counter () in
schedule_after 0.1 (fun () -> Effect.run (set_state (fun state ->
let elapsed = Core.Time_ns.(Span.to_sec (diff (now ()) started)) in
let elapsed = Mtime.Span.to_float_ns (Mtime_clock.count started) *. 1e-9 in
let next = Journal_startup.Presentation.step state.startup_presentation (Elapsed(key,elapsed)) in
if next == state.startup_presentation then state else {state with startup_presentation=next})))
in
Expand All @@ -5295,12 +5295,12 @@ let start
in
let prev_detail_loading_key = ref (detail_loading_key initial_state) in
let arm_detail_loading_timer graph_generation entry_id request_generation =
let started = Core.Time_ns.now () in
let started = Mtime_clock.counter () in
schedule_after 0.1 (fun () ->
Effect.run (set_state (fun state ->
if state.graph_state.generation <> graph_generation then state
else
let elapsed = Core.Time_ns.(Span.to_sec (diff (now ()) started)) in
let elapsed = Mtime.Span.to_float_ns (Mtime_clock.count started) *. 1e-9 in
let routes = Journal_routes.observe_loading_delay state.routes
~entry_id ~request_generation ~elapsed in
if routes == state.routes then state else { state with routes })))
Expand All @@ -5309,7 +5309,7 @@ let start
let arm_sync_error_timer sequence =
incr sync_error_timer_generation;
let generation = !sync_error_timer_generation in
schedule_after (Core.Time_ns.Span.to_sec sync_error_card_lifetime) (fun () ->
schedule_after sync_error_card_lifetime (fun () ->
if !sync_error_timer_generation = generation
then
send_action
Expand Down
3 changes: 1 addition & 2 deletions app/dune
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@
journal_symbols)
(libraries
rrbvec
base
core
mtime.clock
mldoc
lui
ocaml-signal
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Mtime Without Core

## Problem

Journal uses Jane Street Core only to measure two loading delays and express a five-second notification lifetime. The application needs monotonic elapsed time for the loading gates; calendar clock adjustments must not affect them. Core also remains a declared dependency and appears in two package locks.

## Proposal

Replace the two application elapsed-time measurements with `Mtime_clock.counter` / `Mtime_clock.count`, converting `Mtime.span` nanoseconds to floating-point seconds with `Mtime.Span.to_float_ns span *. 1e-9`. Keep the notification lifetime as `5.` seconds and keep the existing `Thread.create`, `Unix.sleepf`, pump delivery, running flag and generation checks. Do not use monotonic values as calendar timestamps.

The initially approved protected-file patch was extended by the user’s explicit Base-cleanup authorization. Its final scope is:

- `app/dune`: replace library `core` with `mtime.clock` and remove unused direct library `base`.
- `dune-project`: in the `logseq_journal` package, replace `(core (= v0.17.2))` with `(mtime (= 2.1.0))` and remove unused `(base (= v0.17.3))`.
- `logseq_journal.opam`: replace `"core" {= "v0.17.2"}` with `"mtime" {= "2.1.0"}` and remove unused `"base" {= "v0.17.3"}`.
- `logseq_journal.opam.locked` and `logseq_db_worker.opam.locked`: remove Core and 52 constraints belonging exclusively to its dependency closure, including Base, Stdio and unused Core PPX packages. The exact removed-name set and per-edge dependency evidence live in the task’s external `evidence/exact-dependency-closure.json`. Both already lock Mtime 2.1.0. Preserve all retained versions and every pin; do not prune unrelated stale constraints or compiler `base-*` pseudo-packages.

No `.mli`, `spec/`, other Dune file or dependency source edit is proposed. Update the existing temporary-notice source boundary assertion and exercise timing ownership through the existing public startup and route reducers. All temporary evidence stays outside the repository.

Initial investigation used main `fc27cfd62e7fede81185c7ec0bc8807fca797b52`. The parent confirmed PR90, PR91 and PR92 merged at main `87d0cccd0d65e77958a090d4181c7b9c9bd5fb94`. This isolated branch was fast-forwarded to that exact revision. The five protected dependency files have no changes between these two main revisions, and the six Core timing references remain the only application use. The updated journal-build producer-only instructions were read; the approved five-file patch and Base extension were implemented and validated after the resource window was released.

## Decision

Use Mtime counters for elapsed loading time and apply the approved five-file dependency patch plus the user-authorized Base cleanup in those same files. Keep all existing timer scheduling and owner fencing.

## Alternatives considered

### Keep wall-clock elapsed measurements

Rejected because adjusting system calendar time can change elapsed loading time. Mtime 2.1.0 is already locked and its public `mtime.clock` library supports counters directly.

### Rewrite scheduling or introduce a new timer abstraction

Rejected because this task only changes elapsed-time measurement and dependency identity. The existing public reducers own cancellation and stale-result fencing; changing scheduling would expand the behavioral scope.

### Remove similarly named packages or shared switch installations

Rejected. Jane Street Base, compiler `base-*` pseudo-packages and the project-specific `Core` modules, `melange-edn-core` and `melange-transit-core` are separate dependencies. Base itself is now authorized for removal after proving it is unused; retain the unrelated names. The old global switch contains outdated Mldoc metadata and is not evidence of the current pinned dependency graph. Do not modify another owner's switch or pins.

## Acceptance criteria

- Receive explicit approval for the exact dependency/Dune/lock patch before applying it; record the response and transition to proposed before changing other repository files.
- Recheck current main and use an isolated branch with no unrelated task changes. Do not push, open a PR, merge or install on an iPhone.
- Verify dependency removal first fails against the baseline and passes after implementation; retain the existing behavioral tests for the 100ms loading boundary, ready/completed/failed/retired owners, retry and graph generations, startup background interruption and fresh resume grace. Add only missing coverage at those public pure-owner boundaries.
- Build all source targets and run the complete test suite with the prepared locked switch after the parent releases the CPU/Simulator window. Follow the current journal-build entry point and provenance checks.
- Build baseline and changed Apps with the same target, configuration, toolchain and signing inputs, record exact hashes and sizes, inspect actual link inputs and Core symbols, and perform Simulator runtime checks without creating devices or changing private graphs.
- Verify the iPhoneOS target compiles/links and preserve any host-restamp ABI limitation. Host restamping is never proof of a complete cross-compiled OCaml ABI.
- Run spec-dev-tool check --all and report remaining limitations honestly, with no predicted 2.09MB saving claim.

## Risks

- Mtime 2.1.0 uses `mach_continuous_time` on Darwin, including system sleep. Startup's foreground event retires the previous serial and resume creates a fresh grace period. Detail owns no foreground reset; its existing owner and request generation checks continue to govern a callback delivered after suspension. Preserve these semantics.
- The current global switch's old Mldoc metadata requires Core, Core_bench and Core_unix. The verified task10 prepared switch has pinned Mldoc b3e06c and no installed package depending on Core; use that switch's recorded identity, not the stale global switch, for validation.
- Official opam direct-dependency queries at every exact installed package version show no Core or Base in the Journal or Worker production/build closure. Version-ambiguous recursive queries can traverse older recipes and give misleading Base chains. Current URI/IPaddr/Macaddr references to `ppx_sexp_conv` are upstream `with-test` dependencies; their runtime libraries and Journal’s Yojson PPX driver do not require Base. Remove only Core-exclusive constraints, preserving shared `sexplib0`, `sexplib`, `parsexp` and all other live build dependencies.
- PR92’s maintained producer-only route was used at the final main identity. iOS objects still use the explicit experimental host-restamp importer; record `cross_abi_validated=false` and do not infer a physical-device runtime result.

## Questions

- Approved. The parent relayed the human user’s explicit “允许” response to the exact five-file patch on 2026-10-17. No `.mli` or `spec/` edits are included.

## Authorization

The approved scope is `app/dune`, `dune-project`, `logseq_journal.opam`, `logseq_journal.opam.locked` and `logseq_db_worker.opam.locked` with only the replacements/deletions listed above. The original task authorizes the matching application implementation and relevant tests. The parent confirmed the Timeline performance experiment released the heavy-build/Simulator window at 09:17:40 UTC on 2026-10-17. Full tests and target builds are now authorized; only device 1446 may be used for isolated synthetic acceptance and its existing app/data must remain untouched.

## Base cleanup authorization

The parent relayed the human user’s explicit instruction: “如果能清理掉就清理,检查是不是依赖库依赖了base”. This authorizes removing the unused direct Base declarations in the same three files and handling the same two locks according to the real dependency closure, without upstream edits. No additional protected file is required. A Base-removal boundary test failed on all five existing declarations before removal.

## Validation progress

The approved implementation passes startup, route and source-boundary targeted tests, `dune build @all app/native_embed.exe.o` and full `dune runtest --force` with the original prepared switch, Release profile and two jobs. The candidate complete object has zero defined Core/Base symbols and retains Mtime/Mtime_clock. The new clone reuses the original CI pin-resolution record through a read-only ignored pointer; no pins, switch or producer proof was modified. Target App/link, size and bounded Simulator checks are recorded below.

## Consequences

### Core-only validation checkpoint

- Implementation commit `45f845cdd704ead5be09e6b79eca9810363daa50` changes six production/config/dependency files and three existing test files. No `.mli`, `spec/`, upstream source or scheduling change was made.
- Dependency-boundary checks failed before Core/Base removal and passed afterwards. Targeted startup/routes/source-boundary tests, the complete source build and full test suite passed with Release profile and the original prepared switch. The final source verification was run once; subsequent changes are documentation only.
- The native link command now uses 85 `.cmxa` archives instead of 136 and has no Core/Base archive input. Candidate Simulator and iPhoneOS binaries each contain zero Core/Base defined or undefined symbols. Installed Core/Base packages in the shared switch were not uninstalled and are not evidence of final retention.
- Baseline `87d0ccc` and candidate `45f845c` built in the same absolute source path with identical Release, SDK, deployment, compiler, Swift/LUI and signing inputs. Simulator executable bytes changed from 38,023,216 to 29,622,656; App file bytes changed from 39,884,448 to 31,483,888. iPhoneOS executable bytes changed from 38,089,744 to 29,672,768; App file bytes changed from 39,975,900 to 31,558,924. These are actual signed-file sizes, not compressed download sizes or independent Core-versus-Base attribution estimates.
- Both target pairs report `status: built`. Target C/Swift compilation, platform/provider/link-map checks and signatures passed. They remain experimental host-restamp builds with `cross_abi_validated=false`; a validated OCaml iPhoneOS cross toolchain/ABI and physical-device runtime acceptance remain unavailable. Nothing was installed on an iPhone.
- The actual production candidate Simulator App launched to native Logseq sign-in. The independent synthetic warm-start probe did not reach Capture/detail: diagnostics remained Loading catalog / Graph Closed. A control with the same Swift host and initial generated fixture linked to baseline `87d0ccc` reproduces persistent Loading and fetch-catalog start. The root cause is not established; detail and foreground-resume UI acceptance are explicitly incomplete. No product workaround was added, and this task did not expand into fixing that fixture.
- On release, 1446’s original scroll-top bundle was restored and its executable plus all 18 data-file hashes remained unchanged. Two Simulator devices remain; A135 and private graphs were untouched. All task build/test/sampling work stopped before handoff.
- Independent read-only session `01a1493a-75ec-7e93-ad28-1d6045a13b3a` used journal-code-review on `87d0ccc..45f845c` and found no evidence-backed issue. It separately confirmed the UI/ABI limitations and performed no build, test or Simulator operation.
- The task document validates. Full decision-document validation still reports three unchanged historical documents missing required sections; no unrelated documentation repair was made. No push, PR or merge was performed.

External task evidence includes `completion-report.txt`, `final-artifact-comparison.json`, `target-builds.json`, `targeted-tests.json`, `full-checks.json`, `exact-dependency-closure.json`, `simulator-acceptance.json`, `1446-original-fixture-preserved.json` and `independent-review.txt`.


## PR publication scope and evidence

On 2026-10-17 the user explicitly requested publishing the Core cleanup PR as a regular, non-draft PR. This
supersedes the initial no-push/no-PR restriction for this branch only; no merge or
physical iPhone installation is authorized. The fetched latest main is still
`87d0cccd0d65e77958a090d4181c7b9c9bd5fb94`, so no source rebase or rebuild is needed.
The final PR contains only Core/Mtime and the authorized unused Base cleanup,
three existing test files and this decision document. Every non-Markdown source,
test and dependency input remains identical to verified implementation `45f845c`.

Core-only full build and forced tests passed: 21 Alcotest suites and 907 cases,
with 115 named running checks reported separately. The Core-only target receipts
and measured sizes above remain applicable; later documentation commits do not
change their native inputs. Detailed records remain in external `full-checks.json`,
`full-checks.log`, `target-builds.json` and `final-artifact-comparison.json`.

The later local-restoration repair is preserved only on the separate local branch
`codex/fix-local-restore-auth-order-20261017` at `e5b9b2b`; none of its production
changes, Application tests or decision document belongs to this PR. Its 915-case
suite and successful encrypted startup/detail/foreground UI acceptance are not
validation results for this Core-only branch. Core-only production Simulator
sign-in succeeded, but synthetic detail and resume acceptance remains incomplete
as documented at the checkpoint. The initial fixture and baseline restoration
issues were investigated separately; this PR does not repair them.

Publishing reuses verified evidence without another heavy build or Simulator run,
preserving the current Timeline performance resource window. A fresh independent
journal-code-review session must review the published PR's final head and scope.
3 changes: 1 addition & 2 deletions dune-project
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,7 @@
(logseq_sync (= 0.1.0))
(lui (= 0.1.0))
(ocaml-signal (= 0.1.0))
(base (= v0.17.3))
(core (= v0.17.2))
(mtime (= 2.1.0))
(datascript_ocaml (= dev))
(datascript-ocaml-native (= dev))
(melange-edn-core (= 0.5.0))
Expand Down
53 changes: 0 additions & 53 deletions logseq_db_worker.opam.locked
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ depends: [
"angstrom" {= "dev"}
"asn1-combinators" {= "0.3.3"}
"astring" {= "0.8.5"}
"base" {= "v0.17.3"}
"base-bigarray" {= "base"}
"base-bytes" {= "base"}
"base-domains" {= "base"}
Expand All @@ -20,20 +19,15 @@ depends: [
"base-threads" {= "base"}
"base-unix" {= "base"}
"base64" {= "3.5.2"}
"base_bigstring" {= "v0.17.0"}
"base_quickcheck" {= "v0.17.1"}
"bigstringaf" {= "0.10.0"}
"bin_prot" {= "v0.17.0-1"}
"bos" {= "0.3.0"}
"ca-certs-nss" {= "3.126"}
"capitalization" {= "v0.17.0"}
"cmdliner" {= "2.1.1"}
"compiler-cloning" {= "disabled"}
"conf-gmp" {= "5"}
"conf-gmp-powm-sec" {= "4"}
"conf-pkg-config" {= "5"}
"conf-sqlite3" {= "1"}
"core" {= "v0.17.2"}
"cppo" {= "1.8.0"}
"csexp" {= "1.5.2"}
"cstruct" {= "6.2.0"}
Expand All @@ -53,10 +47,8 @@ depends: [
"eqaf" {= "0.10"}
"ezjsonm" {= "1.3.0"}
"faraday" {= "0.8.2"}
"fieldslib" {= "v0.17.0"}
"fmt" {= "0.11.0"}
"fpath" {= "0.7.3"}
"gel" {= "v0.17.0"}
"gen" {= "1.1"}
"gluten" {= "0.5.2"}
"gluten-eio" {= "0.5.2"}
Expand All @@ -67,14 +59,11 @@ depends: [
"httpun-eio" {= "0.2.0"}
"httpun-types" {= "0.2.0"}
"httpun-ws" {= "0.2.0"}
"int_repr" {= "v0.17.0"}
"iomux" {= "0.4"}
"ipaddr" {= "5.6.2"}
"jane-street-headers" {= "v0.17.0"}
"js_of_ocaml" {= "6.4.1"}
"js_of_ocaml-compiler" {= "6.4.1"}
"jsonm" {= "1.0.2"}
"jst-config" {= "v0.17.0"}
"kdf" {= "1.1.1"}
"logs" {= "0.10.0"}
"logseq_db_storage" {= "0.1.0"}
Expand Down Expand Up @@ -107,54 +96,17 @@ depends: [
"ocaml-compiler-libs" {= "v0.17.0"}
"ocaml-options-vanilla" {= "1"}
"ocaml-syntax-shims" {= "1.0.0"}
"ocaml_intrinsics_kernel" {= "v0.17.2"}
"ocamlbuild" {= "0.16.1"}
"ocamlfind" {= "1.9.9~preview"}
"ocplib-endian" {= "1.2"}
"ohex" {= "0.2.0"}
"optint" {= "0.3.0"}
"parsexp" {= "v0.17.0"}
"persistent_sorted_set_ocaml" {= "dev"}
"ppx_assert" {= "v0.17.0"}
"ppx_base" {= "v0.17.0"}
"ppx_bench" {= "v0.17.1"}
"ppx_bin_prot" {= "v0.17.1"}
"ppx_cold" {= "v0.17.0"}
"ppx_compare" {= "v0.17.0"}
"ppx_custom_printf" {= "v0.17.0"}
"ppx_derivers" {= "1.2.1"}
"ppx_deriving" {= "6.2.0"}
"ppx_deriving_yojson" {= "3.10.0"}
"ppx_diff" {= "v0.17.1"}
"ppx_disable_unused_warnings" {= "v0.17.0"}
"ppx_enumerate" {= "v0.17.0"}
"ppx_expect" {= "v0.17.3"}
"ppx_fields_conv" {= "v0.17.0"}
"ppx_fixed_literal" {= "v0.17.0"}
"ppx_globalize" {= "v0.17.2"}
"ppx_hash" {= "v0.17.0"}
"ppx_here" {= "v0.17.0"}
"ppx_ignore_instrumentation" {= "v0.17.0"}
"ppx_inline_test" {= "v0.17.1"}
"ppx_jane" {= "v0.17.0"}
"ppx_let" {= "v0.17.1"}
"ppx_log" {= "v0.17.0"}
"ppx_module_timer" {= "v0.17.0"}
"ppx_optcomp" {= "v0.17.1"}
"ppx_optional" {= "v0.17.0"}
"ppx_pipebang" {= "v0.17.0"}
"ppx_sexp_conv" {= "v0.17.1"}
"ppx_sexp_message" {= "v0.17.0"}
"ppx_sexp_value" {= "v0.17.0"}
"ppx_stable" {= "v0.17.1"}
"ppx_stable_witness" {= "v0.17.0"}
"ppx_string" {= "v0.17.0"}
"ppx_string_conv" {= "v0.17.0"}
"ppx_tydi" {= "v0.17.1"}
"ppx_typerep_conv" {= "v0.17.1"}
"ppx_variants_conv" {= "v0.17.1"}
"ppxlib" {= "0.38.0"}
"ppxlib_jane" {= "v0.17.4"}
"psq" {= "0.2.1"}
"ptime" {= "1.2.0"}
"rrbvec" {= "dev"}
Expand All @@ -163,22 +115,17 @@ depends: [
"seq" {= "base"}
"sexplib" {= "v0.17.0"}
"sexplib0" {= "v0.17.0"}
"splittable_random" {= "v0.17.0"}
"sqlite3" {= "5.4.0"}
"stdio" {= "v0.17.0"}
"stdlib-shims" {= "0.3.0"}
"stringext" {= "1.6.0"}
"thread-table" {= "1.0.0"}
"time_now" {= "v0.17.0"}
"tls" {= "2.1.2"}
"tls-eio" {= "2.1.2"}
"topkg" {= "1.1.1"}
"typerep" {= "v0.17.1"}
"uri" {= "4.4.0"}
"uucp" {= "17.0.0"}
"uunf" {= "17.0.0"}
"uutf" {= "1.0.4"}
"variantslib" {= "v0.17.0"}
"x509" {= "1.1.1"}
"yojson" {= "3.0.0"}
"zarith" {= "1.14"}
Expand Down
Loading
Loading