Skip to content

Latest commit

 

History

History
64 lines (58 loc) · 9.03 KB

File metadata and controls

64 lines (58 loc) · 9.03 KB

LEARNINGS

Architecture

  • JSONL append-only events (.tasque/events.jsonl) are the sole source of truth. Derived state (.tasque/state.json) is a rebuildable cache — never edit it manually.
  • Single-machine write lock via .tasque/.lock (open wx, short retry). No multi-writer guarantees.
  • Snapshot loader scans newest-to-oldest valid snapshot; writes prune to latest 5 files.
  • Git repos default to sync-worktree mode on tsq init: main worktree keeps .tasque/config.json; task data lives in tsq-sync unless --sync-branch or --worktree-name names another branch/worktree. Legacy git repos with main-tree .tasque data auto-migrate on the next command. Fresh clones fetch the configured sync branch and create the worktree on first use. tsq sync pushes the sync branch to origin and sets upstream automatically when needed.
  • Event IDs are ULIDs. Canonical event field is id with legacy event_id alias accepted on read. Task IDs are 8-char Crockford base32 random (root) or <parent>.<n> (children, append-only).
  • TasqueService is split into focused Rust modules: src/app/service.rs (facade), src/app/service_types.rs, src/app/service_utils.rs, src/app/service_lifecycle*.rs (mutations), src/app/service_query.rs, plus notes/specs/labels modules. Internal modules receive a ServiceContext object.
  • Status transitions emit task.status_set events; non-status field updates emit task.updated. Supersede/duplicate emit both.
  • Shared helpers: src/domain/events.rs (event factory), src/cli/terminal.rs (width/density), dependency tree helpers in src/domain/dep_tree.rs.
  • JSON output uses a universal envelope with schema_version=1.

Design Decisions

  • Bidirectional relates_to links; canonical supersede closes the source task and sets superseded_by without dependency/link rewiring.
  • duplicate closes source, adds duplicate_of metadata - no dependency rewiring (same pattern as supersede).
  • Strict CAS (compare-and-swap) claim semantics.
  • Spec required sections: Overview, Constraints / Non-goals, Interfaces (CLI/API), Data model / schema changes, Acceptance criteria, Test plan.
  • Timestamp filters (--created-after, --updated-after, --closed-after) require strict ISO timestamps; reject natural-language dates.
  • There is no task re-parent command; to split/move a subtree, create a new epic/feature branch and use supersede links from old tasks to new IDs for durable traceability.
  • TUI v2 visual baseline is Beads-inspired but Tasque-native: dark navy shell, top tabs Tasks|Epics|Board (optional Ready|History), dense pill tables, fixed 3-column board, and explicit Spec state (attached|missing|invalid) visible in table rows, board cards, and inspector.

Pitfalls

  • Human-readable CLI color/styling must stay TTY-aware and honor NO_COLOR/CLICOLOR=0 (with optional CLICOLOR_FORCE) so automation/tests remain plain-text stable while interactive shells get richer output.
  • resolve_task_id returns TASK_NOT_FOUND, not NOT_FOUND.
  • Negated search queries (-field:value) need a -- separator before them because clap treats leading - as option flags.
  • clap option conflict detection (e.g. --assignee vs --unassigned) must handle both --flag value and --flag=value forms consistently.
  • Lock contention timeout (LOCK_TIMEOUT) is a concurrency-class failure and must keep exitCode: 3 (not IO/storage code 2).
  • Query tokenizer must handle field:\"quoted value\" as one token; quote handling only at token-start breaks field-prefixed quoted filters.
  • with_write_lock returns INTERNAL_ERROR when both callback and lock release fail; keep release failure visible instead of masking it behind the callback error.
  • Stale lock cleanup uses atomic rename + content verification to prevent TOCTOU races between concurrent cleaners.
  • Projector validates dep/link targets with requireTask() — repair tests must inject orphans via state cache, not raw events, to bypass this validation.
  • repair --fix computes plan inside write lock using locked snapshot to prevent plan/apply drift.
  • CLI command handlers return explicit i32 exit codes; do not reintroduce global process exit state that can leak between in-process command runs.
  • clap may report no-subcommand cases as DisplayHelpOnMissingArgumentOrSubcommand (not only MissingSubcommand); for hard default no-arg behavior (like TUI entry), prefer an explicit pre-parse args.len()==1 TTY check and then handle both error kinds in fallback parsing paths.
  • On Windows, replacing a compiled tsq.exe can fail with EPERM if a prior test or shell still holds the binary; stop the process and retry the Cargo build.
  • For new CLI-option coverage before a fresh release build, run tests against cargo run -- ... or rebuild first to avoid stale-binary false failures.

Build & Release

  • cargo build --release --locked compiles the Rust binary; release workflows emit platform artifacts + SHA256SUMS.txt in dist/releases/.
  • Release automation should pass the freshly built dist/tsq(.exe) path into release-note generation instead of relying on tsq from PATH; this keeps GitHub runners and local environments deterministic.
  • tsq init skill lifecycle for agents uses managed-marker semantics: install, uninstall, idempotent update, non-managed skip unless --force.
  • Versioning/release planning baseline: use Cargo.toml as version source, surface via CLI -V/--version, and automate release PR/tag flow with release-please + GitHub Actions artifact publishing.
  • Added node npm/scripts/bump-version.js helper to bump Cargo.toml, Cargo.lock, root npm package, and platform package versions; supports --dry-run.
  • release-please.yml now supports workflow_dispatch for manual release-PR refresh from GitHub Actions.
  • Release workflows enforce tag/version sync against Cargo.toml.
  • Added release-from-package.yml workflow: manual dispatch creates a GitHub release from Cargo.toml version and then the publish workflow handles artifact builds.

Init UX

  • Wizard contract baseline: run tsq init wizard only on TTY by default; --no-wizard is authoritative; --wizard is TTY-only; non-interactive agent flows must remain fully deterministic via flags.
  • Refined wizard UX contract (docs/design/init-wizard-design.md): preserve a 4-step max flow, always show resolved plan before writes, treat --yes as wizard auto-accept (no-op outside wizard), and keep preset semantics deterministic (minimal, standard, full) with explicit-flags-over-preset precedence.
  • Explicit skill actions (--install-skill / --uninstall-skill) should bypass auto-wizard mode so tsq init executes immediately; --wizard is still available to force interactive flow.

Recent Updates

  • 2026-02-18: Event parsing validates JSONL boundaries via typed Rust/serde parsing; canonical event field is id while reads still accept legacy event_id.
  • 2026-02-18: Cache path migrated to .tasque/state.json with backward-compatible reads from legacy .tasque/tasks.jsonl.
  • 2026-02-18: Planned workflow model approved: keep lifecycle status separate from new planning_state; add deferred lifecycle status; ready should surface both planning and coding lanes with optional lane filter; create defaults to planning_state=needs_planning; add --body-file, strict --id regex, and deferred follow-up tasks for discovered-from + typed dependency model expansion.
  • 2026-02-18: Implemented discovered_from provenance metadata end-to-end (create/update/list/search/show) and typed dependency edges (blocks|starts_after) with directional filters/search (--dep-type/--dep-direction, dep_type_in/out); only blocks affect ready/cycle checks.
  • 2026-02-18: Skill installer now sources managed skill content from on-disk packages under SKILLS/<name>/ and recursively copies package contents (including references/scripts) to target agent skill directories.
  • 2026-02-19: In Rust file-based parent modules (e.g. src/app/service.rs, src/domain/projector.rs), sibling module splits need explicit #[path = "..."] mod ...; to prevent Rust from resolving into implicit subdirectories (service/..., projector/...).
  • 2026-02-19: Rust 2024 edition treats gen as a reserved keyword; calls like rand::thread_rng().gen::<u8>() must use raw identifier syntax (r#gen) or an alternate API.
  • 2026-02-19: clap repeatable CSV options with value_delimiter=',' can silently admit empty tokens unless validated explicitly; parity with TS requires rejecting --id ""/--label-any "" as --<field> must not be empty and inputs like a,,b as --<field> values must not be empty.
  • 2026-02-19: Rust watch parity with TS requires non-fatal refresh failures in loop mode (keep last good frame + print refresh error) and TTY-gated clear-screen/interactive controls; exiting on first refresh error is a behavioral regression.
  • 2026-02-19: Stable Rust hygiene baseline for this repo: pin toolchain components (rustfmt, clippy), keep rustfmt.toml aligned to style_edition=2024, and enforce cargo fmt --check + cargo clippy --all-targets --all-features -- -D warnings in CI to prevent drift.