Files
Marcos Paulo e8c8c06d1e
ci / ci (macos-latest) (push) Has been cancelled
ci / ci (ubuntu-latest) (push) Has been cancelled
ci / ci (windows-latest) (push) Has been cancelled
feat: smart folder model, media time fragments, link card URL guard (MiniMax); specs for 10 more gaps (Codex) and the registry with bloat measurements
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-21 14:41:26 -03:00

9.6 KiB

Tasks: web clipper (roadmap 33)

One task = one bounded implementation handoff. Spec: spec.md; rules: AGENTS.md, docs/CODE-MAP.md. Paths marked new do not exist yet. Tasks run in order; each leaves its own testable result. Later implementation owns code paths listed below; this documentation run writes only specs/plugins-parity/.

First tool call rule: batch at most three relevant reads in first tool call; write first OWNS file in SECOND tool call (compiling stub plus one failing test), then implement and pass that test. Do not spend second call exploring. For docs-only task, write first OWNS document in second call and validate its acceptance checklist. Standing VERIFY (future implementation only): export PATH="$HOME/.cargo/bin:$PATH"; cargo test -p <package>; cargo clippy -p <package> --all-targets -- -D warnings; rustfmt --edition 2024 <owned Rust files>; UI tasks add cargo xtask i18n and read snapshot PNGs; final integration adds cargo xtask layers, cargo xtask tree, cargo xtask ci. Stop on failure; never bypass checks. Standing DO NOT: edit outside OWNS, change Git state, commit, use cargo fmt --all, add unapproved dependency, modify craft-libs API, use unsafe/panics/input indexing, write disk outside atomic Vault/Session/settings APIs, hardcode UI strings. Parent module declarations/test harnesses must be owned explicitly.

Phase 1 — pure contract

  • 1. Versioned envelope and validation (brief briefs/20-web-capture-envelope.md). OWNS: crates/engine/src/capture/web_model.rs (new, first write), crates/engine/src/capture/mod.rs (module declaration only). FILES TO OPEN: specs/plugins-parity/web-clipper/spec.md D1, crates/engine/src/capture/rules.rs, crates/engine/src/capture/mod.rs. GOAL: WebCapture::parse(&str) -> Result<Self, CommandError>, validated metadata/assets and normalized capture target; named caps from D1; decoded signatures/duplicate ids/placeholder validation; pure function, no IO. Keep result type crate-private and tests local. Use existing base64 decoder, no added dependency. TESTS: roundtrip minimal envelope; unknown version/fields; exact byte caps/+1; UTF-8 size; bad source/credentials; traversal/reserved paths; duplicate/missing asset ids; bad base64/MIME/signature; no replacement inside code; empty capture; valid PNG/JPEG fixtures. VERIFY: standing -p notescraft-engine, cargo test -p notescraft-engine capture::web_model passes all named cases. DO NOT: register commands, save assets, open listener, convert arbitrary HTML or add htmlmd dependency.

Phase 2 — engine save semantics

  • 2. Preview/save, local assets and retry identity. Depends on 1 and owner Q3 decision. OWNS: crates/engine/src/capture/web.rs (new, first write), crates/engine/src/capture/mod.rs, crates/engine/src/capture/rules.rs (shared capture execution only), crates/engine/src/vault/session.rs (bounded replay state only), crates/engine/src/commands.rs, crates/engine/src/ai/assistant_gate.rs, crates/engine/tests/core_commands.rs, crates/engine/tests/web_capture.rs (new); crates/engine/Cargo.toml ONLY if owner Q3 approves existing workspace sha2 usage. FILES TO OPEN: spec D1-D2, crates/engine/src/capture/mod.rs, crates/engine/src/vault/attachments.rs, crates/engine/tests/capture.rs, crates/engine/tests/common/mod.rs. GOAL: two D2 commands, shared existing capture executor, attachment destination span rewrite; preflight before writes; replay ledger 128 ids/digests/results; explicit partial_capture path report. Do not promise transactional multi-file save. TESTS: TempVault preview zero writes; text+PNG emits local embed; Daily dirty buffer and undo; Inbox collisions; same-id replay once; changed-id payload conflict; ledger eviction at 129 entries; retry_only unknown/evicted id zero writes; bad asset no writes; injected later write failure lists only new assets; read-only; existing note.capture tests remain passing. VERIFY: standing engine plus --test web_capture --test capture --test core_commands. DO NOT: network fetch, overwrite existing files, delete orphaned assets automatically, change NDJSON limit, add a new crate.

Phase 3 — loopback transport

  • 3. HTTP bridge owned by control lifecycle. Depends on 2; existing axum/tokio approved, no new dependency proposal. OWNS: crates/engine/src/control/capture_http.rs (new, first write), crates/engine/src/control/mod.rs, crates/engine/src/control/server.rs, crates/engine/src/control/pump.rs, crates/engine/src/control/protocol.rs, crates/engine/src/control/token.rs, crates/engine/Cargo.toml (existing workspace axum/tokio), Cargo.lock (resolved approved workspace dependencies only), crates/engine/tests/web_capture_http.rs (new). FILES TO OPEN: spec D3, crates/engine/src/control/server.rs, crates/engine/src/control/pump.rs, crates/engine/src/control/protocol.rs, crates/engine/tests/control.rs, apps/notescraft-sync-server/Cargo.toml (existing approved HTTP framework). GOAL: separate HTTP loopback listener, same control pump/registry dispatch, optional descriptor field; explicit local enable/token rotation API using fallible OS CSPRNG (no RandomState fallback); capture-only auth and exact origin/Host gates; fixed body/header/connection/inflight/deadline limits. Existing NDJSON payload cap/protocol untouched. Extend Job with expiry so skipped-before-execution jobs do not mutate after timeout. Reuse framework HTTP parsing. TESTS: raw HTTP/axum tests: no bind disabled; POST preview/save/replay with explicit envelope-to-command wrapping and retry-only header; arbitrary route/command refused; token separation, wrong Host, null/foreign origin, preflight, missing bearer, oversized body/header; queued expiry zero writes; drop/disable shuts listener; RNG failure leaves listener disabled; Unix token source and unsupported Windows status until Q5 approval; slow client/flood bounded; old NDJSON control tests pass. VERIFY: standing engine, --test web_capture_http --test control --test control_client; cargo xtask layers, cargo xtask tree. DO NOT: expose control token, log payload, permit wildcard CORS or LAN, allow page origins, implement handwritten HTTP parser, change workspace registrations (no new crate). Windows bridge is blocked on Q5; before any approved RNG dependency addition, amend OWNS to include root Cargo.toml and Cargo.lock plus engine manifest. Unix-only transport can proceed without it.

Phase 4 — import and pairing UI

  • 4. Explicit settings, pairing and clipboard-envelope preview/save. OWNS: crates/ui-egui/src/views/web_capture/mod.rs (new, first write), crates/ui-egui/src/views/mod.rs, crates/ui-egui/src/shell/app.rs, crates/ui-egui/src/shell/app/window/commands.rs, crates/ui-egui/src/shell/app/window/frame.rs, crates/ui-egui/src/text/features/web_capture.rs (new), crates/ui-egui/src/text/features/mod.rs, crates/i18n/locales/en.toml (append ui.web_capture), crates/engine/src/prefs/app_settings.rs, crates/engine/src/prefs/settings.rs, crates/ui-egui/tests/web_capture.rs (new), apps/notescraft/src/main.rs (control startup/local bridge lifecycle hook only). FILES TO OPEN: spec D3-D5, crates/ui-egui/src/views/share_dialog/mod.rs, crates/engine/src/prefs/app_settings.rs, crates/engine/src/prefs/settings.rs, crates/ui-egui/src/shell/app/window/frame.rs. GOAL: off-by-default web enable setting and extension-origin list, local token display/revoke, listener reconciliation outside paint; Import web capture dialog takes copied JSON, previews, confirms save, reports remote images/partial capture/uncertain retry. Save stays registry-backed. Secrets absent from diagnostics/snapshot fixtures. TESTS: kittest disabled/enabled/revoke; invalid JSON and selection-only envelope; Save once; retry-only unknown result requires explicit fresh-submission confirmation; missing assets warning; read-only; queued failure keeps draft. Settings restart preserves enabled/origins but rotates token. TOML parses. VERIFY: standing engine + ui-egui; cargo xtask i18n; offscreen screenshots Mocha/Latte, normal/compact, read PNGs. DO NOT: write browser extension, silently change destination, execute HTML, read clipboard automatically, call engine per row/frame.

Phase 5 — external client contract and status

  • 5. Browser adapter contract with executable transport fixtures; close acceptance gaps. OWNS: specs/plugins-parity/web-clipper/browser-contract.md (new, first write), crates/engine/tests/web_capture_http.rs, specs/plugins-parity/web-clipper/spec.md, specs/plugins-parity/web-clipper/tasks.md, specs/plugins-parity/roadmap.md (33 only), ROADMAP.md, docs/ARCHITECTURE.md, docs/CODE-MAP.md (feature entries only). FILES TO OPEN: spec D4 and AC1-8, crates/engine/tests/web_capture_http.rs, specs/plugins-parity/roadmap.md. GOAL: publish exact JSON/route/error/pairing contract, selection-only bookmarklet algorithm and clipboard fallback, extension background/host-permission and asset rules. Include request/response examples and manual browser matrix for restricted page/CSP/permission/stale token/offline app. Mark external adapter unimplemented until separate work exists; update status with actual scope. TESTS: example envelopes accepted by registry/HTTP fixtures; invalid examples rejected; manual browser checks only for actual adapters, record untested contract claims as such. Trace every AC to prior tests or explicit gated adapter check. VERIFY: fixture tests plus standing final gates; docs links resolve. No cargo is run while writing these plans. DO NOT: publish/install extension, add JS to native app, mark full adapter shipped without real browser test, infer owner approval from time elapsed.