Compare commits
@@ -35,10 +35,10 @@
|
|||||||
"Bash(pql)",
|
"Bash(pql)",
|
||||||
"Bash(pql *)",
|
"Bash(pql *)",
|
||||||
"Bash(clide)",
|
"Bash(clide)",
|
||||||
"Bash(clide *)",
|
"Bash(clide *)"
|
||||||
"Bash(awk *)"
|
|
||||||
],
|
],
|
||||||
"deny": [
|
"deny": [
|
||||||
|
"Edit(//var/mnt/data/projects/treesitter/**)",
|
||||||
"Bash(rm -rf /*)",
|
"Bash(rm -rf /*)",
|
||||||
"Bash(rm -rf ~*)",
|
"Bash(rm -rf ~*)",
|
||||||
"Bash(rm -rf $HOME*)",
|
"Bash(rm -rf $HOME*)",
|
||||||
@@ -59,7 +59,10 @@
|
|||||||
"Bash(git checkout -- *)",
|
"Bash(git checkout -- *)",
|
||||||
"Bash(git restore .*)",
|
"Bash(git restore .*)",
|
||||||
"Bash(chmod -R 777 *)",
|
"Bash(chmod -R 777 *)",
|
||||||
"Bash(chmod 777 *)"
|
"Bash(chmod 777 *)",
|
||||||
|
"Bash(git add -A*)",
|
||||||
|
"Bash(git add --all*)",
|
||||||
|
"Bash(git add .)"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-10
@@ -5,19 +5,22 @@ lives in its own directory with a `SKILL.md` (frontmatter + body) and any
|
|||||||
helper scripts. This index is for humans skimming what's available; Claude
|
helper scripts. This index is for humans skimming what's available; Claude
|
||||||
discovers skills automatically from the directory structure.
|
discovers skills automatically from the directory structure.
|
||||||
|
|
||||||
|
Only clide-specific skills live in this repo. Repo-agnostic skills
|
||||||
|
(`d2-diagram`, `frame0-wireframe`, `skill-create`) live at user scope
|
||||||
|
(`~/.claude/skills/`), as do the pql-distributed ones (`pql`, `clean-house`,
|
||||||
|
installed via `pql init`).
|
||||||
|
|
||||||
| Skill | Purpose |
|
| Skill | Purpose |
|
||||||
|---|---|
|
|---|---|
|
||||||
| [`d2-diagram`](d2-diagram/SKILL.md) | Generate technical diagrams from `.d2` source with the d2 CLI; renders to PNG. |
|
| [`clide`](clide/SKILL.md) | Observe/drive the live clide UI through the `clide` CLI; discover the surface with `clide capabilities`. |
|
||||||
| [`frame0-wireframe`](frame0-wireframe/SKILL.md) | Author UI wireframes as local JSON and sync to the Frame0 desktop app for rendering + export. |
|
| [`git-commit`](git-commit/SKILL.md) | Commit conventions for this repo — message style, CHANGELOG discipline (60-word cap), attribution trailer, safety rules. |
|
||||||
| [`git-commit`](git-commit/SKILL.md) | Commit conventions for this repo — message style, CHANGELOG discipline (40/60 word cap), attribution trailer, safety rules. |
|
| [`testmode`](testmode/SKILL.md) | Run and interpret the `ClideTestApp` platform integration harness; smoke-test after toolchain / IPC / PTY / theme / native changes. |
|
||||||
| [`pql`](pql/SKILL.md) | Query and plan against the markdown vault via the `pql` CLI (decisions, tickets, structural queries). |
|
| [`ui-design`](ui-design/SKILL.md) | Visual design guide — surface tokens, control geometry, Phosphor icons (`byName` + generated glyph table). |
|
||||||
| [`skill-create`](skill-create/SKILL.md) | Guidance for creating new skills — SKILL.md structure, bundling scripts, packaging. |
|
|
||||||
| [`testmode`](testmode/SKILL.md) | Run and interpret the `ClideTestApp` platform integration harness; smoke-test after toolchain / IPC / theme / native changes. |
|
|
||||||
| [`ui-design`](ui-design/SKILL.md) | Visual design guide — surface tokens, control geometry, Phosphor icons. |
|
|
||||||
| [`whats-next`](whats-next/SKILL.md) | Dependency-driven batch selection against the pql backlog. Walks the initiative/epic tree, filters unblocked work, refines, optionally activates. |
|
| [`whats-next`](whats-next/SKILL.md) | Dependency-driven batch selection against the pql backlog. Walks the initiative/epic tree, filters unblocked work, refines, optionally activates. |
|
||||||
|
|
||||||
## Adding a skill
|
## Adding a skill
|
||||||
|
|
||||||
Use the `skill-create` skill (or follow its SKILL.md by hand). Add a row to
|
Use the `skill-create` skill (user scope; or follow its SKILL.md by hand).
|
||||||
the table above so the inventory stays accurate; the index is otherwise just
|
Clide-specific skills go here; repo-agnostic ones go to `~/.claude/skills/`.
|
||||||
a directory listing.
|
Add a row to the table above so the inventory stays accurate; the index is
|
||||||
|
otherwise just a directory listing.
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"version": "1.5.0",
|
|
||||||
"hash": "sha256:8090b99552c828ce019aa3740d8a0acb4768a443704b4e935efa23b32e91128d",
|
|
||||||
"installed_at": "2026-06-02T08:46:25Z"
|
|
||||||
}
|
|
||||||
@@ -1,229 +0,0 @@
|
|||||||
---
|
|
||||||
name: clean-house
|
|
||||||
description: >
|
|
||||||
Run a documentation-discipline pass over a DQR (Decisions / Questions /
|
|
||||||
Rejected) markdown system. Audits decisions/, surfaces drift (broken
|
|
||||||
anchor links, missing Q→D backlinks, sunset-shaped phrases without
|
|
||||||
linked tickets, files over the split threshold, dead cross-references),
|
|
||||||
batches findings by category, and uses AskUserQuestion to apply fixes
|
|
||||||
interactively. Trigger this skill whenever the user asks to clean,
|
|
||||||
tidy, audit, sweep, garden, or review the state of decisions/, the
|
|
||||||
DQR system, the questions index, or the records under decisions/.
|
|
||||||
Also trigger before a release, after a session that touched many
|
|
||||||
records, or whenever the user mentions documentation drift, stale
|
|
||||||
plans, or "house" / "clean-house" / "house cleaning". Imperative —
|
|
||||||
apply fixes, not just report.
|
|
||||||
---
|
|
||||||
|
|
||||||
# clean-house
|
|
||||||
|
|
||||||
A periodic gardening pass over `decisions/`. The DQR system is
|
|
||||||
markdown-as-source-of-truth; `.pql/pql.db` is a derived index. This skill
|
|
||||||
operates on the markdown files, batches drift by category, and uses
|
|
||||||
`AskUserQuestion` to decide what to apply.
|
|
||||||
|
|
||||||
The skill is **imperative**. It really cleans. The verb-noun match is
|
|
||||||
load-bearing — a `clean-house` that only produced a report would be
|
|
||||||
misnamed. Mechanical fixes get a single batched approval, judgment-call
|
|
||||||
findings get individual prompts, and a "stop asking" escape hatch is
|
|
||||||
always present.
|
|
||||||
|
|
||||||
You — Claude — are the runtime. Read this file, read
|
|
||||||
`references/rules.md`, follow the procedure below, call `pql` and `Edit`
|
|
||||||
to do the work, call `AskUserQuestion` for the prompts.
|
|
||||||
|
|
||||||
## When to run
|
|
||||||
|
|
||||||
- Before a release.
|
|
||||||
- After a session that touched many D / Q / R records.
|
|
||||||
- When something feels stale and a sweep is wanted.
|
|
||||||
- When `pql decisions validate` is green but `decisions/` still feels off.
|
|
||||||
|
|
||||||
This skill is **not** a replacement for `pql decisions validate`.
|
|
||||||
Validate is fast, hot, and gates pre-push. clean-house is slow, cold,
|
|
||||||
on-demand. Escalation path: rules that fire often here are candidates
|
|
||||||
for promotion to `pql decisions validate`; rules that almost never fire
|
|
||||||
stay here where false positives don't slow anyone down.
|
|
||||||
|
|
||||||
## Procedure
|
|
||||||
|
|
||||||
1. **Gate on validate.** Run `pql decisions validate`. If it exits
|
|
||||||
non-zero, stop and tell the user to fix validator findings first.
|
|
||||||
Do not proceed.
|
|
||||||
|
|
||||||
2. **Load the rule catalog.** Read `references/rules.md`. Each rule
|
|
||||||
names its detection, fix, and finding-id format.
|
|
||||||
|
|
||||||
3. **Probe conventions.** Read `decisions/.clean-house.yaml` if it
|
|
||||||
exists; otherwise infer from the project. Conventions to resolve:
|
|
||||||
- `heading_level`: 2 or 3 — the depth records use (`## D-N` vs
|
|
||||||
`### D-N`). Probe by sampling the first 3 records' file
|
|
||||||
locations and looking for the first matching ATX heading.
|
|
||||||
- `backlink_phrasing`: the project's Q→D backlink phrase (default
|
|
||||||
`Resolved → D-N`; some projects use `Resolved as D-N` or
|
|
||||||
`→ D-N`).
|
|
||||||
- `file_threshold`: default 350 (RULE-FILE-OVER-THRESHOLD).
|
|
||||||
- `stale_open_q_days`: default 60 (RULE-STALE-OPEN-Q).
|
|
||||||
|
|
||||||
Pass the resolved conventions into each rule's detection. Cache
|
|
||||||
the probe result for the run.
|
|
||||||
|
|
||||||
`decisions/.clean-house.yaml` shape (all keys optional):
|
|
||||||
```yaml
|
|
||||||
heading_level: 3
|
|
||||||
backlink_phrasing: "Resolved → "
|
|
||||||
file_threshold: 500
|
|
||||||
stale_open_q_days: 90
|
|
||||||
exclude_paths: ["legacy/", "drafts/"]
|
|
||||||
```
|
|
||||||
|
|
||||||
4. **Sync the index.** Run `pql decisions sync` so the DB reflects
|
|
||||||
the markdown.
|
|
||||||
|
|
||||||
5. **Walk decisions/.** Use `pql decisions list` to enumerate
|
|
||||||
records, plus `pql decisions read <id>` per record when a rule
|
|
||||||
needs the body. For file-level rules (size, sort), read the
|
|
||||||
markdown files directly. **Filter out** any record whose
|
|
||||||
`file_path` begins with `legacy/` (or any prefix in
|
|
||||||
`exclude_paths` from the probe).
|
|
||||||
|
|
||||||
6. **Run each rule's detection.** Collect findings. Tag each with
|
|
||||||
its rule ID, finding ID (per the rule's format), category
|
|
||||||
(`mechanical` | `judgment`), and the record(s)/file(s) involved.
|
|
||||||
|
|
||||||
7. **Group findings by rule** and prompt. Honor any "skipped 3+
|
|
||||||
times" findings from the skip ledger by escalating their prompt
|
|
||||||
("skipped 3x — promote to manual decision, downgrade to
|
|
||||||
summary-only, or keep asking?"):
|
|
||||||
|
|
||||||
- **Mechanical rules** — one prompt per rule, batched. Show the
|
|
||||||
count and offer: apply all / show diff first / skip this rule /
|
|
||||||
**stop asking** (global — see below).
|
|
||||||
- **Judgment rules** — one prompt per finding. Options match the
|
|
||||||
rule's `Fix` section, plus the same global **stop asking**.
|
|
||||||
|
|
||||||
**"Stop asking" semantics (global).** When the user picks "stop
|
|
||||||
asking" on any prompt, immediately halt all further prompts in
|
|
||||||
the run — mechanical batches not yet asked AND remaining
|
|
||||||
judgment findings. Move all unprompted findings to the skip
|
|
||||||
ledger marked `deferred-stop-asking`. Skip to step 9.
|
|
||||||
|
|
||||||
**"Show diff first" loop.** When the user picks "show diff
|
|
||||||
first" on a mechanical batch, emit a unified diff of the staged
|
|
||||||
edits (one block per file), then re-prompt the same question
|
|
||||||
with the same options minus "show diff first" — preventing
|
|
||||||
infinite loops while still letting the user inspect before
|
|
||||||
committing.
|
|
||||||
|
|
||||||
8. **Apply approvals.** For mechanical rules use `Edit` to mutate
|
|
||||||
the markdown directly. For judgment rules, follow the option the
|
|
||||||
user picked (file a ticket via `pql ticket new`, mark superseded
|
|
||||||
by editing the record, etc.).
|
|
||||||
|
|
||||||
9. **Update the skip ledger and history.** Both files live at
|
|
||||||
`decisions/.clean-house-state.md`, gitignored. The file uses
|
|
||||||
per-run section headers so it doubles as run history:
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
# clean-house run history
|
|
||||||
|
|
||||||
## 2026-05-06T13:42Z
|
|
||||||
fired: RULE-ANCHOR-DRIFT(1) RULE-SUNSET-WITHOUT-TICKET(1)
|
|
||||||
applied: RULE-ANCHOR-DRIFT(1) RULE-SUNSET-WITHOUT-TICKET(1)
|
|
||||||
skipped:
|
|
||||||
- RULE-ANCHOR-DRIFT D-8:#q-1-markdown-mirror-for-tickets
|
|
||||||
|
|
||||||
## 2026-05-04T11:10Z
|
|
||||||
fired: ...
|
|
||||||
```
|
|
||||||
|
|
||||||
Each section starts with a UTC ISO-8601 timestamp. `fired`
|
|
||||||
counts findings detected; `applied` counts findings the user
|
|
||||||
acted on; `skipped` lists `<rule-id> <finding-id>` pairs.
|
|
||||||
|
|
||||||
**Promotion-candidate computation.** Scan the most recent N=7
|
|
||||||
sections (or all sections if fewer). A rule is a promotion
|
|
||||||
candidate if it `fired` in ≥ 5 of those sections. Surface the
|
|
||||||
candidates in the summary; do not auto-promote.
|
|
||||||
|
|
||||||
10. **Emit the summary** (see Output below).
|
|
||||||
|
|
||||||
## Question phrasing
|
|
||||||
|
|
||||||
Always include the rule ID in the prompt so the user learns what's
|
|
||||||
being checked.
|
|
||||||
|
|
||||||
**Mechanical (batched):**
|
|
||||||
> RULE-ANCHOR-DRIFT: 12 cross-reference anchors point to headings that
|
|
||||||
> no longer exist (renamed or deleted). Apply all 12 fixes? Options:
|
|
||||||
> apply all / show diff first / skip this rule / stop asking, summarize
|
|
||||||
> the rest.
|
|
||||||
|
|
||||||
**Judgment (individual):**
|
|
||||||
> RULE-SUNSET-WITHOUT-TICKET: D-59 mentions "must track dugite-native
|
|
||||||
> releases for security updates" but has no linked T. Options: file T
|
|
||||||
> now / draft a T description first / mark as already covered (add note
|
|
||||||
> to D) / skip / stop asking.
|
|
||||||
|
|
||||||
Phrasing rules:
|
|
||||||
|
|
||||||
- **Always include "stop asking, summarize the rest."** Sessions
|
|
||||||
without bandwidth for full review need an escape. Forcing answers
|
|
||||||
to every question kills the tool.
|
|
||||||
- **Always include "skip."** Skipped findings go to the ledger; three
|
|
||||||
consecutive skips of the same finding promote the next prompt.
|
|
||||||
- **Mechanical batches; judgment doesn't.** "Apply all 12 fixes?" is
|
|
||||||
one decision against a clear delta. Twelve individual prompts defeat
|
|
||||||
the point. Conversely, judgment findings are each separate work —
|
|
||||||
presenting them as a batch hides cost.
|
|
||||||
|
|
||||||
## What this skill does NOT do
|
|
||||||
|
|
||||||
- Does not file tickets without asking.
|
|
||||||
- Does not rewrite D-record body prose, only metadata fields and
|
|
||||||
cross-reference links.
|
|
||||||
- Does not touch records under `legacy/`.
|
|
||||||
- Does not run `pql decisions validate` *as a fix* — only as a
|
|
||||||
precondition gate.
|
|
||||||
- Does not promote rules to `pql decisions validate` automatically.
|
|
||||||
Promotion is a human decision; this skill only flags candidates
|
|
||||||
("RULE-X has fired in 5 of the last 7 runs — consider promoting").
|
|
||||||
|
|
||||||
## Non-interactive context
|
|
||||||
|
|
||||||
If invoked without an interactive `AskUserQuestion` surface (a CI run,
|
|
||||||
a batch script), refuse to apply judgment fixes. Apply mechanical
|
|
||||||
fixes only if the user explicitly says so via the trigger phrase
|
|
||||||
("auto-apply mechanical, skip judgment"); otherwise emit the summary
|
|
||||||
and exit without mutating files.
|
|
||||||
|
|
||||||
## Output
|
|
||||||
|
|
||||||
At the end, emit a summary block:
|
|
||||||
|
|
||||||
```
|
|
||||||
clean-house — sweep complete
|
|
||||||
────────────────────────────
|
|
||||||
Files scanned: 11
|
|
||||||
Records parsed: 62 D, 23 Q, 11 R
|
|
||||||
Conventions: heading_level=3 backlink="Resolved → "
|
|
||||||
Mechanical fixes: 14 applied, 0 deferred
|
|
||||||
Judgment findings: 3 acted on, 2 deferred (in state file)
|
|
||||||
Promotion candidates: RULE-ANCHOR-DRIFT (5/7 runs)
|
|
||||||
Touched files: decisions/architecture.md, decisions/questions.md
|
|
||||||
```
|
|
||||||
|
|
||||||
If this is the first run (no prior history) or there are fewer
|
|
||||||
than 5 prior runs, `Promotion candidates:` reports
|
|
||||||
`(none — N/7 runs of history)` instead of decorative empty content.
|
|
||||||
|
|
||||||
The summary names the touched files so the next commit message can be
|
|
||||||
honest about what changed. The skill does not commit on its own.
|
|
||||||
|
|
||||||
## Versioning
|
|
||||||
|
|
||||||
clean-house ships embedded in the pql binary; its version is the
|
|
||||||
pql version (`pql --version`). To see what changed and when, read
|
|
||||||
`CHANGELOG.md` or `git log internal/skill/clean-house/` in the pql
|
|
||||||
repo. Keep this file and `references/rules.md` consistent with
|
|
||||||
each other when iterating — they're the contract.
|
|
||||||
@@ -1,386 +0,0 @@
|
|||||||
# clean-house rule catalog
|
|
||||||
|
|
||||||
The rules clean-house runs and the reasoning behind each. New rules
|
|
||||||
land here as their own entry. Catalog churn — additions, refinements,
|
|
||||||
retirements — is tracked in pql's `CHANGELOG.md` and `git log
|
|
||||||
internal/skill/clean-house/`. When a rule is retired, leave a
|
|
||||||
**Retired** stub (ID + one-line reason + retirement commit) so the
|
|
||||||
trail of "we used to check X" is recoverable from this file alone.
|
|
||||||
|
|
||||||
## Reading a rule
|
|
||||||
|
|
||||||
Each entry below has:
|
|
||||||
|
|
||||||
- **ID** — Stable identifier (e.g. `RULE-ANCHOR-DRIFT`). Used in
|
|
||||||
AskUserQuestion prompts and skip-ledger entries so the user learns
|
|
||||||
what's being checked.
|
|
||||||
- **Category** — `mechanical` or `judgment`. Drives whether findings
|
|
||||||
batch into one prompt or each get their own.
|
|
||||||
- **Finding ID** — Format string for the per-finding stable
|
|
||||||
identifier. Skip-ledger entries are written as `<rule-id>
|
|
||||||
<finding-id> <ISO-date>`; subsequent runs use the same format to
|
|
||||||
recognize "same finding skipped 3 runs in a row" and escalate.
|
|
||||||
Use only stable inputs (record IDs, file paths, slug strings, body
|
|
||||||
hashes) — never line numbers or timestamps.
|
|
||||||
- **Detection** — Concrete steps to find violations. Names the
|
|
||||||
pql command or file primitive used.
|
|
||||||
- **Fix** — Mechanical: deterministic action. Judgment: the prompt
|
|
||||||
option list and what each option does.
|
|
||||||
- **Why** — One paragraph on the failure mode this rule guards
|
|
||||||
against. Future-you reading the rule benefits from the reasoning,
|
|
||||||
not just the check.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## RULE-ANCHOR-DRIFT
|
|
||||||
|
|
||||||
**Category:** mechanical
|
|
||||||
|
|
||||||
**Finding ID:** `<source-record>:<link-target>` (e.g.
|
|
||||||
`D-8:#q-1-markdown-mirror-for-tickets` or
|
|
||||||
`D-8:questions.md#q-1`).
|
|
||||||
|
|
||||||
**Detection:**
|
|
||||||
|
|
||||||
Anchor-only markdown links (`[text](#slug)`) resolve against the
|
|
||||||
**source file's full heading set**, not the body of a single record
|
|
||||||
— record-level headings (`### D-N: …`) live as siblings in the
|
|
||||||
file and are valid link targets. The previous detection (which used
|
|
||||||
`pql decisions read`'s body-only `headings` array) missed these
|
|
||||||
and produced false positives.
|
|
||||||
|
|
||||||
Per source body:
|
|
||||||
|
|
||||||
1. Open the source body's file (`<vault>/<file_path>` from
|
|
||||||
`pql decisions list`) and extract every ATX heading. Build a
|
|
||||||
slug index for the file using the GFM convention (lowercase,
|
|
||||||
hyphenate spaces, drop punctuation, disambiguate duplicates with
|
|
||||||
`-1`/`-2`). Cache per file — every record in that file uses the
|
|
||||||
same index.
|
|
||||||
2. For each `[text](target)` link in the body:
|
|
||||||
- Anchor-only (`#slug`): check `slug` against the **source file's**
|
|
||||||
index. Missing → flag.
|
|
||||||
- Cross-file (`path.md#slug`): resolve `path.md` relative to the
|
|
||||||
source file's directory; check `slug` against that file's
|
|
||||||
index. Missing file or missing slug → flag.
|
|
||||||
|
|
||||||
**Fix:**
|
|
||||||
|
|
||||||
If the slug exists in a sibling file's index (same directory) and
|
|
||||||
the link is anchor-only, rewrite to `path.md#slug` (the canonical
|
|
||||||
cross-file form). If the slug exists in the source file's index
|
|
||||||
with edit-distance ≤ 2 from the link target, rewrite to the
|
|
||||||
matched slug. Otherwise downgrade to judgment ("no auto-fix; the
|
|
||||||
heading was removed, not renamed") with options: drop the link /
|
|
||||||
point elsewhere / mark as intentionally dangling.
|
|
||||||
|
|
||||||
**Fix:**
|
|
||||||
|
|
||||||
If exactly one heading with a closely-matching slug exists (slug
|
|
||||||
edit-distance ≤ 2 or substring match), rewrite the link to point at
|
|
||||||
that heading. If no plausible match exists, downgrade the finding to
|
|
||||||
judgment ("no auto-fix; the heading was removed, not renamed") and
|
|
||||||
prompt the user with options: drop the link / point elsewhere / mark
|
|
||||||
as intentionally dangling.
|
|
||||||
|
|
||||||
**Why:**
|
|
||||||
|
|
||||||
When a heading is renamed for clarity, every cross-reference pointing
|
|
||||||
at the old slug silently breaks. The rendered docs still look fine —
|
|
||||||
the link just goes nowhere. Without periodic sweeps these decay
|
|
||||||
indefinitely; the cost of the sweep is small compared to the cost of
|
|
||||||
a reader following a dead link and losing trust in the index.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## RULE-MISSING-Q-BACKLINK
|
|
||||||
|
|
||||||
**Category:** mechanical
|
|
||||||
|
|
||||||
**Finding ID:** `<d-id>:<q-id>` (e.g. `D-7:Q-2`). Order is always
|
|
||||||
D-first regardless of which side is missing the backlink.
|
|
||||||
|
|
||||||
**Detection:**
|
|
||||||
|
|
||||||
For each D record body, find lines of the shape `Resolves: Q-N`
|
|
||||||
(plain text, typically in the metadata block at the top of the
|
|
||||||
record). For each Q-N referenced, fetch that Q record's body via
|
|
||||||
`pql decisions read Q-N` and check whether it contains a line of the
|
|
||||||
shape `Resolved → D-N` (or equivalent backlink phrasing — match the
|
|
||||||
project's own convention; default pattern is `Resolved → D-N`).
|
|
||||||
|
|
||||||
Also check the reverse direction: any Q record claiming
|
|
||||||
`Resolved → D-N` whose D-N body lacks `Resolves: Q-N`.
|
|
||||||
|
|
||||||
**Fix:**
|
|
||||||
|
|
||||||
Insert the missing backlink in-place using `Edit`:
|
|
||||||
|
|
||||||
- Missing on the D side: add `Resolves: Q-N` to the D's metadata
|
|
||||||
block (typically right after `Domain:` / `Status:` lines).
|
|
||||||
- Missing on the Q side: append `Resolved → D-N` to the Q's status
|
|
||||||
line (or in the conventional position for that project).
|
|
||||||
|
|
||||||
**Why:**
|
|
||||||
|
|
||||||
Bidirectional Q↔D links are the navigation backbone of the DQR
|
|
||||||
system. When one side drifts, search-by-decision finds nothing for
|
|
||||||
that question and search-by-question doesn't surface its resolution.
|
|
||||||
The asymmetric state usually arises from a hand-edit on one record
|
|
||||||
that forgot to update the other; the fix is purely mechanical because
|
|
||||||
the correct content is already determined by the existing pointer
|
|
||||||
in the other direction.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## RULE-RECORD-SORT
|
|
||||||
|
|
||||||
**Category:** mechanical
|
|
||||||
|
|
||||||
**Finding ID:** `<file-path>` (e.g. `decisions/architecture.md`).
|
|
||||||
The whole file is one finding — sort applies to the file as a
|
|
||||||
unit.
|
|
||||||
|
|
||||||
**Detection:**
|
|
||||||
|
|
||||||
For each `decisions/*.md` file, read it directly (no pql) and find
|
|
||||||
all top-level `## D-N` / `## Q-N` / `## R-N` headings in order. Strip
|
|
||||||
the prefix, parse the numeric suffix, and check whether the sequence
|
|
||||||
is monotonically ascending within each ID family (D, Q, R kept
|
|
||||||
separate — files commonly mix families).
|
|
||||||
|
|
||||||
Only flag a file if it is **otherwise tidy** — currently no out-of-
|
|
||||||
order amendments interleaved with new records. The heuristic: if the
|
|
||||||
sort would touch fewer than three records out of position, apply it;
|
|
||||||
if more, downgrade to judgment ("this file looks deliberately
|
|
||||||
arranged — confirm before reordering"). Three is a soft threshold; if
|
|
||||||
the file's last commit message contains `WIP` or `do-not-sort`, skip.
|
|
||||||
|
|
||||||
**Fix:**
|
|
||||||
|
|
||||||
Reorder the records within the file so each ID family is ascending.
|
|
||||||
Preserve everything else (headings between record blocks, any prose
|
|
||||||
prelude/postlude). Use `Edit` with full block replacement, not in-
|
|
||||||
place line shuffling — easier to verify the diff.
|
|
||||||
|
|
||||||
**Why:**
|
|
||||||
|
|
||||||
Records added at the bottom of a file are easy to write but hard to
|
|
||||||
find. Sorted IDs let a reader find D-37 by jumping to the
|
|
||||||
two-thirds mark of the file rather than scanning. The cost of the
|
|
||||||
sort is one reordering pass; the benefit is paid back on every
|
|
||||||
subsequent read.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## RULE-EOF-NORMALIZATION
|
|
||||||
|
|
||||||
**Category:** mechanical
|
|
||||||
|
|
||||||
**Finding ID:** `<file-path>` (one finding per file).
|
|
||||||
|
|
||||||
**Detection:**
|
|
||||||
|
|
||||||
For each `decisions/*.md` file (and any other markdown the skill
|
|
||||||
touched during this run), read directly. Flag if:
|
|
||||||
|
|
||||||
- File does not end with exactly one `\n`.
|
|
||||||
- Any line contains trailing whitespace before its `\n`.
|
|
||||||
|
|
||||||
**Fix:**
|
|
||||||
|
|
||||||
Trim trailing whitespace from each line. Ensure exactly one trailing
|
|
||||||
newline at end of file. Use `Edit` only if a violation was found —
|
|
||||||
this rule must not produce a no-op diff.
|
|
||||||
|
|
||||||
**Why:**
|
|
||||||
|
|
||||||
Editor and git config drift causes whitespace creep that's invisible
|
|
||||||
in rendering but pollutes diffs (every record edit ends up touching
|
|
||||||
unrelated lines). A periodic normalization keeps future diffs clean
|
|
||||||
without forcing per-editor enforcement on every contributor.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## RULE-SUNSET-WITHOUT-TICKET
|
|
||||||
|
|
||||||
**Category:** judgment
|
|
||||||
|
|
||||||
**Finding ID:** `<record-id>:<phrase-hash-8>` where phrase-hash-8 is
|
|
||||||
the first 8 hex chars of `sha256(<matched-phrase>)`. Lets the
|
|
||||||
ledger distinguish two sunset phrases in the same record.
|
|
||||||
|
|
||||||
**Detection:**
|
|
||||||
|
|
||||||
For each D record body (via `pql decisions read <id>`), grep for
|
|
||||||
sunset-shaped phrases. Default regex set:
|
|
||||||
|
|
||||||
```
|
|
||||||
(?i)\b(delete|remove|sunset|kill[ -]?switch|tear[ -]?down) when\b
|
|
||||||
(?i)\bmust (track|monitor|watch|follow)\b
|
|
||||||
(?i)\brevisit (when|after|once)\b
|
|
||||||
(?i)\b(deprecate|retire) (when|after|once)\b
|
|
||||||
```
|
|
||||||
|
|
||||||
For each match, run `pql ticket list --decision <id>`. If no tickets
|
|
||||||
exist, the D has work-shaped intent without a tracked T — flag.
|
|
||||||
|
|
||||||
**Fix (prompt options):**
|
|
||||||
|
|
||||||
- **File T now** — Run `pql ticket new task "<phrase>" --decision <id>`,
|
|
||||||
then prompt the user for a description (or call `pql ticket refine
|
|
||||||
write <T> --description ...` after creation).
|
|
||||||
- **Draft a T description first** — Open an `AskUserQuestion` for the
|
|
||||||
description, then file as above.
|
|
||||||
- **Mark as already covered** — Add a note to the D body
|
|
||||||
("Tracked under T-N") via `Edit`. Skill does not assert which T;
|
|
||||||
user provides the ID.
|
|
||||||
- **Skip** — Adds to the ledger.
|
|
||||||
- **Stop asking** — Skip remaining sunset findings, summarize.
|
|
||||||
|
|
||||||
**Why:**
|
|
||||||
|
|
||||||
Sunset-shaped intent ("we'll handle X when Y happens") is the most
|
|
||||||
common source of accumulated debt in a DQR system: the trigger
|
|
||||||
condition arrives, nobody remembers the D, the work doesn't happen.
|
|
||||||
Linking each sunset to a T is the simplest defense — a T is a
|
|
||||||
backlog item that surfaces in `plan whatsnext` / `plan board`. The
|
|
||||||
fix is judgment because the right action depends on whether the D's
|
|
||||||
condition is still relevant, whether it's already covered, and what
|
|
||||||
the right scope is for the resulting T.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## RULE-FILE-OVER-THRESHOLD
|
|
||||||
|
|
||||||
**Category:** judgment
|
|
||||||
|
|
||||||
**Finding ID:** `<file-path>` (one finding per file; threshold
|
|
||||||
choice is judgment, not a per-line problem).
|
|
||||||
|
|
||||||
**Detection:**
|
|
||||||
|
|
||||||
For each `decisions/*.md` file, count lines (via `wc -l` or
|
|
||||||
equivalent). Default threshold: **350 lines**. Configurable per
|
|
||||||
project — read `decisions/.clean-house.yaml` if present, key
|
|
||||||
`file_threshold`. Fall back to 350.
|
|
||||||
|
|
||||||
**Fix (prompt options):**
|
|
||||||
|
|
||||||
- **Split now (which axis?)** — Prompt for the split axis: by ID
|
|
||||||
family (D/Q/R), by domain, by date range, custom. Then perform the
|
|
||||||
split: create new file(s), move records, update any anchor links
|
|
||||||
pointing into the moved records (run RULE-ANCHOR-DRIFT in apply
|
|
||||||
mode against the affected files after the split).
|
|
||||||
- **Accept and raise the threshold** — Update
|
|
||||||
`decisions/.clean-house.yaml`'s `file_threshold` to the next
|
|
||||||
reasonable round number above the current line count.
|
|
||||||
- **Defer** — Skip until next run.
|
|
||||||
|
|
||||||
**Why:**
|
|
||||||
|
|
||||||
A single decisions file growing past ~350 lines is the point at which
|
|
||||||
linear scanning starts to lose to grep, and where the cost of
|
|
||||||
splitting (renaming anchors) is still small. Beyond ~600 lines the
|
|
||||||
split cost compounds. The threshold is judgment because some projects
|
|
||||||
deliberately keep one file per domain and accept the size; others
|
|
||||||
split aggressively. The skill surfaces the question; it doesn't
|
|
||||||
decide.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## RULE-DEAD-FILE-REFERENCE
|
|
||||||
|
|
||||||
**Category:** judgment
|
|
||||||
|
|
||||||
**Finding ID:** `<record-id>:<path-token>` (path token as written
|
|
||||||
in the body, not resolved).
|
|
||||||
|
|
||||||
**Detection:**
|
|
||||||
|
|
||||||
For each D record body (via `pql decisions read <id>`), grep for
|
|
||||||
path-shaped tokens. Default regex:
|
|
||||||
|
|
||||||
```
|
|
||||||
\b([\w./-]+\.(md|go|py|sql|yaml|yml|toml))\b
|
|
||||||
```
|
|
||||||
|
|
||||||
The first detection pass produced 6/6 false positives in
|
|
||||||
real-world use; the regex is necessary but not sufficient. For
|
|
||||||
each match, apply the filters below in order — if any matches,
|
|
||||||
**skip without flagging**:
|
|
||||||
|
|
||||||
1. **Placeholder filter.** Token contains `T-NNN`, `D-NNN`,
|
|
||||||
`Q-NNN`, `R-NNN`, `...`, `<`, `>`, or `*` — it's a pattern,
|
|
||||||
not a real path.
|
|
||||||
2. **Source-relative resolution.** Resolve the token against the
|
|
||||||
source file's directory (`<vault>/<file_path>`'s dir). If
|
|
||||||
`[ -e <resolved> ]`, the reference is live.
|
|
||||||
3. **Repo-relative resolution.** If `[ -e <token> ]` from the
|
|
||||||
repo root, the reference is live.
|
|
||||||
4. **Basename-fallback.** Run `find <repo-root> -name <basename>`
|
|
||||||
(where basename is the last path component). If exactly one
|
|
||||||
match exists, treat the reference as live and emit a low-
|
|
||||||
priority "consider rewriting to the absolute path" note (not a
|
|
||||||
judgment finding). If multiple matches exist, do not flag —
|
|
||||||
the token is too ambiguous.
|
|
||||||
|
|
||||||
Only after all four filters miss does the reference qualify as
|
|
||||||
truly dead and warrant a judgment prompt.
|
|
||||||
|
|
||||||
**Fix (prompt options):**
|
|
||||||
|
|
||||||
- **Update reference** — Prompt for the new path; rewrite the
|
|
||||||
reference via `Edit`. If the user types a path, validate it exists
|
|
||||||
before applying.
|
|
||||||
- **Mark superseded** — Add a note to the D ("This decision
|
|
||||||
references files no longer present; the underlying constraint
|
|
||||||
was retired by D-N") and prompt for the superseding D ID.
|
|
||||||
- **Defer** — Skip until next run.
|
|
||||||
|
|
||||||
**Why:**
|
|
||||||
|
|
||||||
Decisions reference code paths to ground their reasoning in the
|
|
||||||
codebase that motivated them. When the code moves or gets deleted,
|
|
||||||
the D's reasoning becomes harder to verify. Dead refs are a signal
|
|
||||||
that either the decision should be updated or the decision itself is
|
|
||||||
no longer load-bearing — both are judgment calls the user needs to
|
|
||||||
make.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## RULE-STALE-OPEN-Q
|
|
||||||
|
|
||||||
**Category:** judgment
|
|
||||||
|
|
||||||
**Finding ID:** `<q-id>` (one finding per Q-record; staleness
|
|
||||||
threshold is global per run, so a Q is either stale or not).
|
|
||||||
|
|
||||||
**Detection:**
|
|
||||||
|
|
||||||
Run `pql decisions list --type question --status open`. For each
|
|
||||||
returned record, check the `date` field. Default staleness threshold:
|
|
||||||
**60 days** (configurable via `decisions/.clean-house.yaml` key
|
|
||||||
`stale_open_q_days`). Flag any Q with `date` older than the
|
|
||||||
threshold.
|
|
||||||
|
|
||||||
**Fix (prompt options):**
|
|
||||||
|
|
||||||
- **Still relevant** — Touch the Q's `date` field to today, optionally
|
|
||||||
add a one-line "still open as of YYYY-MM-DD: <reason>" to the body.
|
|
||||||
- **Nudge to load-bearing index** — If the project keeps a
|
|
||||||
load-bearing Qs list (a curated index of unresolved questions
|
|
||||||
affecting current work), prompt for inclusion and add the Q there.
|
|
||||||
- **Mark withdrawn** — Change the Q's status to `withdrawn` (the DQR
|
|
||||||
system's terminal state for "no longer worth answering"); the
|
|
||||||
user supplies a one-line reason.
|
|
||||||
- **Defer** — Skip until next run.
|
|
||||||
|
|
||||||
**Why:**
|
|
||||||
|
|
||||||
Open questions are useful when they're current; stale ones become
|
|
||||||
ambient noise that drowns the signal of new questions. Most
|
|
||||||
projects don't enforce explicit Q-lifecycle, so without a periodic
|
|
||||||
prompt the open list grows forever. The right action depends on
|
|
||||||
whether the question is still open in fact — not just in metadata —
|
|
||||||
which only the user can confirm.
|
|
||||||
@@ -1,13 +1,12 @@
|
|||||||
---
|
---
|
||||||
name: clide
|
name: clide
|
||||||
description: >
|
description: >
|
||||||
Use when you are running inside the clide IDE and want to observe or drive
|
clide is the IDE hosting this session; it puts `clide` on your PATH and a
|
||||||
its live UI — panes, editor, files, git, readers, toasts, layout — through
|
per-workspace socket in `CLIDE_SOCK`. Start with `clide capabilities` to
|
||||||
the `clide` CLI, or to find out what commands clide exposes. clide is the
|
enumerate the live tool surface, then observe or drive the UI — panes,
|
||||||
IDE hosting this session; it puts `clide` on your PATH and a per-workspace
|
editor, files, git, readers, toasts, layout — via `clide <subsystem> <verb>`.
|
||||||
socket in `CLIDE_SOCK`. Start with `clide capabilities` to enumerate the
|
Triggers: "what can clide do", "drive the clide UI", "open this in clide",
|
||||||
live tool surface. Triggers: "what can clide do", "drive the clide UI",
|
"show the user", "toast", or invoking /clide.
|
||||||
"open this in clide", "show the user", "toast", or invoking /clide.
|
|
||||||
user-invocable: true
|
user-invocable: true
|
||||||
allowed-tools: Bash
|
allowed-tools: Bash
|
||||||
---
|
---
|
||||||
@@ -15,9 +14,10 @@ allowed-tools: Bash
|
|||||||
# Driving clide from the CLI
|
# Driving clide from the CLI
|
||||||
|
|
||||||
You are (often) running **inside clide** — a Flutter IDE that hosts this
|
You are (often) running **inside clide** — a Flutter IDE that hosts this
|
||||||
Claude session. It exposes its whole UI surface as a `clide <subsystem> <verb>`
|
Claude session. It puts `clide` on your PATH and exposes its whole UI surface
|
||||||
CLI on your PATH, talking to the running app over a per-workspace socket
|
as a `clide <subsystem> <verb>` CLI, talking to the running app over a
|
||||||
(`CLIDE_SOCK`). Every UI action the user can take has a CLI verb, and every
|
per-workspace socket (`CLIDE_SOCK`). Every UI action the user can take has a
|
||||||
|
CLI verb, and every
|
||||||
verb's effect is observable — that is the parity contract (D-6). So you can
|
verb's effect is observable — that is the parity contract (D-6). So you can
|
||||||
*see what the user sees* and *show the user what you mean*.
|
*see what the user sees* and *show the user what you mean*.
|
||||||
|
|
||||||
@@ -53,9 +53,11 @@ one). `clide <subsystem>` with no verb, or an unknown command, prints usage.
|
|||||||
|
|
||||||
## Conventions
|
## Conventions
|
||||||
|
|
||||||
- **Slots:** the layout has three content slots — `sidebar` (left), `workspace`
|
- **Slots:** the layout has four content slots — `sidebar` (left), `workspace`
|
||||||
(center, where Claude lives), `context` (right) — plus the bottom `statusbar`.
|
(center, where Claude lives), `context` (right), and `dock` (bottom —
|
||||||
Many verbs take a slot.
|
Output/Problems panes, hidden by default; D-87) — plus the bottom
|
||||||
|
`statusbar`. Many verbs take a slot. The live list is whatever
|
||||||
|
`clide capabilities` reports.
|
||||||
- **Honest failures:** a drive verb with no live GUI returns a `toolError`
|
- **Honest failures:** a drive verb with no live GUI returns a `toolError`
|
||||||
("no live UI to drive"), not a hang. JSON on stdout; exit code conveys
|
("no live UI to drive"), not a hang. JSON on stdout; exit code conveys
|
||||||
ok/usage/tool error.
|
ok/usage/tool error.
|
||||||
|
|||||||
@@ -1,53 +0,0 @@
|
|||||||
---
|
|
||||||
name: commit
|
|
||||||
description: Create a well-formatted git commit with staged changes
|
|
||||||
---
|
|
||||||
|
|
||||||
# Git Commit
|
|
||||||
|
|
||||||
Create a well-formatted commit with staged changes following best practices.
|
|
||||||
|
|
||||||
## Steps
|
|
||||||
|
|
||||||
1. Run `git status --porcelain` to check for changes
|
|
||||||
2. If no staged changes, show unstaged files and ask what to stage
|
|
||||||
3. Run `git diff --cached` to review staged changes
|
|
||||||
4. Generate a commit message following Conventional Commits format:
|
|
||||||
- `feat:` new feature
|
|
||||||
- `fix:` bug fix
|
|
||||||
- `docs:` documentation
|
|
||||||
- `refactor:` code restructuring
|
|
||||||
- `test:` adding tests
|
|
||||||
- `chore:` maintenance
|
|
||||||
5. Create commit with the message, adding Co-Authored-By trailer
|
|
||||||
|
|
||||||
## Commit Message Format
|
|
||||||
|
|
||||||
```
|
|
||||||
<type>(<scope>): <short description>
|
|
||||||
|
|
||||||
<body - what and why, not how>
|
|
||||||
|
|
||||||
Co-Authored-By: Claude <noreply@anthropic.com>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Best Practices
|
|
||||||
|
|
||||||
- Warn about large commits (>500 lines changed)
|
|
||||||
- Suggest splitting large changes into smaller commits
|
|
||||||
- Never skip pre-commit hooks unless explicitly requested
|
|
||||||
|
|
||||||
## Changelog
|
|
||||||
|
|
||||||
After committing, update `CHANGELOG.md` following [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) format:
|
|
||||||
|
|
||||||
1. Add entry under `[Unreleased]` section (create if not exists)
|
|
||||||
2. Categorize changes:
|
|
||||||
- `Added` - new features
|
|
||||||
- `Changed` - changes to existing functionality
|
|
||||||
- `Deprecated` - features marked for removal
|
|
||||||
- `Removed` - removed features
|
|
||||||
- `Fixed` - bug fixes
|
|
||||||
- `Security` - security-related changes
|
|
||||||
3. Write entries in imperative mood: "Add feature" not "Added feature"
|
|
||||||
4. Reference issue numbers where applicable
|
|
||||||
@@ -1,151 +0,0 @@
|
|||||||
---
|
|
||||||
name: d2-diagram
|
|
||||||
description: >
|
|
||||||
Generate technical diagrams using d2 (text-to-diagram CLI). Use when the
|
|
||||||
user says "create a diagram", "draw architecture", "make a flowchart",
|
|
||||||
"diagram this", "render d2", "d2", "data flow diagram", "entity relationship",
|
|
||||||
"state machine", "sequence diagram", "UI flow", or invokes /d2-diagram.
|
|
||||||
Produces .d2 source files and renders them to PNG. Also use when asked
|
|
||||||
to update, re-render, or batch render existing diagrams.
|
|
||||||
---
|
|
||||||
|
|
||||||
# d2 Diagram Generation
|
|
||||||
|
|
||||||
Generate technical diagrams from text using d2 (v0.7.1). Pure CLI, no
|
|
||||||
external dependencies beyond the d2 binary.
|
|
||||||
|
|
||||||
**Binary:** `/home/linuxbrew/.linuxbrew/bin/d2`
|
|
||||||
|
|
||||||
## Project Defaults
|
|
||||||
|
|
||||||
| Setting | Value | Override |
|
|
||||||
|---------|-------|----------|
|
|
||||||
| Theme | 200 (Dark Mauve) | `--theme N` |
|
|
||||||
| Layout | dagre | `--layout elk` |
|
|
||||||
| Padding | 100px | — |
|
|
||||||
| Format | PNG | `--svg` |
|
|
||||||
|
|
||||||
## Output Convention
|
|
||||||
|
|
||||||
```
|
|
||||||
docs/diagrams/
|
|
||||||
architecture/ # System architecture, IPC, component layout
|
|
||||||
data-flow/ # Sequence diagrams, data pipelines
|
|
||||||
entity/ # ER diagrams, ECS component schemas
|
|
||||||
state/ # State machines, behavior trees
|
|
||||||
ui/ # UI navigation flow, screen transitions
|
|
||||||
```
|
|
||||||
|
|
||||||
Both `.d2` source and `.png` output are tracked in git.
|
|
||||||
|
|
||||||
## Single Diagram Workflow
|
|
||||||
|
|
||||||
1. **Determine category** — architecture, data-flow, entity, state, or ui
|
|
||||||
2. **Read template** — `references/diagram-templates.md` for the matching category
|
|
||||||
3. **Read syntax** — `references/d2-syntax-guide.md` if unfamiliar with d2 syntax
|
|
||||||
4. **Write .d2 source** — to `docs/diagrams/{category}/{name}.d2`
|
|
||||||
5. **Validate** — `.claude/skills/d2-diagram/scripts/d2-render.sh validate {file}`
|
|
||||||
6. **Render** — `.claude/skills/d2-diagram/scripts/d2-render.sh {file}`
|
|
||||||
7. **Read SVG** — verify the output, present to user
|
|
||||||
|
|
||||||
### Script Usage
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Render with project defaults
|
|
||||||
.claude/skills/d2-diagram/scripts/d2-render.sh docs/diagrams/architecture/ipc-bridge.d2
|
|
||||||
|
|
||||||
# Validate syntax only
|
|
||||||
.claude/skills/d2-diagram/scripts/d2-render.sh validate docs/diagrams/architecture/ipc-bridge.d2
|
|
||||||
|
|
||||||
# Auto-format source
|
|
||||||
.claude/skills/d2-diagram/scripts/d2-render.sh fmt docs/diagrams/architecture/ipc-bridge.d2
|
|
||||||
|
|
||||||
# Sketch mode (hand-drawn look for drafts)
|
|
||||||
.claude/skills/d2-diagram/scripts/d2-render.sh docs/diagrams/ui/flow.d2 --sketch
|
|
||||||
|
|
||||||
# Light theme (for printable docs)
|
|
||||||
.claude/skills/d2-diagram/scripts/d2-render.sh docs/diagrams/entity/schema.d2 --theme 0
|
|
||||||
|
|
||||||
# SVG output (if specifically needed)
|
|
||||||
.claude/skills/d2-diagram/scripts/d2-render.sh docs/diagrams/architecture/overview.d2 --svg
|
|
||||||
```
|
|
||||||
|
|
||||||
## Batch Render
|
|
||||||
|
|
||||||
Re-render all diagrams after theme or style changes:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# All diagrams
|
|
||||||
.claude/skills/d2-diagram/scripts/d2-batch.sh
|
|
||||||
|
|
||||||
# One category
|
|
||||||
.claude/skills/d2-diagram/scripts/d2-batch.sh docs/diagrams/architecture/
|
|
||||||
|
|
||||||
# Preview what would render
|
|
||||||
.claude/skills/d2-diagram/scripts/d2-batch.sh --dry-run
|
|
||||||
|
|
||||||
# Force re-render everything
|
|
||||||
.claude/skills/d2-diagram/scripts/d2-batch.sh --force
|
|
||||||
```
|
|
||||||
|
|
||||||
Batch skips files whose PNG is newer than the `.d2` source unless `--force`.
|
|
||||||
|
|
||||||
## Advanced Patterns
|
|
||||||
|
|
||||||
### Variables for consistent styling
|
|
||||||
|
|
||||||
```d2
|
|
||||||
vars: {
|
|
||||||
color-bg: "#2a3040"
|
|
||||||
color-stroke: "#333340"
|
|
||||||
color-text: "#c8d0e0"
|
|
||||||
color-accent: "#c8d8f0"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Multi-board (layers)
|
|
||||||
|
|
||||||
```d2
|
|
||||||
# Base diagram here
|
|
||||||
|
|
||||||
layers: {
|
|
||||||
detailed: {
|
|
||||||
# More detailed view
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Sequence diagrams
|
|
||||||
|
|
||||||
```d2
|
|
||||||
shape: sequence_diagram
|
|
||||||
client: Godot Client
|
|
||||||
server: Rust Server
|
|
||||||
|
|
||||||
client -> server: TickRequest(delta)
|
|
||||||
server -> client: WorldState(entities)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Imports
|
|
||||||
|
|
||||||
Split shared definitions into a separate file and import:
|
|
||||||
|
|
||||||
```d2
|
|
||||||
...@shared-defs.d2
|
|
||||||
```
|
|
||||||
|
|
||||||
## Agent Guidance
|
|
||||||
|
|
||||||
- **Qatux** — Architecture decision records, system overview diagrams, data
|
|
||||||
schemas. Prefer architecture and entity templates.
|
|
||||||
- **Tyre** — IPC bridge, ECS system flow, chunk loading pipeline, perception
|
|
||||||
system data flow. Prefer architecture and data-flow templates.
|
|
||||||
- **Araminta** — UI navigation flow, screen transitions, component hierarchy.
|
|
||||||
Prefer UI flow template.
|
|
||||||
|
|
||||||
## References
|
|
||||||
|
|
||||||
- `references/d2-syntax-guide.md` — Language quick reference (shapes, edges,
|
|
||||||
containers, styling, variables). Read when unfamiliar with d2 syntax.
|
|
||||||
- `references/diagram-templates.md` — Five category templates with complete
|
|
||||||
d2 source examples. Read when starting a new diagram.
|
|
||||||
@@ -1,212 +0,0 @@
|
|||||||
# D2 Language Quick Reference
|
|
||||||
|
|
||||||
## Nodes
|
|
||||||
|
|
||||||
```d2
|
|
||||||
server # Implicit label from key
|
|
||||||
server: Simulation Server # Explicit label
|
|
||||||
server: Simulation Server { # With properties
|
|
||||||
shape: hexagon
|
|
||||||
style.fill: "#2d3436"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Edges
|
|
||||||
|
|
||||||
```d2
|
|
||||||
a -> b # Directed
|
|
||||||
a <- b # Reverse directed
|
|
||||||
a <-> b # Bidirectional
|
|
||||||
a -- b # Undirected
|
|
||||||
a -> b: "label" # Labeled edge
|
|
||||||
a -> b -> c # Chained
|
|
||||||
```
|
|
||||||
|
|
||||||
## Containers (nesting)
|
|
||||||
|
|
||||||
```d2
|
|
||||||
infrastructure: {
|
|
||||||
server: Simulation Server
|
|
||||||
database: State Store {
|
|
||||||
shape: cylinder
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Shapes
|
|
||||||
|
|
||||||
| Shape | Use for |
|
|
||||||
|-------|---------|
|
|
||||||
| `rectangle` | Default. Components, modules, generic. |
|
|
||||||
| `hexagon` | Systems, services, major components. |
|
|
||||||
| `cylinder` | Databases, storage, persistent state. |
|
|
||||||
| `diamond` | Decisions, conditions, branch points. |
|
|
||||||
| `oval` / `circle` | Start/end states, events. |
|
|
||||||
| `cloud` | External systems, networks. |
|
|
||||||
| `person` | Actors, users, NPCs. |
|
|
||||||
| `queue` | Message queues, buffers. |
|
|
||||||
| `page` | Documents, files. |
|
|
||||||
| `package` | Packages, modules, crates. |
|
|
||||||
| `sql_table` | Database tables, ECS component schemas. |
|
|
||||||
| `class` | Class diagrams, ECS system definitions. |
|
|
||||||
| `code` | Code blocks (set `language` property). |
|
|
||||||
| `markdown` | Rich text blocks. |
|
|
||||||
|
|
||||||
## SQL Tables
|
|
||||||
|
|
||||||
```d2
|
|
||||||
entity: {
|
|
||||||
shape: sql_table
|
|
||||||
id: u64 {constraint: primary_key}
|
|
||||||
name: String
|
|
||||||
position: Vec2
|
|
||||||
faction_id: u64 {constraint: foreign_key}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Class Diagrams
|
|
||||||
|
|
||||||
```d2
|
|
||||||
perception_system: {
|
|
||||||
shape: class
|
|
||||||
+run(world: &mut World)
|
|
||||||
-calculate_los(entity: Entity): HashSet<Entity>
|
|
||||||
#update_knowledge(entity: Entity, seen: HashSet<Entity>)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Sequence Diagrams
|
|
||||||
|
|
||||||
```d2
|
|
||||||
shape: sequence_diagram
|
|
||||||
client: Godot Client
|
|
||||||
server: Rust Server
|
|
||||||
|
|
||||||
client -> server: TickRequest(delta)
|
|
||||||
server -> server: run ECS systems
|
|
||||||
server -> client: WorldState(entities)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Styling
|
|
||||||
|
|
||||||
```d2
|
|
||||||
node: Label {
|
|
||||||
style: {
|
|
||||||
fill: "#2d3436"
|
|
||||||
stroke: "#333340"
|
|
||||||
stroke-width: 2
|
|
||||||
stroke-dash: 5 # Dashed line
|
|
||||||
opacity: 0.8
|
|
||||||
font-size: 14
|
|
||||||
font-color: "#c8d0e0"
|
|
||||||
bold: true
|
|
||||||
italic: false
|
|
||||||
border-radius: 4
|
|
||||||
shadow: true
|
|
||||||
3d: true # Rectangles only
|
|
||||||
multiple: true # Stacked appearance
|
|
||||||
double-border: true # Rectangles/ovals only
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Edge styling
|
|
||||||
|
|
||||||
```d2
|
|
||||||
a -> b: {
|
|
||||||
style: {
|
|
||||||
stroke: "#c8d8f0"
|
|
||||||
stroke-width: 2
|
|
||||||
stroke-dash: 5
|
|
||||||
opacity: 0.8
|
|
||||||
animated: true # Animated flow
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Variables
|
|
||||||
|
|
||||||
```d2
|
|
||||||
vars: {
|
|
||||||
color-bg: "#1a1e24"
|
|
||||||
color-stroke: "#333340"
|
|
||||||
color-text: "#c8d0e0"
|
|
||||||
color-accent: "#c8d8f0"
|
|
||||||
}
|
|
||||||
|
|
||||||
node: {
|
|
||||||
style.fill: ${color-bg}
|
|
||||||
style.stroke: ${color-stroke}
|
|
||||||
style.font-color: ${color-text}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Direction
|
|
||||||
|
|
||||||
```d2
|
|
||||||
direction: right # left-to-right (default for dagre)
|
|
||||||
direction: down # top-to-bottom
|
|
||||||
direction: up
|
|
||||||
direction: left
|
|
||||||
```
|
|
||||||
|
|
||||||
## Imports
|
|
||||||
|
|
||||||
```d2
|
|
||||||
...@shared-defs.d2 # Spread import (inline all definitions)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Icons
|
|
||||||
|
|
||||||
```d2
|
|
||||||
node: Label {
|
|
||||||
icon: https://icons.terrastruct.com/essentials/time.svg
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Layers (multi-board)
|
|
||||||
|
|
||||||
```d2
|
|
||||||
# Base diagram content here
|
|
||||||
|
|
||||||
layers: {
|
|
||||||
detailed: {
|
|
||||||
# More detailed view
|
|
||||||
}
|
|
||||||
simplified: {
|
|
||||||
# Simplified overview
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Scenarios (animated transitions)
|
|
||||||
|
|
||||||
```d2
|
|
||||||
# Base state
|
|
||||||
|
|
||||||
scenarios: {
|
|
||||||
alert: {
|
|
||||||
# Changes from base for alert state
|
|
||||||
}
|
|
||||||
combat: {
|
|
||||||
# Changes from base for combat state
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Comments
|
|
||||||
|
|
||||||
```d2
|
|
||||||
# This is a comment
|
|
||||||
node: Label # Inline comment
|
|
||||||
```
|
|
||||||
|
|
||||||
## Project Colors (from visual-grammar-v01.md)
|
|
||||||
|
|
||||||
| Constant | Hex | Usage |
|
|
||||||
|----------|-----|-------|
|
|
||||||
| Zone 1 floor | `#1a1e24` | Dark backgrounds |
|
|
||||||
| Zone 1 wall | `#2a3040` | Component fill |
|
|
||||||
| Outline standard | `#333340` | Borders, strokes |
|
|
||||||
| Insert chrome | `#c8d0e0` | Text, labels |
|
|
||||||
| Zone 1 fixture | `#c8d8f0` | Accents, highlights |
|
|
||||||
@@ -1,251 +0,0 @@
|
|||||||
# Diagram Templates
|
|
||||||
|
|
||||||
Copy, adapt, and render. Each template uses project colors from visual-grammar-v01.md.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1. Architecture Diagram
|
|
||||||
|
|
||||||
System components, relationships, communication channels.
|
|
||||||
|
|
||||||
**When to use:** IPC bridge, perception pipeline, chunk loading, ECS system layout, client-server architecture.
|
|
||||||
|
|
||||||
**Agents:** Tyre (system architecture), Qatux (architecture decision records).
|
|
||||||
|
|
||||||
```d2
|
|
||||||
vars: {
|
|
||||||
color-bg: "#2a3040"
|
|
||||||
color-stroke: "#333340"
|
|
||||||
color-text: "#c8d0e0"
|
|
||||||
color-accent: "#c8d8f0"
|
|
||||||
}
|
|
||||||
|
|
||||||
direction: right
|
|
||||||
|
|
||||||
client: Godot Client {
|
|
||||||
shape: hexagon
|
|
||||||
style.fill: ${color-bg}
|
|
||||||
style.font-color: ${color-text}
|
|
||||||
|
|
||||||
rendering: Rendering {
|
|
||||||
style.fill: ${color-bg}
|
|
||||||
style.font-color: ${color-text}
|
|
||||||
}
|
|
||||||
ui: UI Layer {
|
|
||||||
style.fill: ${color-bg}
|
|
||||||
style.font-color: ${color-text}
|
|
||||||
}
|
|
||||||
bridge: IPC Bridge {
|
|
||||||
style.fill: ${color-bg}
|
|
||||||
style.font-color: ${color-text}
|
|
||||||
style.stroke: ${color-accent}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
server: Rust Server {
|
|
||||||
shape: hexagon
|
|
||||||
style.fill: ${color-bg}
|
|
||||||
style.font-color: ${color-text}
|
|
||||||
|
|
||||||
ecs: bevy_ecs {
|
|
||||||
style.fill: ${color-bg}
|
|
||||||
style.font-color: ${color-text}
|
|
||||||
}
|
|
||||||
perception: Perception {
|
|
||||||
style.fill: ${color-bg}
|
|
||||||
style.font-color: ${color-text}
|
|
||||||
}
|
|
||||||
bridge: IPC Bridge {
|
|
||||||
style.fill: ${color-bg}
|
|
||||||
style.font-color: ${color-text}
|
|
||||||
style.stroke: ${color-accent}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
client.bridge -> server.bridge: "stdin/stdout" {
|
|
||||||
style.stroke: ${color-accent}
|
|
||||||
style.stroke-dash: 5
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2. Entity Relationship
|
|
||||||
|
|
||||||
Data schemas, ECS components, knowledge graph structure.
|
|
||||||
|
|
||||||
**When to use:** Database tables, component definitions, entity relationships, knowledge store schema.
|
|
||||||
|
|
||||||
**Agents:** Tyre (ECS component design), Qatux (schema documentation).
|
|
||||||
|
|
||||||
```d2
|
|
||||||
entity: Entity {
|
|
||||||
shape: sql_table
|
|
||||||
id: u64 {constraint: primary_key}
|
|
||||||
name: String
|
|
||||||
faction_id: u64 {constraint: foreign_key}
|
|
||||||
}
|
|
||||||
|
|
||||||
position: Position {
|
|
||||||
shape: sql_table
|
|
||||||
entity_id: u64 {constraint: foreign_key}
|
|
||||||
x: f32
|
|
||||||
y: f32
|
|
||||||
chunk_id: u32
|
|
||||||
}
|
|
||||||
|
|
||||||
knowledge: KnowledgeEntry {
|
|
||||||
shape: sql_table
|
|
||||||
observer_id: u64 {constraint: foreign_key}
|
|
||||||
subject_id: u64 {constraint: foreign_key}
|
|
||||||
fact_type: FactType
|
|
||||||
confidence: f32
|
|
||||||
last_seen_tick: u64
|
|
||||||
}
|
|
||||||
|
|
||||||
entity.id -> position.entity_id
|
|
||||||
entity.id -> knowledge.observer_id
|
|
||||||
entity.id -> knowledge.subject_id
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3. Sequence / Data Flow
|
|
||||||
|
|
||||||
Ordered interactions between systems over time.
|
|
||||||
|
|
||||||
**When to use:** IPC message flow, tick processing, perception update cycle, dialogue system exchanges.
|
|
||||||
|
|
||||||
**Agents:** Tyre (system interaction design), Qatux (protocol documentation).
|
|
||||||
|
|
||||||
```d2
|
|
||||||
shape: sequence_diagram
|
|
||||||
|
|
||||||
client: Godot Client
|
|
||||||
bridge: IPC Bridge
|
|
||||||
server: Rust Server
|
|
||||||
ecs: ECS Systems
|
|
||||||
|
|
||||||
client -> bridge: TickRequest(delta, input)
|
|
||||||
bridge -> server: deserialize + dispatch
|
|
||||||
server -> ecs: run_systems(delta)
|
|
||||||
ecs -> ecs: perception, AI, physics
|
|
||||||
ecs -> server: collect WorldState
|
|
||||||
server -> bridge: serialize WorldState
|
|
||||||
bridge -> client: WorldState(entities, events)
|
|
||||||
client -> client: update rendering
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4. State Machine
|
|
||||||
|
|
||||||
Entity states, transitions, conditions.
|
|
||||||
|
|
||||||
**When to use:** NPC behavior states, game mode transitions, dialogue state, investigation phases.
|
|
||||||
|
|
||||||
**Agents:** Tyre (behavior system design), Qatux (state documentation).
|
|
||||||
|
|
||||||
```d2
|
|
||||||
vars: {
|
|
||||||
color-state: "#2a3040"
|
|
||||||
color-text: "#c8d0e0"
|
|
||||||
color-edge: "#c8d8f0"
|
|
||||||
color-decision: "#333340"
|
|
||||||
}
|
|
||||||
|
|
||||||
idle: Idle {
|
|
||||||
style.fill: ${color-state}
|
|
||||||
style.font-color: ${color-text}
|
|
||||||
}
|
|
||||||
|
|
||||||
alert: Alert {
|
|
||||||
style.fill: ${color-state}
|
|
||||||
style.font-color: ${color-text}
|
|
||||||
}
|
|
||||||
|
|
||||||
investigate: Investigate {
|
|
||||||
style.fill: ${color-state}
|
|
||||||
style.font-color: ${color-text}
|
|
||||||
}
|
|
||||||
|
|
||||||
combat: Combat {
|
|
||||||
style.fill: ${color-state}
|
|
||||||
style.font-color: ${color-text}
|
|
||||||
style.stroke: "#f0b840"
|
|
||||||
}
|
|
||||||
|
|
||||||
flee: Flee {
|
|
||||||
style.fill: ${color-state}
|
|
||||||
style.font-color: ${color-text}
|
|
||||||
}
|
|
||||||
|
|
||||||
idle -> alert: "stimulus detected" { style.stroke: ${color-edge} }
|
|
||||||
alert -> investigate: "stimulus confirmed" { style.stroke: ${color-edge} }
|
|
||||||
alert -> idle: "timeout / stimulus lost" { style.stroke: ${color-edge}; style.stroke-dash: 5 }
|
|
||||||
investigate -> combat: "threat confirmed" { style.stroke: "#f0b840" }
|
|
||||||
investigate -> idle: "nothing found" { style.stroke: ${color-edge}; style.stroke-dash: 5 }
|
|
||||||
combat -> flee: "health < threshold" { style.stroke: "#f0b840" }
|
|
||||||
combat -> idle: "threat eliminated" { style.stroke: ${color-edge}; style.stroke-dash: 5 }
|
|
||||||
flee -> idle: "safe distance reached" { style.stroke: ${color-edge}; style.stroke-dash: 5 }
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5. UI Flow
|
|
||||||
|
|
||||||
Screen navigation, component hierarchy, interaction paths.
|
|
||||||
|
|
||||||
**When to use:** HUD layout relationships, menu navigation, dialogue flow, insert mode transitions.
|
|
||||||
|
|
||||||
**Agents:** Araminta (UI/visual design), Tyre (interface architecture), Qatux (UI documentation).
|
|
||||||
|
|
||||||
```d2
|
|
||||||
vars: {
|
|
||||||
color-screen: "#1a1e24"
|
|
||||||
color-panel: "#2a3040"
|
|
||||||
color-text: "#c8d0e0"
|
|
||||||
color-nav: "#c8d8f0"
|
|
||||||
}
|
|
||||||
|
|
||||||
gameplay: Gameplay {
|
|
||||||
style.fill: ${color-screen}
|
|
||||||
style.font-color: ${color-text}
|
|
||||||
|
|
||||||
hud: HUD {
|
|
||||||
style.fill: ${color-panel}
|
|
||||||
style.font-color: ${color-text}
|
|
||||||
|
|
||||||
minimap: Minimap
|
|
||||||
monologue: Monologue Panel
|
|
||||||
insert_display: Insert Display
|
|
||||||
}
|
|
||||||
|
|
||||||
world: World View {
|
|
||||||
style.fill: ${color-panel}
|
|
||||||
style.font-color: ${color-text}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pause: Pause Menu {
|
|
||||||
style.fill: ${color-screen}
|
|
||||||
style.font-color: ${color-text}
|
|
||||||
|
|
||||||
inventory: Inventory
|
|
||||||
journal: Journal
|
|
||||||
settings: Settings
|
|
||||||
}
|
|
||||||
|
|
||||||
dialogue: Dialogue Mode {
|
|
||||||
style.fill: ${color-screen}
|
|
||||||
style.font-color: ${color-text}
|
|
||||||
|
|
||||||
speaker: Speaker Panel
|
|
||||||
responses: Response List
|
|
||||||
}
|
|
||||||
|
|
||||||
gameplay -> pause: "ESC" { style.stroke: ${color-nav} }
|
|
||||||
pause -> gameplay: "ESC / Resume" { style.stroke: ${color-nav}; style.stroke-dash: 5 }
|
|
||||||
gameplay -> dialogue: "interact with NPC" { style.stroke: ${color-nav} }
|
|
||||||
dialogue -> gameplay: "end conversation" { style.stroke: ${color-nav}; style.stroke-dash: 5 }
|
|
||||||
```
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
||||||
REPO_ROOT="$(cd "$SCRIPT_DIR" && git rev-parse --show-toplevel)"
|
|
||||||
RENDER="$SCRIPT_DIR/d2-render.sh"
|
|
||||||
|
|
||||||
usage() {
|
|
||||||
cat <<EOF
|
|
||||||
Usage: $(basename "$0") [directory] [options]
|
|
||||||
|
|
||||||
Batch render all .d2 files in a directory. Skips files whose PNG is
|
|
||||||
newer than the source unless --force is used.
|
|
||||||
|
|
||||||
Options:
|
|
||||||
--dry-run List files that would be rendered
|
|
||||||
--force Re-render even if SVG is up to date
|
|
||||||
--theme N Override theme for all files
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
$(basename "$0") # All in docs/diagrams/
|
|
||||||
$(basename "$0") docs/diagrams/architecture/ # One category
|
|
||||||
$(basename "$0") --dry-run # Preview
|
|
||||||
$(basename "$0") --force # Re-render everything
|
|
||||||
EOF
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
DIR="$REPO_ROOT/docs/diagrams"
|
|
||||||
DRY_RUN=false
|
|
||||||
FORCE=false
|
|
||||||
EXTRA_ARGS=()
|
|
||||||
|
|
||||||
while [[ $# -gt 0 ]]; do
|
|
||||||
case "$1" in
|
|
||||||
--dry-run) DRY_RUN=true; shift ;;
|
|
||||||
--force) FORCE=true; shift ;;
|
|
||||||
--theme) EXTRA_ARGS+=(--theme "$2"); shift 2 ;;
|
|
||||||
--help|-h) usage ;;
|
|
||||||
*)
|
|
||||||
if [[ -d "$1" ]] || [[ -d "$REPO_ROOT/$1" ]]; then
|
|
||||||
DIR="$1"
|
|
||||||
[[ "$DIR" != /* ]] && DIR="$REPO_ROOT/$DIR"
|
|
||||||
else
|
|
||||||
echo "Unknown option or directory: $1" >&2; exit 1
|
|
||||||
fi
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
[[ ! -d "$DIR" ]] && { echo "ERROR: Directory not found: $DIR" >&2; exit 1; }
|
|
||||||
|
|
||||||
RENDERED=0
|
|
||||||
SKIPPED=0
|
|
||||||
FAILED=0
|
|
||||||
|
|
||||||
while IFS= read -r -d '' d2_file; do
|
|
||||||
png_file="${d2_file%.d2}.png"
|
|
||||||
|
|
||||||
# Skip if PNG is newer than source (unless --force)
|
|
||||||
if [[ "$FORCE" != true ]] && [[ -f "$png_file" ]] && [[ "$png_file" -nt "$d2_file" ]]; then
|
|
||||||
SKIPPED=$((SKIPPED + 1))
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
rel_path="${d2_file#"$REPO_ROOT/"}"
|
|
||||||
|
|
||||||
if [[ "$DRY_RUN" == true ]]; then
|
|
||||||
echo "Would render: $rel_path"
|
|
||||||
RENDERED=$((RENDERED + 1))
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
if "$RENDER" "$d2_file" "${EXTRA_ARGS[@]+"${EXTRA_ARGS[@]}"}"; then
|
|
||||||
RENDERED=$((RENDERED + 1))
|
|
||||||
else
|
|
||||||
echo "FAILED: $rel_path" >&2
|
|
||||||
FAILED=$((FAILED + 1))
|
|
||||||
fi
|
|
||||||
done < <(find "$DIR" -name '*.d2' -print0 | sort -z)
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "Batch complete: $RENDERED rendered, $SKIPPED skipped (up to date), $FAILED failed"
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
D2="/home/linuxbrew/.linuxbrew/bin/d2"
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
||||||
REPO_ROOT="$(cd "$SCRIPT_DIR" && git rev-parse --show-toplevel)"
|
|
||||||
|
|
||||||
DEFAULT_THEME=200
|
|
||||||
DEFAULT_LAYOUT="dagre"
|
|
||||||
DEFAULT_PAD=100
|
|
||||||
|
|
||||||
usage() {
|
|
||||||
cat <<EOF
|
|
||||||
Usage: $(basename "$0") [validate|fmt] <file.d2> [options]
|
|
||||||
|
|
||||||
Render a .d2 file to PNG with project defaults (theme $DEFAULT_THEME, $DEFAULT_LAYOUT layout).
|
|
||||||
|
|
||||||
Commands:
|
|
||||||
validate <file> Check syntax without rendering
|
|
||||||
fmt <file> Auto-format in place
|
|
||||||
|
|
||||||
Options:
|
|
||||||
--theme N Override theme (default: $DEFAULT_THEME)
|
|
||||||
--layout NAME Override layout engine (default: $DEFAULT_LAYOUT)
|
|
||||||
--sketch Enable hand-drawn sketch mode
|
|
||||||
--output PATH Override output path (default: input with .png extension)
|
|
||||||
--svg Render to SVG instead of PNG
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
$(basename "$0") docs/diagrams/architecture/ipc-bridge.d2
|
|
||||||
$(basename "$0") validate docs/diagrams/architecture/ipc-bridge.d2
|
|
||||||
$(basename "$0") docs/diagrams/architecture/ipc-bridge.d2 --sketch --theme 0
|
|
||||||
EOF
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
[[ $# -lt 1 ]] && usage
|
|
||||||
|
|
||||||
# Parse subcommand
|
|
||||||
SUBCMD=""
|
|
||||||
case "$1" in
|
|
||||||
validate|fmt)
|
|
||||||
SUBCMD="$1"
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
[[ $# -lt 1 ]] && usage
|
|
||||||
|
|
||||||
INPUT="$1"
|
|
||||||
shift
|
|
||||||
|
|
||||||
# Resolve to absolute path
|
|
||||||
[[ "$INPUT" != /* ]] && INPUT="$REPO_ROOT/$INPUT"
|
|
||||||
|
|
||||||
[[ ! -f "$INPUT" ]] && { echo "ERROR: File not found: $INPUT" >&2; exit 1; }
|
|
||||||
|
|
||||||
# Handle subcommands
|
|
||||||
if [[ -n "$SUBCMD" ]]; then
|
|
||||||
"$D2" "$SUBCMD" "$INPUT"
|
|
||||||
echo "OK: $SUBCMD $INPUT"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Parse render options
|
|
||||||
THEME="$DEFAULT_THEME"
|
|
||||||
LAYOUT="$DEFAULT_LAYOUT"
|
|
||||||
SKETCH=""
|
|
||||||
OUTPUT=""
|
|
||||||
FORMAT="png"
|
|
||||||
|
|
||||||
while [[ $# -gt 0 ]]; do
|
|
||||||
case "$1" in
|
|
||||||
--theme) THEME="$2"; shift 2 ;;
|
|
||||||
--layout) LAYOUT="$2"; shift 2 ;;
|
|
||||||
--sketch) SKETCH="-s"; shift ;;
|
|
||||||
--output) OUTPUT="$2"; shift 2 ;;
|
|
||||||
--svg) FORMAT="svg"; shift ;;
|
|
||||||
*) echo "Unknown option: $1" >&2; exit 1 ;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
# Derive output path
|
|
||||||
if [[ -z "$OUTPUT" ]]; then
|
|
||||||
OUTPUT="${INPUT%.d2}.$FORMAT"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Render
|
|
||||||
"$D2" -t "$THEME" -l "$LAYOUT" --pad "$DEFAULT_PAD" $SKETCH "$INPUT" "$OUTPUT"
|
|
||||||
|
|
||||||
SIZE=$(stat --printf="%s" "$OUTPUT" 2>/dev/null || stat -f%z "$OUTPUT" 2>/dev/null)
|
|
||||||
echo "Rendered: $OUTPUT ($(( SIZE / 1024 ))KB)"
|
|
||||||
@@ -1,222 +0,0 @@
|
|||||||
---
|
|
||||||
name: frame0-wireframe
|
|
||||||
description: >
|
|
||||||
Create and export UI wireframes using Frame0 (local desktop wireframing
|
|
||||||
app with HTTP API). Use when the user says "create wireframe", "wireframe
|
|
||||||
this", "mock up the UI", "draw a screen", "UI layout", "wireframe the HUD",
|
|
||||||
"Frame0", "frame0", "export wireframe", or invokes /frame0-wireframe.
|
|
||||||
Wireframes are authored as local JSON files (source of truth) and synced
|
|
||||||
to Frame0 for rendering and export. Requires Frame0 to be running locally.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Frame0 Wireframe Generation
|
|
||||||
|
|
||||||
Create UI wireframes as JSON files, sync them to Frame0 for rendering, and
|
|
||||||
export as PNG. Local JSON is the source of truth — Frame0 is the renderer.
|
|
||||||
|
|
||||||
**Frame0 is a renderer, not a workspace.** Treat it as disposable output.
|
|
||||||
Push freely, delete test pages, keep it clean. Never pull from Frame0 unless
|
|
||||||
the user explicitly says they have made edits in Frame0 and want to import
|
|
||||||
them. The pull workflow exists for that case only — do not use it proactively.
|
|
||||||
|
|
||||||
**Prerequisite:** Frame0 desktop app must be running. If not available,
|
|
||||||
stop and inform the user. Point to `references/setup-guide.md`.
|
|
||||||
|
|
||||||
## Health Check
|
|
||||||
|
|
||||||
Always check first:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
.claude/skills/frame0-wireframe/scripts/frame0-cmd.sh health
|
|
||||||
```
|
|
||||||
|
|
||||||
## Core Workflow
|
|
||||||
|
|
||||||
Wireframing is a **design conversation, not a batch job.** Produce **one screen
|
|
||||||
at a time**, show it, and **stop for the user's reaction** before authoring the
|
|
||||||
next. Each shown screen is a checkpoint — never fan out a whole set of
|
|
||||||
wireframes unprompted, even if the user described several screens up front.
|
|
||||||
|
|
||||||
1. **Health check** — verify Frame0 is running
|
|
||||||
2. **Write wireframe JSON** — to `docs/design/wireframes/{category}/{name}.json`.
|
|
||||||
Author **one** screen.
|
|
||||||
3. **Push to Frame0** — `frame0-sync.py push <file.json>`
|
|
||||||
4. **Export PNG** — `frame0-sync.py export <file.json> <output.png>`
|
|
||||||
5. **Show it inline** — surface the exported PNG in the conversation so the
|
|
||||||
user sees the result without opening Frame0. Always do this after an export,
|
|
||||||
and again whenever you re-export or the user asks to see it.
|
|
||||||
- **Inside clide** (the IDE hosting this session — `CLIDE_SOCK` is set):
|
|
||||||
render it as a native image card in the live Claude pane with
|
|
||||||
`clide image show <path> [--caption "…"]` (T-249). This is the *proper*
|
|
||||||
way to put an image in the clide conversation — a bare `Read` only shows
|
|
||||||
it in the transcript, not in the UI the user is looking at.
|
|
||||||
- **Otherwise**: `Read` the PNG so it renders inline in the transcript.
|
|
||||||
6. **STOP and wait for approval** — after showing a screen, pause and ask the
|
|
||||||
user for feedback. Do **not** author, push, or export the next screen until
|
|
||||||
they give an explicit go-ahead. Iterate on the current screen until they're
|
|
||||||
happy, then proceed to the next one — looping back to step 2 for each.
|
|
||||||
7. **Clean up** — delete test/scratch pages from Frame0 when done
|
|
||||||
|
|
||||||
> **Multi-screen requests are still one-at-a-time.** If the user asks for
|
|
||||||
> several screens, treat it as a queue: build the first, show it, get approval,
|
|
||||||
> then move on. The only exception is an explicit, unambiguous instruction to
|
|
||||||
> generate a batch without stopping (and even then prefer the batch-export
|
|
||||||
> dry-run + approval flow below).
|
|
||||||
|
|
||||||
### Scripts
|
|
||||||
|
|
||||||
| Script | Purpose |
|
|
||||||
|--------|---------|
|
|
||||||
| `scripts/frame0-sync.py` | **Primary.** Push/pull/export wireframes between JSON and Frame0 |
|
|
||||||
| `scripts/frame0-cmd.sh` | Low-level API wrapper for ad-hoc commands |
|
|
||||||
|
|
||||||
## Wireframe JSON Format
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"name": "Dialogue Box",
|
|
||||||
"shapes": {
|
|
||||||
"panel": {
|
|
||||||
"type": "Rectangle",
|
|
||||||
"left": 170, "top": 500, "width": 800, "height": 260,
|
|
||||||
"fillColor": "#1a1e24",
|
|
||||||
"strokeColor": "#333340",
|
|
||||||
"corners": [8, 8, 8, 8]
|
|
||||||
},
|
|
||||||
"speaker": {
|
|
||||||
"type": "Text",
|
|
||||||
"parent": "panel",
|
|
||||||
"left": 190, "top": 520,
|
|
||||||
"text": "LERA KONSTANTIN",
|
|
||||||
"fontColor": "#c8d0e0",
|
|
||||||
"fontSize": 16
|
|
||||||
},
|
|
||||||
"btn-ask": {
|
|
||||||
"type": "Rectangle",
|
|
||||||
"parent": "panel",
|
|
||||||
"left": 190, "top": 670, "width": 370, "height": 30,
|
|
||||||
"fillColor": "#2a3040",
|
|
||||||
"strokeColor": "#c8d8f0",
|
|
||||||
"corners": [4, 4, 4, 4]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"connectors": {
|
|
||||||
"flow-1": {
|
|
||||||
"tailId": "panel",
|
|
||||||
"headId": "btn-ask",
|
|
||||||
"strokeColor": "#c8d8f0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Key rules
|
|
||||||
|
|
||||||
- **Shape IDs are stable local IDs** you control (e.g. `"panel"`, `"btn-ask"`)
|
|
||||||
- **`parent`** references another local shape ID for nesting
|
|
||||||
- **`type`** uses create-API names: `Rectangle`, `Ellipse`, `Text`, `Line`
|
|
||||||
- **Colors** can be hex (`#2a3040`) or Frame0 theme tokens (`$slate6`)
|
|
||||||
- After a pull, Frame0 returns its native vocabulary (`Box` for Rectangle,
|
|
||||||
theme tokens for colors). The sync script handles the mapping transparently.
|
|
||||||
- The `.idmap.json` mapping file (gitignored) tracks local ID ↔ Frame0 ID
|
|
||||||
|
|
||||||
### Sync commands
|
|
||||||
|
|
||||||
```bash
|
|
||||||
SYNC=".claude/skills/frame0-wireframe/scripts/frame0-sync.py"
|
|
||||||
|
|
||||||
# Push local JSON to Frame0 (clears page, recreates all shapes)
|
|
||||||
$SYNC push docs/design/wireframes/dialogue/dialogue-box.json
|
|
||||||
|
|
||||||
# Pull Frame0 page back to local JSON (preserves local IDs via mapping)
|
|
||||||
$SYNC pull "Dialogue Box" docs/design/wireframes/dialogue/dialogue-box.json
|
|
||||||
|
|
||||||
# Push + export as PNG in one step
|
|
||||||
$SYNC export docs/design/wireframes/dialogue/dialogue-box.json \
|
|
||||||
docs/design/wireframes/dialogue/dialogue-box.png
|
|
||||||
```
|
|
||||||
|
|
||||||
### Batch export
|
|
||||||
|
|
||||||
Use this when exporting multiple wireframes. It runs as a single Bash call,
|
|
||||||
avoiding repeated permission prompts.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
BATCH=".claude/skills/frame0-wireframe/scripts/frame0-export-batch.sh"
|
|
||||||
|
|
||||||
# Dry run first — shows full manifest, no Frame0 calls
|
|
||||||
$BATCH --dry-run
|
|
||||||
|
|
||||||
# Export everything (skips PNGs already newer than their JSON)
|
|
||||||
$BATCH
|
|
||||||
|
|
||||||
# Export one category only
|
|
||||||
$BATCH --category dialogue
|
|
||||||
|
|
||||||
# Force re-export of everything
|
|
||||||
$BATCH --force
|
|
||||||
```
|
|
||||||
|
|
||||||
**Always dry-run first, then get approval before running the live export.**
|
|
||||||
|
|
||||||
## Low-Level Commands
|
|
||||||
|
|
||||||
For ad-hoc operations or exec calls not covered by sync:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
CMD=".claude/skills/frame0-wireframe/scripts/frame0-cmd.sh"
|
|
||||||
$CMD health
|
|
||||||
$CMD list-pages
|
|
||||||
$CMD current-page
|
|
||||||
$CMD get-page <page-id>
|
|
||||||
$CMD create-shape Rectangle '{"name":"btn","left":100,"top":100,"width":120,"height":36}'
|
|
||||||
$CMD create-connector <tail-id> <head-id>
|
|
||||||
$CMD move <shape-id> <dx> <dy>
|
|
||||||
$CMD export --format image/png
|
|
||||||
$CMD exec "view:fit-to-screen" '{}'
|
|
||||||
```
|
|
||||||
|
|
||||||
If you find yourself using `exec` for the same command repeatedly, flag it as
|
|
||||||
a candidate for a proper wrapper in `frame0-cmd.sh`.
|
|
||||||
|
|
||||||
## Project Styling Defaults
|
|
||||||
|
|
||||||
Colors from `docs/design/visual-grammar-v01.md`:
|
|
||||||
|
|
||||||
| Role | Hex | Frame0 token |
|
|
||||||
|------|-----|-------------|
|
|
||||||
| Background | `#1a1e24` | `$sage3` |
|
|
||||||
| Stroke | `#333340` | `$slate6` |
|
|
||||||
| Fill | `#2a3040` | `$slate5` |
|
|
||||||
| Text | `#c8d0e0` | `$mint12` |
|
|
||||||
| Accent | `#c8d8f0` | `$blue12` |
|
|
||||||
|
|
||||||
Use hex when authoring new wireframes. Frame0 maps them to theme tokens on push.
|
|
||||||
|
|
||||||
## Output Convention
|
|
||||||
|
|
||||||
```
|
|
||||||
docs/design/wireframes/
|
|
||||||
hud/ # HUD layout wireframes
|
|
||||||
menus/ # Menu screen wireframes
|
|
||||||
dialogue/ # Dialogue box wireframes
|
|
||||||
insert/ # Neural insert wireframes
|
|
||||||
```
|
|
||||||
|
|
||||||
Both `.json` source and `.png` exports are tracked in git.
|
|
||||||
`.idmap.json` mapping files are gitignored.
|
|
||||||
|
|
||||||
## Agent Guidance
|
|
||||||
|
|
||||||
- **Araminta** — Primary user. Full wireframe creation, layout iteration,
|
|
||||||
visual consistency. Uses all component library patterns.
|
|
||||||
- **Tyre** — Interface architecture wireframes. System boundary diagrams.
|
|
||||||
- **Qatux** — Export wireframes for UI decision records and documentation.
|
|
||||||
|
|
||||||
## References
|
|
||||||
|
|
||||||
- `references/component-library.md` — Pre-built JSON wireframe templates
|
|
||||||
(HUD, dialogue, menus, modals, lists, inventory). Copy and adapt.
|
|
||||||
- `references/api-reference.md` — Frame0 HTTP API command reference and
|
|
||||||
type mappings. Read for low-level control.
|
|
||||||
- `references/setup-guide.md` — Frame0 installation and startup for Fedora.
|
|
||||||
@@ -1,241 +0,0 @@
|
|||||||
# Frame0 HTTP API Reference
|
|
||||||
|
|
||||||
Frame0 exposes a local HTTP API when the desktop app is running.
|
|
||||||
|
|
||||||
## Endpoint
|
|
||||||
|
|
||||||
```
|
|
||||||
POST http://localhost:{port}/execute_command
|
|
||||||
Content-Type: application/json
|
|
||||||
```
|
|
||||||
|
|
||||||
Default port: **58320** (override via `FRAME0_PORT` env var or `--port` flag).
|
|
||||||
|
|
||||||
## Request / Response
|
|
||||||
|
|
||||||
```json
|
|
||||||
{"command": "namespace:action", "args": { ... }}
|
|
||||||
```
|
|
||||||
|
|
||||||
```json
|
|
||||||
{"success": true, "data": { ... }}
|
|
||||||
{"success": false, "error": "description"}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Type Mapping
|
|
||||||
|
|
||||||
Frame0 uses different type names for create vs get:
|
|
||||||
|
|
||||||
| Create API (`type`) | Get API (internal) | Description |
|
|
||||||
|--------------------|--------------------|-------------|
|
|
||||||
| `Rectangle` | `Box` | Rectangle with optional corners |
|
|
||||||
| `Ellipse` | `Ellipse` | Circle/ellipse |
|
|
||||||
| `Text` | `Text` | Text label |
|
|
||||||
| `Line` | `Line` | Line/polyline |
|
|
||||||
| `Frame` | `Frame` | Container from library |
|
|
||||||
| `Freehand` | `Freehand` | Freehand drawing |
|
|
||||||
| `Highlighter` | `Highlighter` | Highlighter stroke |
|
|
||||||
|
|
||||||
The sync script handles this mapping transparently.
|
|
||||||
|
|
||||||
## Color Tokens
|
|
||||||
|
|
||||||
Frame0 maps hex colors to theme tokens on creation (`convertColors: true`):
|
|
||||||
|
|
||||||
| Hex | Token | Role |
|
|
||||||
|-----|-------|------|
|
|
||||||
| `#1a1e24` | `$sage3` | Background |
|
|
||||||
| `#2a3040` | `$slate5` | Fill |
|
|
||||||
| `#333340` | `$slate6` | Stroke |
|
|
||||||
| `#c8d0e0` | `$mint12` | Text |
|
|
||||||
| `#c8d8f0` | `$blue12` | Accent |
|
|
||||||
|
|
||||||
Both hex and token strings work in the API. Tokens are preserved on round-trip.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Commands
|
|
||||||
|
|
||||||
### shape:create-shape
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"command": "shape:create-shape",
|
|
||||||
"args": {
|
|
||||||
"type": "Rectangle",
|
|
||||||
"shapeProps": {
|
|
||||||
"name": "my-button",
|
|
||||||
"left": 100, "top": 200, "width": 120, "height": 36,
|
|
||||||
"fillColor": "#2a3040",
|
|
||||||
"strokeColor": "#c8d8f0",
|
|
||||||
"corners": [4, 4, 4, 4]
|
|
||||||
},
|
|
||||||
"parentId": "optional-parent-shape-id",
|
|
||||||
"convertColors": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Returns: shape ID (string).
|
|
||||||
|
|
||||||
### shape:get-shape
|
|
||||||
|
|
||||||
```json
|
|
||||||
{"command": "shape:get-shape", "args": {"shapeId": "id"}}
|
|
||||||
```
|
|
||||||
|
|
||||||
### shape:update-shape
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"command": "shape:update-shape",
|
|
||||||
"args": {
|
|
||||||
"shapeId": "id",
|
|
||||||
"shapeProps": {"fillColor": "#1a1e24", "text": "Updated"},
|
|
||||||
"convertColors": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### shape:move
|
|
||||||
|
|
||||||
```json
|
|
||||||
{"command": "shape:move", "args": {"shapeId": "id", "dx": 50, "dy": -20}}
|
|
||||||
```
|
|
||||||
|
|
||||||
### shape:create-connector
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"command": "shape:create-connector",
|
|
||||||
"args": {
|
|
||||||
"tailId": "source-id",
|
|
||||||
"headId": "target-id",
|
|
||||||
"shapeProps": {"strokeColor": "#c8d8f0"},
|
|
||||||
"convertColors": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### shape:create-icon
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"command": "shape:create-icon",
|
|
||||||
"args": {
|
|
||||||
"iconName": "search",
|
|
||||||
"shapeProps": {"left": 100, "top": 100, "width": 24, "height": 24}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### shape:get-available-icons
|
|
||||||
|
|
||||||
```json
|
|
||||||
{"command": "shape:get-available-icons", "args": {}}
|
|
||||||
```
|
|
||||||
|
|
||||||
### shape:group / shape:ungroup
|
|
||||||
|
|
||||||
```json
|
|
||||||
{"command": "shape:group", "args": {"shapeIdArray": ["id1", "id2"]}}
|
|
||||||
{"command": "shape:ungroup", "args": {"shapeIdArray": ["group-id"]}}
|
|
||||||
```
|
|
||||||
|
|
||||||
### edit:delete / edit:duplicate
|
|
||||||
|
|
||||||
```json
|
|
||||||
{"command": "edit:delete", "args": {"shapeIdArray": ["id1", "id2"]}}
|
|
||||||
{"command": "edit:duplicate", "args": {"shapeIdArray": ["id"], "dx": 20, "dy": 0}}
|
|
||||||
```
|
|
||||||
|
|
||||||
### page:add
|
|
||||||
|
|
||||||
```json
|
|
||||||
{"command": "page:add", "args": {"pageProps": {"name": "Page Name"}}}
|
|
||||||
```
|
|
||||||
|
|
||||||
Returns: `{id, type, name}`.
|
|
||||||
|
|
||||||
### page:get
|
|
||||||
|
|
||||||
```json
|
|
||||||
{"command": "page:get", "args": {"pageId": "id", "exportShapes": true}}
|
|
||||||
```
|
|
||||||
|
|
||||||
### page:get-current-page
|
|
||||||
|
|
||||||
```json
|
|
||||||
{"command": "page:get-current-page", "args": {}}
|
|
||||||
```
|
|
||||||
|
|
||||||
Returns: page ID string.
|
|
||||||
|
|
||||||
### page:set-current-page
|
|
||||||
|
|
||||||
```json
|
|
||||||
{"command": "page:set-current-page", "args": {"pageId": "id"}}
|
|
||||||
```
|
|
||||||
|
|
||||||
### doc:get (list all pages)
|
|
||||||
|
|
||||||
```json
|
|
||||||
{"command": "doc:get", "args": {"exportPages": true, "exportShapes": false}}
|
|
||||||
```
|
|
||||||
|
|
||||||
### page:delete
|
|
||||||
|
|
||||||
```json
|
|
||||||
{"command": "page:delete", "args": {"pageId": "id"}}
|
|
||||||
```
|
|
||||||
|
|
||||||
### file:export-image
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"command": "file:export-image",
|
|
||||||
"args": {
|
|
||||||
"pageId": "optional-page-id",
|
|
||||||
"format": "image/png",
|
|
||||||
"fillBackground": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Formats: `image/png`, `image/jpeg`, `image/webp`, `image/svg+xml`.
|
|
||||||
Returns: base64-encoded image data.
|
|
||||||
|
|
||||||
### view:fit-to-screen
|
|
||||||
|
|
||||||
```json
|
|
||||||
{"command": "view:fit-to-screen", "args": {}}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Shape Properties
|
|
||||||
|
|
||||||
| Property | Type | Notes |
|
|
||||||
|----------|------|-------|
|
|
||||||
| `name` | string | Shape identifier/label |
|
|
||||||
| `left` | number | X position (origin: top-left) |
|
|
||||||
| `top` | number | Y position |
|
|
||||||
| `width` | number | Width in pixels |
|
|
||||||
| `height` | number | Height in pixels |
|
|
||||||
| `fillColor` | string | Hex or `$token` |
|
|
||||||
| `strokeColor` | string | Hex or `$token` |
|
|
||||||
| `strokeWidth` | number | Border width |
|
|
||||||
| `fontColor` | string | Text color (hex or `$token`) |
|
|
||||||
| `fontSize` | number | Font size in pixels |
|
|
||||||
| `fontFamily` | string | Font name (Frame0 default: `Loranthus`) |
|
|
||||||
| `text` | string | Text content |
|
|
||||||
| `wordWrap` | boolean | Enable word wrapping |
|
|
||||||
| `corners` | number[4] | Border radius [TL, TR, BR, BL] |
|
|
||||||
| `roughness` | number | Sketch roughness (Frame0 default: 1) |
|
|
||||||
| `constraints` | array | Auto-sizing constraints |
|
|
||||||
| `horzAlign` | string | Horizontal text alignment |
|
|
||||||
| `vertAlign` | string | Vertical text alignment |
|
|
||||||
| `fillStyle` | string | Fill style (`none` for transparent) |
|
|
||||||
| `path` | array | Coordinate pairs for lines |
|
|
||||||
@@ -1,467 +0,0 @@
|
|||||||
# Component Library
|
|
||||||
|
|
||||||
Pre-built wireframe JSON templates for The Settled Reach UI. Copy the JSON,
|
|
||||||
adapt positions/sizes, save to `docs/design/wireframes/{category}/`, and push.
|
|
||||||
|
|
||||||
**Viewport:** 1140x780 (Godot project settings)
|
|
||||||
**Grid unit:** 8px
|
|
||||||
**Min touch target:** 36px height
|
|
||||||
**Font sizes:** 12 (label), 14 (body), 16 (subtitle), 18 (heading), 24 (title)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1. HUD Layout
|
|
||||||
|
|
||||||
Main gameplay overlay. Minimap top-right, monologue bottom-center,
|
|
||||||
insert display bottom-left, action hints bottom-right.
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"name": "HUD Layout",
|
|
||||||
"shapes": {
|
|
||||||
"minimap": {
|
|
||||||
"type": "Rectangle",
|
|
||||||
"left": 880, "top": 20, "width": 240, "height": 240,
|
|
||||||
"fillColor": "#1a1e24", "strokeColor": "#333340",
|
|
||||||
"corners": [4, 4, 4, 4]
|
|
||||||
},
|
|
||||||
"minimap-label": {
|
|
||||||
"type": "Text",
|
|
||||||
"parent": "minimap",
|
|
||||||
"left": 890, "top": 30,
|
|
||||||
"text": "Minimap",
|
|
||||||
"fontColor": "#c8d0e0", "fontSize": 14
|
|
||||||
},
|
|
||||||
"monologue": {
|
|
||||||
"type": "Rectangle",
|
|
||||||
"left": 300, "top": 680, "width": 520, "height": 80,
|
|
||||||
"fillColor": "#1a1e24", "strokeColor": "#333340",
|
|
||||||
"corners": [4, 4, 4, 4]
|
|
||||||
},
|
|
||||||
"monologue-text": {
|
|
||||||
"type": "Text",
|
|
||||||
"parent": "monologue",
|
|
||||||
"left": 310, "top": 700, "width": 500,
|
|
||||||
"text": "Internal monologue text appears here...",
|
|
||||||
"fontColor": "#c8d0e0", "fontSize": 13, "wordWrap": true
|
|
||||||
},
|
|
||||||
"insert": {
|
|
||||||
"type": "Rectangle",
|
|
||||||
"left": 20, "top": 600, "width": 260, "height": 160,
|
|
||||||
"fillColor": "#1a1e24", "strokeColor": "#333340",
|
|
||||||
"corners": [4, 4, 4, 4]
|
|
||||||
},
|
|
||||||
"insert-label": {
|
|
||||||
"type": "Text",
|
|
||||||
"parent": "insert",
|
|
||||||
"left": 30, "top": 620,
|
|
||||||
"text": "Neural Insert Data",
|
|
||||||
"fontColor": "#c8d0e0", "fontSize": 14
|
|
||||||
},
|
|
||||||
"hints": {
|
|
||||||
"type": "Rectangle",
|
|
||||||
"left": 880, "top": 700, "width": 240, "height": 60,
|
|
||||||
"fillColor": "#1a1e24", "strokeColor": "#333340",
|
|
||||||
"corners": [4, 4, 4, 4]
|
|
||||||
},
|
|
||||||
"hints-label": {
|
|
||||||
"type": "Text",
|
|
||||||
"parent": "hints",
|
|
||||||
"left": 890, "top": 720,
|
|
||||||
"text": "[E] Interact [TAB] Insert",
|
|
||||||
"fontColor": "#c8d0e0", "fontSize": 12
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2. Dialogue Box
|
|
||||||
|
|
||||||
Speaker panel with response options. Anchored bottom-center during dialogue mode.
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"name": "Dialogue Box",
|
|
||||||
"shapes": {
|
|
||||||
"panel": {
|
|
||||||
"type": "Rectangle",
|
|
||||||
"left": 170, "top": 500, "width": 800, "height": 260,
|
|
||||||
"fillColor": "#1a1e24", "strokeColor": "#333340",
|
|
||||||
"corners": [8, 8, 8, 8]
|
|
||||||
},
|
|
||||||
"speaker": {
|
|
||||||
"type": "Text",
|
|
||||||
"parent": "panel",
|
|
||||||
"left": 190, "top": 520,
|
|
||||||
"text": "LERA KONSTANTIN",
|
|
||||||
"fontColor": "#c8d0e0", "fontSize": 16
|
|
||||||
},
|
|
||||||
"text-area": {
|
|
||||||
"type": "Rectangle",
|
|
||||||
"parent": "panel",
|
|
||||||
"left": 190, "top": 550, "width": 760, "height": 100,
|
|
||||||
"fillColor": "#2a3040", "strokeColor": "#333340",
|
|
||||||
"corners": [4, 4, 4, 4]
|
|
||||||
},
|
|
||||||
"dialogue-text": {
|
|
||||||
"type": "Text",
|
|
||||||
"parent": "text-area",
|
|
||||||
"left": 200, "top": 560, "width": 740,
|
|
||||||
"text": "You look like you could use a drink. First time on the station?",
|
|
||||||
"fontColor": "#c8d0e0", "fontSize": 14, "wordWrap": true
|
|
||||||
},
|
|
||||||
"btn-option1": {
|
|
||||||
"type": "Rectangle",
|
|
||||||
"parent": "panel",
|
|
||||||
"left": 190, "top": 670, "width": 370, "height": 30,
|
|
||||||
"fillColor": "#2a3040", "strokeColor": "#c8d8f0",
|
|
||||||
"corners": [4, 4, 4, 4]
|
|
||||||
},
|
|
||||||
"btn-option1-label": {
|
|
||||||
"type": "Text",
|
|
||||||
"parent": "btn-option1",
|
|
||||||
"left": 200, "top": 674,
|
|
||||||
"text": "[1] Ask about the station",
|
|
||||||
"fontColor": "#c8d8f0", "fontSize": 12
|
|
||||||
},
|
|
||||||
"btn-option2": {
|
|
||||||
"type": "Rectangle",
|
|
||||||
"parent": "panel",
|
|
||||||
"left": 190, "top": 710, "width": 370, "height": 30,
|
|
||||||
"fillColor": "#2a3040", "strokeColor": "#c8d8f0",
|
|
||||||
"corners": [4, 4, 4, 4]
|
|
||||||
},
|
|
||||||
"btn-option2-label": {
|
|
||||||
"type": "Text",
|
|
||||||
"parent": "btn-option2",
|
|
||||||
"left": 200, "top": 714,
|
|
||||||
"text": "[2] Ask about recent events",
|
|
||||||
"fontColor": "#c8d8f0", "fontSize": 12
|
|
||||||
},
|
|
||||||
"btn-leave": {
|
|
||||||
"type": "Rectangle",
|
|
||||||
"parent": "panel",
|
|
||||||
"left": 580, "top": 670, "width": 180, "height": 30,
|
|
||||||
"fillColor": "#2a3040", "strokeColor": "#c8d8f0",
|
|
||||||
"corners": [4, 4, 4, 4]
|
|
||||||
},
|
|
||||||
"btn-leave-label": {
|
|
||||||
"type": "Text",
|
|
||||||
"parent": "btn-leave",
|
|
||||||
"left": 590, "top": 674,
|
|
||||||
"text": "[3] Leave",
|
|
||||||
"fontColor": "#c8d8f0", "fontSize": 12
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3. Menu Screen
|
|
||||||
|
|
||||||
Full-screen menu with sidebar navigation and content area.
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"name": "Pause Menu",
|
|
||||||
"shapes": {
|
|
||||||
"bg": {
|
|
||||||
"type": "Rectangle",
|
|
||||||
"left": 0, "top": 0, "width": 1140, "height": 780,
|
|
||||||
"fillColor": "#1a1e24"
|
|
||||||
},
|
|
||||||
"nav": {
|
|
||||||
"type": "Rectangle",
|
|
||||||
"parent": "bg",
|
|
||||||
"left": 20, "top": 20, "width": 200, "height": 740,
|
|
||||||
"fillColor": "#2a3040", "strokeColor": "#333340",
|
|
||||||
"corners": [4, 4, 4, 4]
|
|
||||||
},
|
|
||||||
"btn-inventory": {
|
|
||||||
"type": "Rectangle", "parent": "nav",
|
|
||||||
"left": 30, "top": 40, "width": 180, "height": 36,
|
|
||||||
"fillColor": "#2a3040", "strokeColor": "#c8d8f0", "corners": [4, 4, 4, 4]
|
|
||||||
},
|
|
||||||
"btn-inventory-label": {
|
|
||||||
"type": "Text", "parent": "btn-inventory",
|
|
||||||
"left": 40, "top": 48, "text": "Inventory",
|
|
||||||
"fontColor": "#c8d8f0", "fontSize": 14
|
|
||||||
},
|
|
||||||
"btn-journal": {
|
|
||||||
"type": "Rectangle", "parent": "nav",
|
|
||||||
"left": 30, "top": 86, "width": 180, "height": 36,
|
|
||||||
"fillColor": "#2a3040", "strokeColor": "#c8d8f0", "corners": [4, 4, 4, 4]
|
|
||||||
},
|
|
||||||
"btn-journal-label": {
|
|
||||||
"type": "Text", "parent": "btn-journal",
|
|
||||||
"left": 40, "top": 94, "text": "Journal",
|
|
||||||
"fontColor": "#c8d8f0", "fontSize": 14
|
|
||||||
},
|
|
||||||
"btn-map": {
|
|
||||||
"type": "Rectangle", "parent": "nav",
|
|
||||||
"left": 30, "top": 132, "width": 180, "height": 36,
|
|
||||||
"fillColor": "#2a3040", "strokeColor": "#c8d8f0", "corners": [4, 4, 4, 4]
|
|
||||||
},
|
|
||||||
"btn-map-label": {
|
|
||||||
"type": "Text", "parent": "btn-map",
|
|
||||||
"left": 40, "top": 140, "text": "Map",
|
|
||||||
"fontColor": "#c8d8f0", "fontSize": 14
|
|
||||||
},
|
|
||||||
"btn-settings": {
|
|
||||||
"type": "Rectangle", "parent": "nav",
|
|
||||||
"left": 30, "top": 178, "width": 180, "height": 36,
|
|
||||||
"fillColor": "#2a3040", "strokeColor": "#c8d8f0", "corners": [4, 4, 4, 4]
|
|
||||||
},
|
|
||||||
"btn-settings-label": {
|
|
||||||
"type": "Text", "parent": "btn-settings",
|
|
||||||
"left": 40, "top": 186, "text": "Settings",
|
|
||||||
"fontColor": "#c8d8f0", "fontSize": 14
|
|
||||||
},
|
|
||||||
"btn-resume": {
|
|
||||||
"type": "Rectangle", "parent": "nav",
|
|
||||||
"left": 30, "top": 720, "width": 180, "height": 36,
|
|
||||||
"fillColor": "#2a3040", "strokeColor": "#c8d8f0", "corners": [4, 4, 4, 4]
|
|
||||||
},
|
|
||||||
"btn-resume-label": {
|
|
||||||
"type": "Text", "parent": "btn-resume",
|
|
||||||
"left": 40, "top": 728, "text": "Resume",
|
|
||||||
"fontColor": "#c8d8f0", "fontSize": 14
|
|
||||||
},
|
|
||||||
"content": {
|
|
||||||
"type": "Rectangle",
|
|
||||||
"parent": "bg",
|
|
||||||
"left": 240, "top": 20, "width": 880, "height": 740,
|
|
||||||
"fillColor": "#2a3040", "strokeColor": "#333340",
|
|
||||||
"corners": [4, 4, 4, 4]
|
|
||||||
},
|
|
||||||
"content-label": {
|
|
||||||
"type": "Text", "parent": "content",
|
|
||||||
"left": 260, "top": 40,
|
|
||||||
"text": "Content area",
|
|
||||||
"fontColor": "#c8d0e0", "fontSize": 14
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4. Modal Dialog
|
|
||||||
|
|
||||||
Centered overlay for confirmations, alerts, choices.
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"name": "Modal Dialog",
|
|
||||||
"shapes": {
|
|
||||||
"overlay": {
|
|
||||||
"type": "Rectangle",
|
|
||||||
"left": 0, "top": 0, "width": 1140, "height": 780,
|
|
||||||
"fillColor": "#0a0c10"
|
|
||||||
},
|
|
||||||
"modal": {
|
|
||||||
"type": "Rectangle",
|
|
||||||
"parent": "overlay",
|
|
||||||
"left": 320, "top": 240, "width": 500, "height": 300,
|
|
||||||
"fillColor": "#1a1e24", "strokeColor": "#333340",
|
|
||||||
"corners": [8, 8, 8, 8]
|
|
||||||
},
|
|
||||||
"title": {
|
|
||||||
"type": "Text", "parent": "modal",
|
|
||||||
"left": 340, "top": 260,
|
|
||||||
"text": "Confirm Action",
|
|
||||||
"fontColor": "#c8d0e0", "fontSize": 18
|
|
||||||
},
|
|
||||||
"divider": {
|
|
||||||
"type": "Line", "parent": "modal",
|
|
||||||
"left": 340, "top": 290, "width": 460, "height": 0,
|
|
||||||
"strokeColor": "#333340"
|
|
||||||
},
|
|
||||||
"body-1": {
|
|
||||||
"type": "Text", "parent": "modal",
|
|
||||||
"left": 340, "top": 310,
|
|
||||||
"text": "Are you sure you want to proceed?",
|
|
||||||
"fontColor": "#c8d0e0", "fontSize": 14
|
|
||||||
},
|
|
||||||
"body-2": {
|
|
||||||
"type": "Text", "parent": "modal",
|
|
||||||
"left": 340, "top": 340,
|
|
||||||
"text": "This action cannot be undone.",
|
|
||||||
"fontColor": "#c8d0e0", "fontSize": 14
|
|
||||||
},
|
|
||||||
"btn-cancel": {
|
|
||||||
"type": "Rectangle", "parent": "modal",
|
|
||||||
"left": 480, "top": 480, "width": 120, "height": 36,
|
|
||||||
"fillColor": "#2a3040", "strokeColor": "#c8d8f0", "corners": [4, 4, 4, 4]
|
|
||||||
},
|
|
||||||
"btn-cancel-label": {
|
|
||||||
"type": "Text", "parent": "btn-cancel",
|
|
||||||
"left": 510, "top": 488,
|
|
||||||
"text": "Cancel",
|
|
||||||
"fontColor": "#c8d8f0", "fontSize": 14
|
|
||||||
},
|
|
||||||
"btn-confirm": {
|
|
||||||
"type": "Rectangle", "parent": "modal",
|
|
||||||
"left": 620, "top": 480, "width": 120, "height": 36,
|
|
||||||
"fillColor": "#2a3040", "strokeColor": "#c8d8f0", "corners": [4, 4, 4, 4]
|
|
||||||
},
|
|
||||||
"btn-confirm-label": {
|
|
||||||
"type": "Text", "parent": "btn-confirm",
|
|
||||||
"left": 645, "top": 488,
|
|
||||||
"text": "Confirm",
|
|
||||||
"fontColor": "#c8d8f0", "fontSize": 14
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5. List View
|
|
||||||
|
|
||||||
Scrollable list with item selection and detail panel.
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"name": "List View",
|
|
||||||
"shapes": {
|
|
||||||
"list-panel": {
|
|
||||||
"type": "Rectangle",
|
|
||||||
"left": 20, "top": 20, "width": 400, "height": 740,
|
|
||||||
"fillColor": "#1a1e24", "strokeColor": "#333340", "corners": [4, 4, 4, 4]
|
|
||||||
},
|
|
||||||
"item-1": {
|
|
||||||
"type": "Rectangle", "parent": "list-panel",
|
|
||||||
"left": 30, "top": 30, "width": 380, "height": 40,
|
|
||||||
"fillColor": "#2a3040", "strokeColor": "#c8d8f0", "corners": [4, 4, 4, 4]
|
|
||||||
},
|
|
||||||
"item-1-label": {
|
|
||||||
"type": "Text", "parent": "item-1",
|
|
||||||
"left": 40, "top": 38, "text": "Item Alpha",
|
|
||||||
"fontColor": "#c8d8f0", "fontSize": 14
|
|
||||||
},
|
|
||||||
"item-2": {
|
|
||||||
"type": "Rectangle", "parent": "list-panel",
|
|
||||||
"left": 30, "top": 80, "width": 380, "height": 40,
|
|
||||||
"fillColor": "#2a3040", "strokeColor": "#333340", "corners": [4, 4, 4, 4]
|
|
||||||
},
|
|
||||||
"item-2-label": {
|
|
||||||
"type": "Text", "parent": "item-2",
|
|
||||||
"left": 40, "top": 88, "text": "Item Beta",
|
|
||||||
"fontColor": "#c8d0e0", "fontSize": 14
|
|
||||||
},
|
|
||||||
"item-3": {
|
|
||||||
"type": "Rectangle", "parent": "list-panel",
|
|
||||||
"left": 30, "top": 130, "width": 380, "height": 40,
|
|
||||||
"fillColor": "#2a3040", "strokeColor": "#333340", "corners": [4, 4, 4, 4]
|
|
||||||
},
|
|
||||||
"item-3-label": {
|
|
||||||
"type": "Text", "parent": "item-3",
|
|
||||||
"left": 40, "top": 138, "text": "Item Gamma",
|
|
||||||
"fontColor": "#c8d0e0", "fontSize": 14
|
|
||||||
},
|
|
||||||
"detail-panel": {
|
|
||||||
"type": "Rectangle",
|
|
||||||
"left": 440, "top": 20, "width": 680, "height": 740,
|
|
||||||
"fillColor": "#1a1e24", "strokeColor": "#333340", "corners": [4, 4, 4, 4]
|
|
||||||
},
|
|
||||||
"detail-title": {
|
|
||||||
"type": "Text", "parent": "detail-panel",
|
|
||||||
"left": 460, "top": 40,
|
|
||||||
"text": "Item Alpha",
|
|
||||||
"fontColor": "#c8d0e0", "fontSize": 18
|
|
||||||
},
|
|
||||||
"detail-body": {
|
|
||||||
"type": "Text", "parent": "detail-panel",
|
|
||||||
"left": 460, "top": 80, "width": 640,
|
|
||||||
"text": "Description and properties appear here.",
|
|
||||||
"fontColor": "#c8d0e0", "fontSize": 14, "wordWrap": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 6. Inventory Grid
|
|
||||||
|
|
||||||
Grid of cells for item management.
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"name": "Inventory Grid",
|
|
||||||
"shapes": {
|
|
||||||
"panel": {
|
|
||||||
"type": "Rectangle",
|
|
||||||
"left": 240, "top": 100, "width": 660, "height": 580,
|
|
||||||
"fillColor": "#1a1e24", "strokeColor": "#333340", "corners": [8, 8, 8, 8]
|
|
||||||
},
|
|
||||||
"title": {
|
|
||||||
"type": "Text", "parent": "panel",
|
|
||||||
"left": 260, "top": 120,
|
|
||||||
"text": "INVENTORY",
|
|
||||||
"fontColor": "#c8d0e0", "fontSize": 18
|
|
||||||
},
|
|
||||||
"cell-1-1": {
|
|
||||||
"type": "Rectangle", "parent": "panel",
|
|
||||||
"left": 260, "top": 160, "width": 64, "height": 64,
|
|
||||||
"fillColor": "#2a3040", "strokeColor": "#333340", "corners": [4, 4, 4, 4]
|
|
||||||
},
|
|
||||||
"cell-1-2": {
|
|
||||||
"type": "Rectangle", "parent": "panel",
|
|
||||||
"left": 332, "top": 160, "width": 64, "height": 64,
|
|
||||||
"fillColor": "#2a3040", "strokeColor": "#333340", "corners": [4, 4, 4, 4]
|
|
||||||
},
|
|
||||||
"cell-1-3": {
|
|
||||||
"type": "Rectangle", "parent": "panel",
|
|
||||||
"left": 404, "top": 160, "width": 64, "height": 64,
|
|
||||||
"fillColor": "#2a3040", "strokeColor": "#333340", "corners": [4, 4, 4, 4]
|
|
||||||
},
|
|
||||||
"cell-1-4": {
|
|
||||||
"type": "Rectangle", "parent": "panel",
|
|
||||||
"left": 476, "top": 160, "width": 64, "height": 64,
|
|
||||||
"fillColor": "#2a3040", "strokeColor": "#333340", "corners": [4, 4, 4, 4]
|
|
||||||
},
|
|
||||||
"cell-2-1": {
|
|
||||||
"type": "Rectangle", "parent": "panel",
|
|
||||||
"left": 260, "top": 232, "width": 64, "height": 64,
|
|
||||||
"fillColor": "#2a3040", "strokeColor": "#333340", "corners": [4, 4, 4, 4]
|
|
||||||
},
|
|
||||||
"cell-2-2": {
|
|
||||||
"type": "Rectangle", "parent": "panel",
|
|
||||||
"left": 332, "top": 232, "width": 64, "height": 64,
|
|
||||||
"fillColor": "#2a3040", "strokeColor": "#333340", "corners": [4, 4, 4, 4]
|
|
||||||
},
|
|
||||||
"cell-2-3": {
|
|
||||||
"type": "Rectangle", "parent": "panel",
|
|
||||||
"left": 404, "top": 232, "width": 64, "height": 64,
|
|
||||||
"fillColor": "#2a3040", "strokeColor": "#333340", "corners": [4, 4, 4, 4]
|
|
||||||
},
|
|
||||||
"cell-2-4": {
|
|
||||||
"type": "Rectangle", "parent": "panel",
|
|
||||||
"left": 476, "top": 232, "width": 64, "height": 64,
|
|
||||||
"fillColor": "#2a3040", "strokeColor": "#333340", "corners": [4, 4, 4, 4]
|
|
||||||
},
|
|
||||||
"detail": {
|
|
||||||
"type": "Rectangle", "parent": "panel",
|
|
||||||
"left": 580, "top": 160, "width": 300, "height": 400,
|
|
||||||
"fillColor": "#2a3040", "strokeColor": "#333340", "corners": [4, 4, 4, 4]
|
|
||||||
},
|
|
||||||
"detail-title": {
|
|
||||||
"type": "Text", "parent": "detail",
|
|
||||||
"left": 600, "top": 180,
|
|
||||||
"text": "Selected Item Name",
|
|
||||||
"fontColor": "#c8d0e0", "fontSize": 16
|
|
||||||
},
|
|
||||||
"detail-body": {
|
|
||||||
"type": "Text", "parent": "detail",
|
|
||||||
"left": 600, "top": 210, "width": 260,
|
|
||||||
"text": "Item description and stats",
|
|
||||||
"fontColor": "#c8d0e0", "fontSize": 14, "wordWrap": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
# Frame0 Setup Guide
|
|
||||||
|
|
||||||
## Installation (Fedora)
|
|
||||||
|
|
||||||
Download from https://frame0.app/download and install the RPM:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo dnf install ./frame0-*.x86_64.rpm
|
|
||||||
```
|
|
||||||
|
|
||||||
Requires: Fedora 40 or later (x86_64).
|
|
||||||
|
|
||||||
## Starting Frame0
|
|
||||||
|
|
||||||
Launch the desktop application:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
frame0 &
|
|
||||||
```
|
|
||||||
|
|
||||||
Frame0 exposes an HTTP API at `localhost:58320` when running.
|
|
||||||
|
|
||||||
## Verify API Access
|
|
||||||
|
|
||||||
```bash
|
|
||||||
.claude/skills/frame0-wireframe/scripts/frame0-cmd.sh health
|
|
||||||
```
|
|
||||||
|
|
||||||
Expected output: `Frame0 is running on port 58320`
|
|
||||||
|
|
||||||
## Port Configuration
|
|
||||||
|
|
||||||
Default port: **58320**
|
|
||||||
|
|
||||||
To use a different port, set the environment variable:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
export FRAME0_PORT=58321
|
|
||||||
```
|
|
||||||
|
|
||||||
Or pass `--port` to any script:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
.claude/skills/frame0-wireframe/scripts/frame0-cmd.sh --port 58321 health
|
|
||||||
```
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
| Symptom | Cause | Fix |
|
|
||||||
|---------|-------|-----|
|
|
||||||
| "Connection refused" | Frame0 not running | Start the desktop app |
|
|
||||||
| "Port in use" | Another instance running | Close duplicate or use different port |
|
|
||||||
| Script hangs | API unresponsive | Restart Frame0 |
|
|
||||||
@@ -1,253 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
PORT="${FRAME0_PORT:-58320}"
|
|
||||||
ENDPOINT="http://localhost:${PORT}/execute_command"
|
|
||||||
|
|
||||||
usage() {
|
|
||||||
cat <<EOF
|
|
||||||
Usage: $(basename "$0") <command> [args...] [--port N]
|
|
||||||
|
|
||||||
Low-level Frame0 HTTP API wrapper. Replaces the MCP server with direct
|
|
||||||
curl calls. Requires Frame0 desktop app to be running.
|
|
||||||
|
|
||||||
Commands:
|
|
||||||
health Check if Frame0 is running
|
|
||||||
exec <namespace:action> <json> Execute a raw API command
|
|
||||||
create-shape <type> <json-props> Create a shape (Rectangle, Ellipse, Text, Line)
|
|
||||||
get-shape <id> Get shape details
|
|
||||||
update-shape <id> <json-props> Update shape properties
|
|
||||||
delete <id> [id...] Delete shapes by ID
|
|
||||||
move <id> <dx> <dy> Move a shape by pixel offset
|
|
||||||
duplicate <id> Duplicate a shape
|
|
||||||
group <id> [id...] Group shapes
|
|
||||||
ungroup <group-id> Ungroup a group
|
|
||||||
create-connector <tail-id> <head-id> [json-props] Connect two shapes
|
|
||||||
create-icon <name> <json-props> Create an icon shape
|
|
||||||
add-page <name> Add a new page (becomes current)
|
|
||||||
get-page [page-id] Get current or specific page data
|
|
||||||
list-pages [--shapes] List all pages (--shapes for shape data)
|
|
||||||
current-page Get current page ID
|
|
||||||
set-page <page-id> Set current page
|
|
||||||
export [page-id] [--format mime] Export page as image (default: image/png)
|
|
||||||
fit Fit view to screen
|
|
||||||
|
|
||||||
Options:
|
|
||||||
--port N Frame0 API port (default: $PORT, env: FRAME0_PORT)
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
$(basename "$0") health
|
|
||||||
$(basename "$0") add-page "HUD Layout"
|
|
||||||
$(basename "$0") create-shape Rectangle '{"name":"btn","left":100,"top":100,"width":120,"height":36}'
|
|
||||||
$(basename "$0") list-pages
|
|
||||||
$(basename "$0") export --format image/png
|
|
||||||
EOF
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# Parse --port from anywhere in args
|
|
||||||
ARGS=()
|
|
||||||
while [[ $# -gt 0 ]]; do
|
|
||||||
case "$1" in
|
|
||||||
--port) PORT="$2"; ENDPOINT="http://localhost:${PORT}/execute_command"; shift 2 ;;
|
|
||||||
*) ARGS+=("$1"); shift ;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
set -- "${ARGS[@]+"${ARGS[@]}"}"
|
|
||||||
|
|
||||||
[[ $# -lt 1 ]] && usage
|
|
||||||
|
|
||||||
# Execute a Frame0 API command, return data or error
|
|
||||||
frame0_exec() {
|
|
||||||
local command="$1"
|
|
||||||
local args
|
|
||||||
args="${2:-"{}"}"
|
|
||||||
|
|
||||||
local response
|
|
||||||
response=$(curl -s -w "\n%{http_code}" -X POST "$ENDPOINT" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d "{\"command\": \"$command\", \"args\": $args}" 2>&1) || {
|
|
||||||
echo "ERROR: Cannot connect to Frame0 at localhost:$PORT" >&2
|
|
||||||
echo "Is Frame0 running? See: .claude/skills/frame0-wireframe/references/setup-guide.md" >&2
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
local http_code body
|
|
||||||
http_code=$(echo "$response" | tail -1)
|
|
||||||
body=$(echo "$response" | sed '$d')
|
|
||||||
|
|
||||||
if [[ "$http_code" != 2* ]]; then
|
|
||||||
echo "ERROR: HTTP $http_code from Frame0" >&2
|
|
||||||
echo "$body" >&2
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Parse success/error from response
|
|
||||||
python3 -c "
|
|
||||||
import sys, json
|
|
||||||
try:
|
|
||||||
r = json.loads(sys.stdin.read())
|
|
||||||
if r.get('success'):
|
|
||||||
d = r.get('data')
|
|
||||||
if d is not None:
|
|
||||||
print(json.dumps(d, indent=2))
|
|
||||||
else:
|
|
||||||
print('ERROR: ' + str(r.get('error', 'Unknown error')), file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
except json.JSONDecodeError as e:
|
|
||||||
print(f'ERROR: Invalid JSON response: {e}', file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
" <<< "$body"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Build JSON array from remaining args
|
|
||||||
ids_to_json_array() {
|
|
||||||
local arr="["
|
|
||||||
local first=true
|
|
||||||
for id in "$@"; do
|
|
||||||
[[ "$first" == true ]] && first=false || arr+=","
|
|
||||||
arr+="\"$id\""
|
|
||||||
done
|
|
||||||
arr+="]"
|
|
||||||
echo "$arr"
|
|
||||||
}
|
|
||||||
|
|
||||||
CMD="${1:-}"
|
|
||||||
shift || true
|
|
||||||
|
|
||||||
case "$CMD" in
|
|
||||||
health)
|
|
||||||
if curl -s -o /dev/null -w "%{http_code}" "http://localhost:${PORT}/" 2>/dev/null | grep -q "^[23]"; then
|
|
||||||
echo "Frame0 is running on port $PORT"
|
|
||||||
else
|
|
||||||
echo "Frame0 is NOT running on port $PORT" >&2
|
|
||||||
echo "Start Frame0 desktop app, then retry." >&2
|
|
||||||
echo "See: .claude/skills/frame0-wireframe/references/setup-guide.md" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
|
|
||||||
exec)
|
|
||||||
[[ $# -lt 2 ]] && { echo "Usage: exec <command> <json-args>" >&2; exit 1; }
|
|
||||||
frame0_exec "$1" "$2"
|
|
||||||
;;
|
|
||||||
|
|
||||||
create-shape)
|
|
||||||
[[ $# -lt 2 ]] && { echo "Usage: create-shape <Type> <json-props>" >&2; exit 1; }
|
|
||||||
local_type="$1"
|
|
||||||
local_props="$2"
|
|
||||||
local_parent="${3:-}"
|
|
||||||
local_parent_arg=""
|
|
||||||
[[ -n "$local_parent" ]] && local_parent_arg=", \"parentId\": \"$local_parent\""
|
|
||||||
frame0_exec "shape:create-shape" "{\"type\": \"$local_type\", \"shapeProps\": $local_props$local_parent_arg, \"convertColors\": true}"
|
|
||||||
;;
|
|
||||||
|
|
||||||
get-shape)
|
|
||||||
[[ $# -lt 1 ]] && { echo "Usage: get-shape <id>" >&2; exit 1; }
|
|
||||||
frame0_exec "shape:get-shape" "{\"shapeId\": \"$1\"}"
|
|
||||||
;;
|
|
||||||
|
|
||||||
update-shape)
|
|
||||||
[[ $# -lt 2 ]] && { echo "Usage: update-shape <id> <json-props>" >&2; exit 1; }
|
|
||||||
frame0_exec "shape:update-shape" "{\"shapeId\": \"$1\", \"shapeProps\": $2, \"convertColors\": true}"
|
|
||||||
;;
|
|
||||||
|
|
||||||
delete)
|
|
||||||
[[ $# -lt 1 ]] && { echo "Usage: delete <id> [id...]" >&2; exit 1; }
|
|
||||||
local_arr=$(ids_to_json_array "$@")
|
|
||||||
frame0_exec "edit:delete" "{\"shapeIdArray\": $local_arr}"
|
|
||||||
;;
|
|
||||||
|
|
||||||
move)
|
|
||||||
[[ $# -lt 3 ]] && { echo "Usage: move <id> <dx> <dy>" >&2; exit 1; }
|
|
||||||
frame0_exec "shape:move" "{\"shapeId\": \"$1\", \"dx\": $2, \"dy\": $3}"
|
|
||||||
;;
|
|
||||||
|
|
||||||
duplicate)
|
|
||||||
[[ $# -lt 1 ]] && { echo "Usage: duplicate <id> [dx] [dy]" >&2; exit 1; }
|
|
||||||
local_dx="${2:-0}"
|
|
||||||
local_dy="${3:-0}"
|
|
||||||
frame0_exec "edit:duplicate" "{\"shapeIdArray\": [\"$1\"], \"dx\": $local_dx, \"dy\": $local_dy}"
|
|
||||||
;;
|
|
||||||
|
|
||||||
group)
|
|
||||||
[[ $# -lt 2 ]] && { echo "Usage: group <id> <id> [id...]" >&2; exit 1; }
|
|
||||||
local_arr=$(ids_to_json_array "$@")
|
|
||||||
frame0_exec "shape:group" "{\"shapeIdArray\": $local_arr}"
|
|
||||||
;;
|
|
||||||
|
|
||||||
ungroup)
|
|
||||||
[[ $# -lt 1 ]] && { echo "Usage: ungroup <group-id>" >&2; exit 1; }
|
|
||||||
frame0_exec "shape:ungroup" "{\"shapeIdArray\": [\"$1\"]}"
|
|
||||||
;;
|
|
||||||
|
|
||||||
create-connector)
|
|
||||||
[[ $# -lt 2 ]] && { echo "Usage: create-connector <tail-id> <head-id> [json-props]" >&2; exit 1; }
|
|
||||||
local_props="${3:-{}}"
|
|
||||||
frame0_exec "shape:create-connector" "{\"tailId\": \"$1\", \"headId\": \"$2\", \"shapeProps\": $local_props, \"convertColors\": true}"
|
|
||||||
;;
|
|
||||||
|
|
||||||
create-icon)
|
|
||||||
[[ $# -lt 2 ]] && { echo "Usage: create-icon <name> <json-props>" >&2; exit 1; }
|
|
||||||
frame0_exec "shape:create-icon" "{\"iconName\": \"$1\", \"shapeProps\": $2, \"convertColors\": true}"
|
|
||||||
;;
|
|
||||||
|
|
||||||
add-page)
|
|
||||||
[[ $# -lt 1 ]] && { echo "Usage: add-page <name>" >&2; exit 1; }
|
|
||||||
frame0_exec "page:add" "{\"pageProps\": {\"name\": \"$1\"}}"
|
|
||||||
;;
|
|
||||||
|
|
||||||
get-page)
|
|
||||||
if [[ $# -ge 1 ]]; then
|
|
||||||
frame0_exec "page:get" "{\"pageId\": \"$1\", \"exportShapes\": true}"
|
|
||||||
else
|
|
||||||
local_id
|
|
||||||
local_id=$(frame0_exec "page:get-current-page")
|
|
||||||
# Strip quotes from returned ID
|
|
||||||
local_id=$(echo "$local_id" | tr -d '"')
|
|
||||||
frame0_exec "page:get" "{\"pageId\": \"$local_id\", \"exportShapes\": true}"
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
|
|
||||||
list-pages)
|
|
||||||
local_shapes="false"
|
|
||||||
[[ "${1:-}" == "--shapes" ]] && local_shapes="true"
|
|
||||||
frame0_exec "doc:get" "{\"exportPages\": true, \"exportShapes\": $local_shapes}"
|
|
||||||
;;
|
|
||||||
|
|
||||||
current-page)
|
|
||||||
frame0_exec "page:get-current-page"
|
|
||||||
;;
|
|
||||||
|
|
||||||
set-page)
|
|
||||||
[[ $# -lt 1 ]] && { echo "Usage: set-page <page-id>" >&2; exit 1; }
|
|
||||||
frame0_exec "page:set-current-page" "{\"pageId\": \"$1\"}"
|
|
||||||
;;
|
|
||||||
|
|
||||||
export)
|
|
||||||
local_page_id=""
|
|
||||||
local_format="image/png"
|
|
||||||
while [[ $# -gt 0 ]]; do
|
|
||||||
case "$1" in
|
|
||||||
--format) local_format="$2"; shift 2 ;;
|
|
||||||
*) local_page_id="$1"; shift ;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
local_page_arg=""
|
|
||||||
[[ -n "$local_page_id" ]] && local_page_arg="\"pageId\": \"$local_page_id\", "
|
|
||||||
frame0_exec "file:export-image" "{${local_page_arg}\"format\": \"$local_format\", \"fillBackground\": true}"
|
|
||||||
;;
|
|
||||||
|
|
||||||
fit)
|
|
||||||
frame0_exec "view:fit-to-screen"
|
|
||||||
;;
|
|
||||||
|
|
||||||
--help|-h|help)
|
|
||||||
usage
|
|
||||||
;;
|
|
||||||
|
|
||||||
*)
|
|
||||||
echo "Unknown command: $CMD" >&2
|
|
||||||
usage
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# Batch export wireframes from JSON to PNG via Frame0.
|
|
||||||
#
|
|
||||||
# Finds all .json wireframe files under docs/design/wireframes/ and exports
|
|
||||||
# each to a matching .png. Skips files whose PNG is already newer than the
|
|
||||||
# JSON, unless --force is passed.
|
|
||||||
#
|
|
||||||
# Usage:
|
|
||||||
# frame0-export-batch.sh [--dry-run] [--force] [--category CAT] [--root DIR]
|
|
||||||
#
|
|
||||||
# Options:
|
|
||||||
# --dry-run Print manifest only, don't touch Frame0.
|
|
||||||
# --force Re-export even if PNG already exists and is up to date.
|
|
||||||
# --category CAT Limit to one subdirectory (e.g. --category dialogue)
|
|
||||||
# --root DIR Wireframes root dir (default: docs/design/wireframes)
|
|
||||||
#
|
|
||||||
# Exit codes:
|
|
||||||
# 0 All exports succeeded (or nothing to do)
|
|
||||||
# 1 One or more exports failed
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
||||||
REPO_ROOT="$(cd "$SCRIPT_DIR/../../../.." && pwd)"
|
|
||||||
SYNC="$SCRIPT_DIR/frame0-sync.py"
|
|
||||||
DEFAULT_ROOT="$REPO_ROOT/docs/design/wireframes"
|
|
||||||
|
|
||||||
DRY_RUN=false
|
|
||||||
FORCE=false
|
|
||||||
CATEGORY=""
|
|
||||||
WF_ROOT="$DEFAULT_ROOT"
|
|
||||||
|
|
||||||
# Parse arguments
|
|
||||||
while [[ $# -gt 0 ]]; do
|
|
||||||
case "$1" in
|
|
||||||
--dry-run) DRY_RUN=true; shift ;;
|
|
||||||
--force) FORCE=true; shift ;;
|
|
||||||
--category) CATEGORY="$2"; shift 2 ;;
|
|
||||||
--root) WF_ROOT="$2"; shift 2 ;;
|
|
||||||
-h|--help)
|
|
||||||
sed -n '/^# /p' "$0" | sed 's/^# //'
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
*) echo "Unknown option: $1" >&2; exit 1 ;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
if [[ ! -d "$WF_ROOT" ]]; then
|
|
||||||
echo "ERROR: Wireframes directory not found: $WF_ROOT" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Collect JSON files, optionally filtered by category subdirectory
|
|
||||||
mapfile -t JSON_FILES < <(
|
|
||||||
if [[ -n "$CATEGORY" ]]; then
|
|
||||||
find "$WF_ROOT/$CATEGORY" -name "*.json" ! -name ".*" | sort
|
|
||||||
else
|
|
||||||
find "$WF_ROOT" -name "*.json" ! -name ".*" | sort
|
|
||||||
fi
|
|
||||||
)
|
|
||||||
|
|
||||||
if [[ ${#JSON_FILES[@]} -eq 0 ]]; then
|
|
||||||
echo "No wireframe JSON files found."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Classify files into to-export and to-skip
|
|
||||||
TO_EXPORT=()
|
|
||||||
TO_SKIP=()
|
|
||||||
|
|
||||||
for json in "${JSON_FILES[@]}"; do
|
|
||||||
png="${json%.json}.png"
|
|
||||||
if $FORCE || [[ ! -f "$png" ]] || [[ "$json" -nt "$png" ]]; then
|
|
||||||
TO_EXPORT+=("$json")
|
|
||||||
else
|
|
||||||
TO_SKIP+=("$json")
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Print manifest
|
|
||||||
if [[ ${#TO_EXPORT[@]} -gt 0 ]]; then
|
|
||||||
echo ""
|
|
||||||
echo "Will export (${#TO_EXPORT[@]} files):"
|
|
||||||
for json in "${TO_EXPORT[@]}"; do
|
|
||||||
png="${json%.json}.png"
|
|
||||||
rel="${json#$REPO_ROOT/}"
|
|
||||||
if [[ ! -f "$png" ]]; then
|
|
||||||
status="new"
|
|
||||||
else
|
|
||||||
status="updated"
|
|
||||||
fi
|
|
||||||
printf " [%-7s] %s\n" "$status" "$rel"
|
|
||||||
done
|
|
||||||
else
|
|
||||||
echo ""
|
|
||||||
echo "Nothing to export (all PNGs up to date)."
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ${#TO_SKIP[@]} -gt 0 ]]; then
|
|
||||||
echo ""
|
|
||||||
echo "Will skip (${#TO_SKIP[@]} files already up to date):"
|
|
||||||
for json in "${TO_SKIP[@]}"; do
|
|
||||||
rel="${json#$REPO_ROOT/}"
|
|
||||||
printf " [skip ] %s\n" "$rel"
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
if $DRY_RUN; then
|
|
||||||
echo ""
|
|
||||||
echo "Dry run — no exports performed."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ${#TO_EXPORT[@]} -eq 0 ]]; then
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
PASSED=0
|
|
||||||
FAILED=0
|
|
||||||
FAILED_FILES=()
|
|
||||||
|
|
||||||
TOTAL=${#TO_EXPORT[@]}
|
|
||||||
IDX=0
|
|
||||||
|
|
||||||
for json in "${TO_EXPORT[@]}"; do
|
|
||||||
IDX=$((IDX + 1))
|
|
||||||
png="${json%.json}.png"
|
|
||||||
rel="${json#$REPO_ROOT/}"
|
|
||||||
|
|
||||||
printf "[%d/%d] %s ... " "$IDX" "$TOTAL" "$rel"
|
|
||||||
|
|
||||||
output=$(python3 "$SYNC" export "$json" "$png" 2>/tmp/frame0-batch-err.txt)
|
|
||||||
rc=$?
|
|
||||||
if [[ $rc -eq 0 ]]; then
|
|
||||||
size=$(echo "$output" | tail -1 | grep -oP '\(\K[^)]+' || true)
|
|
||||||
echo "ok $size"
|
|
||||||
PASSED=$((PASSED + 1))
|
|
||||||
else
|
|
||||||
echo "FAILED"
|
|
||||||
cat /tmp/frame0-batch-err.txt >&2
|
|
||||||
FAILED=$((FAILED + 1))
|
|
||||||
FAILED_FILES+=("$rel")
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "$PASSED exported, $FAILED failed."
|
|
||||||
|
|
||||||
if [[ $FAILED -gt 0 ]]; then
|
|
||||||
echo ""
|
|
||||||
echo "Failed:" >&2
|
|
||||||
for f in "${FAILED_FILES[@]}"; do
|
|
||||||
echo " $f" >&2
|
|
||||||
done
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
exit 0
|
|
||||||
@@ -1,414 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""Frame0 sync: push local JSON wireframes to Frame0, pull pages back.
|
|
||||||
|
|
||||||
Local JSON is source of truth. Frame0 is a renderer.
|
|
||||||
A mapping file tracks local_id <-> frame0_id across push/pull cycles.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
frame0-sync.py push <wireframe.json> [--port PORT]
|
|
||||||
frame0-sync.py pull <page-id|page-name> <output.json> [--port PORT]
|
|
||||||
frame0-sync.py export <wireframe.json> <output.png> [--port PORT] [--format MIME]
|
|
||||||
"""
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import urllib.request
|
|
||||||
import urllib.error
|
|
||||||
|
|
||||||
DEFAULT_PORT = 58320
|
|
||||||
|
|
||||||
|
|
||||||
def api(port, command, args=None):
|
|
||||||
"""Execute a Frame0 API command. Returns the data field on success."""
|
|
||||||
url = f"http://localhost:{port}/execute_command"
|
|
||||||
payload = json.dumps({"command": command, "args": args or {}}).encode()
|
|
||||||
req = urllib.request.Request(url, data=payload, headers={"Content-Type": "application/json"})
|
|
||||||
try:
|
|
||||||
with urllib.request.urlopen(req) as resp:
|
|
||||||
result = json.loads(resp.read())
|
|
||||||
except urllib.error.HTTPError as e:
|
|
||||||
body = e.read().decode()
|
|
||||||
print(f"ERROR: {command}: HTTP {e.code}: {body[:500]}", file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
except urllib.error.URLError as e:
|
|
||||||
print(f"ERROR: Cannot connect to Frame0 on port {port}: {e}", file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
if not result.get("success"):
|
|
||||||
print(f"ERROR: {command}: {result.get('error', 'unknown')}", file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
return result.get("data")
|
|
||||||
|
|
||||||
|
|
||||||
# -- Mapping file management --------------------------------------------------
|
|
||||||
|
|
||||||
def mapping_path(wireframe_path):
|
|
||||||
"""Derive the idmap path from the wireframe JSON path."""
|
|
||||||
d = os.path.dirname(wireframe_path)
|
|
||||||
base = os.path.splitext(os.path.basename(wireframe_path))[0]
|
|
||||||
return os.path.join(d, f".{base}.idmap.json")
|
|
||||||
|
|
||||||
|
|
||||||
def load_mapping(wireframe_path):
|
|
||||||
p = mapping_path(wireframe_path)
|
|
||||||
if os.path.exists(p):
|
|
||||||
with open(p) as f:
|
|
||||||
return json.load(f)
|
|
||||||
return {"page_id": None, "shapes": {}, "connectors": {}}
|
|
||||||
|
|
||||||
|
|
||||||
def save_mapping(wireframe_path, mapping):
|
|
||||||
p = mapping_path(wireframe_path)
|
|
||||||
os.makedirs(os.path.dirname(p) or ".", exist_ok=True)
|
|
||||||
with open(p, "w") as f:
|
|
||||||
json.dump(mapping, f, indent=2)
|
|
||||||
f.write("\n")
|
|
||||||
|
|
||||||
|
|
||||||
# -- Push: local JSON -> Frame0 -----------------------------------------------
|
|
||||||
|
|
||||||
# Frame0 returns different type names from get vs what create accepts.
|
|
||||||
# Map internal types back to create-API types.
|
|
||||||
TYPE_TO_CREATE = {
|
|
||||||
"Box": "Rectangle",
|
|
||||||
"box": "Rectangle",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def topo_sort_shapes(shapes):
|
|
||||||
"""Sort shape IDs so parents come before children."""
|
|
||||||
order = []
|
|
||||||
visited = set()
|
|
||||||
|
|
||||||
def visit(sid):
|
|
||||||
if sid in visited:
|
|
||||||
return
|
|
||||||
visited.add(sid)
|
|
||||||
shape = shapes[sid]
|
|
||||||
parent = shape.get("parent")
|
|
||||||
if parent and parent in shapes:
|
|
||||||
visit(parent)
|
|
||||||
order.append(sid)
|
|
||||||
|
|
||||||
for sid in shapes:
|
|
||||||
visit(sid)
|
|
||||||
return order
|
|
||||||
|
|
||||||
|
|
||||||
def find_or_create_page(port, name, mapping):
|
|
||||||
"""Find existing page by mapping or name, or create a new one."""
|
|
||||||
# Try mapped page_id first
|
|
||||||
if mapping.get("page_id"):
|
|
||||||
try:
|
|
||||||
page = api(port, "page:get", {"pageId": mapping["page_id"]})
|
|
||||||
if page:
|
|
||||||
return mapping["page_id"]
|
|
||||||
except SystemExit:
|
|
||||||
pass # Page no longer exists, fall through
|
|
||||||
|
|
||||||
# Search by name in existing pages
|
|
||||||
doc = api(port, "doc:get", {"exportPages": True, "exportShapes": False})
|
|
||||||
if doc and "children" in doc:
|
|
||||||
for page in doc["children"]:
|
|
||||||
if page.get("name") == name:
|
|
||||||
return page["id"]
|
|
||||||
|
|
||||||
# Create new page
|
|
||||||
page = api(port, "page:add", {"pageProps": {"name": name}})
|
|
||||||
return page["id"]
|
|
||||||
|
|
||||||
|
|
||||||
def clear_page(port, page_id):
|
|
||||||
"""Delete all shapes on a page."""
|
|
||||||
page = api(port, "page:get", {"pageId": page_id, "exportShapes": True})
|
|
||||||
if not page or "children" not in page:
|
|
||||||
return
|
|
||||||
shape_ids = [s["id"] for s in page["children"]]
|
|
||||||
if shape_ids:
|
|
||||||
api(port, "edit:delete", {"shapeIdArray": shape_ids})
|
|
||||||
|
|
||||||
|
|
||||||
def push(wireframe_path, port):
|
|
||||||
"""Push local wireframe JSON to Frame0."""
|
|
||||||
with open(wireframe_path) as f:
|
|
||||||
wireframe = json.load(f)
|
|
||||||
|
|
||||||
name = wireframe.get("name", os.path.splitext(os.path.basename(wireframe_path))[0])
|
|
||||||
shapes = wireframe.get("shapes", {})
|
|
||||||
connectors = wireframe.get("connectors", {})
|
|
||||||
|
|
||||||
mapping = load_mapping(wireframe_path)
|
|
||||||
|
|
||||||
# Find or create page
|
|
||||||
page_id = find_or_create_page(port, name, mapping)
|
|
||||||
mapping["page_id"] = page_id
|
|
||||||
|
|
||||||
# Switch to page and clear it
|
|
||||||
api(port, "page:set-current-page", {"pageId": page_id})
|
|
||||||
clear_page(port, page_id)
|
|
||||||
|
|
||||||
# Reset ID mappings (shapes are recreated)
|
|
||||||
mapping["shapes"] = {}
|
|
||||||
mapping["connectors"] = {}
|
|
||||||
|
|
||||||
# Create shapes in dependency order
|
|
||||||
order = topo_sort_shapes(shapes)
|
|
||||||
for local_id in order:
|
|
||||||
shape = shapes[local_id]
|
|
||||||
raw_type = shape.get("type", "Rectangle")
|
|
||||||
shape_type = TYPE_TO_CREATE.get(raw_type, raw_type)
|
|
||||||
parent_local = shape.get("parent")
|
|
||||||
|
|
||||||
# Build shapeProps from everything except meta fields
|
|
||||||
meta_keys = {"type", "parent"}
|
|
||||||
props = {k: v for k, v in shape.items() if k not in meta_keys}
|
|
||||||
|
|
||||||
# Set name to local_id if not explicitly set
|
|
||||||
if "name" not in props:
|
|
||||||
props["name"] = local_id
|
|
||||||
|
|
||||||
create_args = {
|
|
||||||
"type": shape_type,
|
|
||||||
"shapeProps": props,
|
|
||||||
"convertColors": True,
|
|
||||||
}
|
|
||||||
|
|
||||||
# Resolve parent ID
|
|
||||||
if parent_local and parent_local in mapping["shapes"]:
|
|
||||||
create_args["parentId"] = mapping["shapes"][parent_local]
|
|
||||||
|
|
||||||
f0_id = api(port, "shape:create-shape", create_args)
|
|
||||||
mapping["shapes"][local_id] = f0_id
|
|
||||||
|
|
||||||
# Create connectors
|
|
||||||
for local_id, conn in connectors.items():
|
|
||||||
tail_local = conn.get("tailId")
|
|
||||||
head_local = conn.get("headId")
|
|
||||||
|
|
||||||
if tail_local not in mapping["shapes"] or head_local not in mapping["shapes"]:
|
|
||||||
print(f"WARNING: connector '{local_id}' references unknown shape, skipping", file=sys.stderr)
|
|
||||||
continue
|
|
||||||
|
|
||||||
meta_keys = {"tailId", "headId"}
|
|
||||||
props = {k: v for k, v in conn.items() if k not in meta_keys}
|
|
||||||
if "name" not in props:
|
|
||||||
props["name"] = local_id
|
|
||||||
|
|
||||||
f0_id = api(port, "shape:create-connector", {
|
|
||||||
"tailId": mapping["shapes"][tail_local],
|
|
||||||
"headId": mapping["shapes"][head_local],
|
|
||||||
"shapeProps": props,
|
|
||||||
"convertColors": True,
|
|
||||||
})
|
|
||||||
mapping["connectors"][local_id] = f0_id
|
|
||||||
|
|
||||||
# Fit to screen
|
|
||||||
api(port, "view:fit-to-screen")
|
|
||||||
|
|
||||||
save_mapping(wireframe_path, mapping)
|
|
||||||
total = len(mapping["shapes"]) + len(mapping["connectors"])
|
|
||||||
print(f"Pushed '{name}' to Frame0: {len(mapping['shapes'])} shapes, {len(mapping['connectors'])} connectors")
|
|
||||||
|
|
||||||
|
|
||||||
# -- Pull: Frame0 -> local JSON -----------------------------------------------
|
|
||||||
|
|
||||||
def pull(page_ref, output_path, port):
|
|
||||||
"""Pull a Frame0 page into local wireframe JSON."""
|
|
||||||
# Resolve page_ref: could be an ID or a name
|
|
||||||
page_id = None
|
|
||||||
doc = api(port, "doc:get", {"exportPages": True, "exportShapes": False})
|
|
||||||
if doc and "children" in doc:
|
|
||||||
for page in doc["children"]:
|
|
||||||
if page["id"] == page_ref or page.get("name") == page_ref:
|
|
||||||
page_id = page["id"]
|
|
||||||
page_name = page.get("name", page_ref)
|
|
||||||
break
|
|
||||||
|
|
||||||
if not page_id:
|
|
||||||
print(f"ERROR: Page not found: {page_ref}", file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# Load existing mapping for reverse lookup
|
|
||||||
mapping = load_mapping(output_path)
|
|
||||||
reverse_map = {v: k for k, v in mapping.get("shapes", {}).items()}
|
|
||||||
reverse_conn = {v: k for k, v in mapping.get("connectors", {}).items()}
|
|
||||||
|
|
||||||
# Get full page with shapes
|
|
||||||
page = api(port, "page:get", {"pageId": page_id, "exportShapes": True})
|
|
||||||
|
|
||||||
shapes = {}
|
|
||||||
connectors = {}
|
|
||||||
new_mapping = {"page_id": page_id, "shapes": {}, "connectors": {}}
|
|
||||||
auto_id_counter = [0]
|
|
||||||
|
|
||||||
def auto_id(f0_shape):
|
|
||||||
"""Generate a stable local ID from shape name or auto-number."""
|
|
||||||
# Prefer existing mapping
|
|
||||||
f0_id = f0_shape["id"]
|
|
||||||
if f0_id in reverse_map:
|
|
||||||
return reverse_map[f0_id]
|
|
||||||
# Use sanitized name
|
|
||||||
name = f0_shape.get("name", "")
|
|
||||||
if name:
|
|
||||||
sanitized = name.lower().replace(" ", "-").replace("_", "-")
|
|
||||||
if sanitized not in shapes:
|
|
||||||
return sanitized
|
|
||||||
# Fallback: auto-number
|
|
||||||
auto_id_counter[0] += 1
|
|
||||||
return f"s{auto_id_counter[0]:03d}"
|
|
||||||
|
|
||||||
def process_shape(f0_shape, parent_local_id=None):
|
|
||||||
f0_id = f0_shape["id"]
|
|
||||||
local_id = auto_id(f0_shape)
|
|
||||||
new_mapping["shapes"][local_id] = f0_id
|
|
||||||
|
|
||||||
# Extract shape properties — only strip structural keys that our
|
|
||||||
# ID mapping replaces. Everything else passes through as-is so the
|
|
||||||
# local JSON speaks Frame0's native vocabulary.
|
|
||||||
shape_type = f0_shape.get("type", "Box")
|
|
||||||
skip_keys = {"id", "type", "children", "pageId", "parentId"}
|
|
||||||
props = {k: v for k, v in f0_shape.items() if k not in skip_keys and v is not None}
|
|
||||||
|
|
||||||
entry = {"type": shape_type}
|
|
||||||
if parent_local_id:
|
|
||||||
entry["parent"] = parent_local_id
|
|
||||||
entry.update(props)
|
|
||||||
|
|
||||||
# Remove name if it matches local_id (redundant)
|
|
||||||
if entry.get("name") == local_id:
|
|
||||||
del entry["name"]
|
|
||||||
|
|
||||||
shapes[local_id] = entry
|
|
||||||
|
|
||||||
# Process children recursively
|
|
||||||
for child in f0_shape.get("children", []):
|
|
||||||
child_type = child.get("type", "")
|
|
||||||
if child_type == "Connector":
|
|
||||||
process_connector(child)
|
|
||||||
else:
|
|
||||||
process_shape(child, local_id)
|
|
||||||
|
|
||||||
def process_connector(f0_conn):
|
|
||||||
f0_id = f0_conn["id"]
|
|
||||||
local_id = reverse_conn.get(f0_id)
|
|
||||||
if not local_id:
|
|
||||||
auto_id_counter[0] += 1
|
|
||||||
local_id = f"c{auto_id_counter[0]:03d}"
|
|
||||||
|
|
||||||
new_mapping["connectors"][local_id] = f0_id
|
|
||||||
|
|
||||||
tail_f0 = f0_conn.get("tail", {}).get("id")
|
|
||||||
head_f0 = f0_conn.get("head", {}).get("id")
|
|
||||||
|
|
||||||
entry = {}
|
|
||||||
if tail_f0:
|
|
||||||
# Will be resolved after all shapes are processed
|
|
||||||
entry["_tailF0"] = tail_f0
|
|
||||||
if head_f0:
|
|
||||||
entry["_headF0"] = head_f0
|
|
||||||
|
|
||||||
skip_keys = {"id", "type", "children", "pageId", "tail", "head"}
|
|
||||||
props = {k: v for k, v in f0_conn.items() if k not in skip_keys and v is not None}
|
|
||||||
entry.update(props)
|
|
||||||
|
|
||||||
connectors[local_id] = entry
|
|
||||||
|
|
||||||
# Process all top-level shapes
|
|
||||||
for child in page.get("children", []):
|
|
||||||
child_type = child.get("type", "")
|
|
||||||
if child_type == "Connector":
|
|
||||||
process_connector(child)
|
|
||||||
else:
|
|
||||||
process_shape(child)
|
|
||||||
|
|
||||||
# Resolve connector references to local IDs
|
|
||||||
f0_to_local = {v: k for k, v in new_mapping["shapes"].items()}
|
|
||||||
for conn in connectors.values():
|
|
||||||
tail_f0 = conn.pop("_tailF0", None)
|
|
||||||
head_f0 = conn.pop("_headF0", None)
|
|
||||||
if tail_f0 and tail_f0 in f0_to_local:
|
|
||||||
conn["tailId"] = f0_to_local[tail_f0]
|
|
||||||
if head_f0 and head_f0 in f0_to_local:
|
|
||||||
conn["headId"] = f0_to_local[head_f0]
|
|
||||||
|
|
||||||
wireframe = {"name": page_name}
|
|
||||||
if shapes:
|
|
||||||
wireframe["shapes"] = shapes
|
|
||||||
if connectors:
|
|
||||||
wireframe["connectors"] = connectors
|
|
||||||
|
|
||||||
os.makedirs(os.path.dirname(output_path) or ".", exist_ok=True)
|
|
||||||
with open(output_path, "w") as f:
|
|
||||||
json.dump(wireframe, f, indent=2)
|
|
||||||
f.write("\n")
|
|
||||||
|
|
||||||
save_mapping(output_path, new_mapping)
|
|
||||||
print(f"Pulled '{page_name}' -> {output_path}: {len(shapes)} shapes, {len(connectors)} connectors")
|
|
||||||
|
|
||||||
|
|
||||||
# -- Export: push then export as image -----------------------------------------
|
|
||||||
|
|
||||||
def export_image(wireframe_path, output_path, port, fmt="image/png"):
|
|
||||||
"""Push wireframe to Frame0 and export the page as an image."""
|
|
||||||
import base64
|
|
||||||
|
|
||||||
# Push first to ensure Frame0 is up to date
|
|
||||||
push(wireframe_path, port)
|
|
||||||
|
|
||||||
mapping = load_mapping(wireframe_path)
|
|
||||||
page_id = mapping.get("page_id")
|
|
||||||
if not page_id:
|
|
||||||
print("ERROR: No page_id in mapping after push", file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
image_b64 = api(port, "file:export-image", {
|
|
||||||
"pageId": page_id,
|
|
||||||
"format": fmt,
|
|
||||||
"fillBackground": True,
|
|
||||||
})
|
|
||||||
|
|
||||||
image_bytes = base64.b64decode(image_b64)
|
|
||||||
with open(output_path, "wb") as f:
|
|
||||||
f.write(image_bytes)
|
|
||||||
|
|
||||||
print(f"Exported: {output_path} ({len(image_bytes) // 1024}KB)")
|
|
||||||
|
|
||||||
|
|
||||||
# -- CLI -----------------------------------------------------------------------
|
|
||||||
|
|
||||||
def main():
|
|
||||||
parser = argparse.ArgumentParser(description="Sync wireframe JSON with Frame0")
|
|
||||||
parser.add_argument("--port", type=int, default=int(os.environ.get("FRAME0_PORT", DEFAULT_PORT)))
|
|
||||||
sub = parser.add_subparsers(dest="command")
|
|
||||||
|
|
||||||
p_push = sub.add_parser("push", help="Push local JSON to Frame0")
|
|
||||||
p_push.add_argument("wireframe", help="Path to wireframe .json file")
|
|
||||||
|
|
||||||
p_pull = sub.add_parser("pull", help="Pull Frame0 page to local JSON")
|
|
||||||
p_pull.add_argument("page", help="Page ID or page name")
|
|
||||||
p_pull.add_argument("output", help="Output .json path")
|
|
||||||
|
|
||||||
p_export = sub.add_parser("export", help="Push and export as image")
|
|
||||||
p_export.add_argument("wireframe", help="Path to wireframe .json file")
|
|
||||||
p_export.add_argument("output", help="Output image path (e.g. wireframe.png)")
|
|
||||||
p_export.add_argument("--format", default="image/png",
|
|
||||||
help="Export MIME type (default: image/png)")
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
if args.command == "push":
|
|
||||||
push(args.wireframe, args.port)
|
|
||||||
elif args.command == "pull":
|
|
||||||
pull(args.page, args.output, args.port)
|
|
||||||
elif args.command == "export":
|
|
||||||
export_image(args.wireframe, args.output, args.port, args.format)
|
|
||||||
else:
|
|
||||||
parser.print_help()
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
@@ -14,29 +14,40 @@ Follow these conventions whenever you create a commit in this repository. These
|
|||||||
|
|
||||||
## Message style
|
## Message style
|
||||||
|
|
||||||
- **First line:** imperative mood, ≤ 70 characters. Examples: `add sidecar PTY scaffold`, `fix IPC reconnect after app reload`, `update CLI exit-code contract`.
|
This repo uses [Conventional Commits 1.0](https://www.conventionalcommits.org/en/v1.0.0/) (per [D-37](../../../governance/decisions/process.md#d-37)).
|
||||||
|
|
||||||
|
- **First line:** `type(scope): imperative subject`, ≤ 72 characters **including** the prefix. Examples: `feat(settings): add Appearance font picker (T-460)`, `fix(ipc): reconnect after app reload`, `docs(readme): drop brittle version line`.
|
||||||
|
- **Type:** one of `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `chore`. Use `feat`/`fix` for user-visible behavior; `chore` for bookkeeping (`chore(plan)` is the convention for pql ticket housekeeping). Append `!` after the scope for a breaking change (`feat(ipc)!: …`).
|
||||||
|
- **Scope (optional but preferred):** the subsystem the change lives in — `settings`, `vim`, `pty`, `git`, `plan`, etc. Lower-case, no spaces.
|
||||||
|
- **Ticket ref:** keep a trailing `(T-NNN)` on the subject when the work has a ticket — `feat(settings): category rail + navigation (T-447)`.
|
||||||
- **Body (optional):** wrap at ~72 chars. Explain the *why* — the reason this change exists. The diff already shows the *what*; don't restate it in prose.
|
- **Body (optional):** wrap at ~72 chars. Explain the *why* — the reason this change exists. The diff already shows the *what*; don't restate it in prose.
|
||||||
- **No emojis.** Anywhere.
|
- **No emojis.** Anywhere.
|
||||||
- **Don't prefix with types** like `feat:` or `fix:` — this repo isn't Conventional Commits. (The Python-era clide under `legacy/` used Conventional Commits; the Flutter rebuild at the repo root does not.)
|
|
||||||
- **Don't reference the current task or flow** (`for the v2.0 milestone`, `used by the canvas panel`) — that context belongs in the PR description and rots as the repo evolves.
|
- **Don't reference the current task or flow** (`for the v2.0 milestone`, `used by the canvas panel`) — that context belongs in the PR description and rots as the repo evolves.
|
||||||
- **Naming:** the project is `clide`. The Flutter desktop app lives at the repo root; the Go sidecar/CLI binary is `clide`. The supporter project is `pql` (referenced, not part of this repo). The archived Python implementation lives under `legacy/`.
|
- **Naming:** the project is `clide`. The Flutter desktop app lives at the repo root; the `clide` CLI is a thin C client (`native/clide-cli/`). The supporter project is `pql` (referenced, not part of this repo). The archived Python implementation lives under `legacy/`.
|
||||||
|
|
||||||
## Logically-separated commits
|
## Logically-separated commits
|
||||||
|
|
||||||
Default to **one logical change per commit**, even when a lot of work lands in the tree at once. When there's a pile of uncommitted or untracked files:
|
Default to **one logical change per commit**, even when a lot of work lands in the tree at once. When there's a pile of uncommitted or untracked files:
|
||||||
|
|
||||||
1. **Read `git status` + `git diff` first** — never stage the whole tree blind.
|
1. **Read `git status` + `git diff` first** — never stage the whole tree blind.
|
||||||
2. **Group by concern**, not by file location. Typical concerns to separate:
|
2. **Triage: session vs pre-existing.** Separate changes you made in this
|
||||||
|
session from changes that were already dirty (or that a concurrent session
|
||||||
|
is producing — this worktree can host several Claude sessions at once).
|
||||||
|
Check the conversation history — if you didn't touch a file, it's not yours
|
||||||
|
to stage. After grouping your own commits, surface any remaining modified
|
||||||
|
or untracked files to the user and ask whether they belong in a commit.
|
||||||
|
Never silently skip or silently include changes that aren't yours.
|
||||||
|
3. **Group by concern**, not by file location. Typical concerns to separate:
|
||||||
- **Bookkeeping** — `.gitignore`, editor/IDE config, lockfiles, `go.sum` / `pubspec.lock` updates.
|
- **Bookkeeping** — `.gitignore`, editor/IDE config, lockfiles, `go.sum` / `pubspec.lock` updates.
|
||||||
- **Documentation** — `README.md`, `CLAUDE.md`, ADRs under `docs/ADRs/`, design notes under `docs/`.
|
- **Documentation** — `README.md`, `CLAUDE.md`, D-records under `governance/`, design notes under `docs/`.
|
||||||
- **General-purpose tooling / skills** — things that aren't project-specific (reusable skills, shared scripts).
|
- **General-purpose tooling / skills** — things that aren't project-specific (reusable skills, shared scripts).
|
||||||
- **Project-specific conventions** — this repo's own rules.
|
- **Project-specific conventions** — this repo's own rules.
|
||||||
- **Feature or subsystem** — one cohesive change per commit; a sidecar change and an app change for the same feature can land together, but two unrelated features should split.
|
- **Feature or subsystem** — one cohesive change per commit; a CLI change and an app change for the same feature can land together, but two unrelated features should split.
|
||||||
- **Layer changes** — Flutter app, sidecar CLI, sidecar daemon, IPC server, pql wrapper, canvas driver, git panel — separate concerns; prefer separate commits when the changes are independent.
|
- **Layer changes** — Flutter app, `clide` CLI (`native/clide-cli/`), IPC server, pql wrapper, canvas driver, git panel — separate concerns; prefer separate commits when the changes are independent.
|
||||||
3. **Sequence the commits** so each one is cleanly scoped, but don't obsess about whether each intermediate commit "works" — for scaffolding PRs it's fine if the full picture only snaps together at the end.
|
4. **Sequence the commits** so each one is cleanly scoped, but don't obsess about whether each intermediate commit "works" — for scaffolding PRs it's fine if the full picture only snaps together at the end.
|
||||||
4. **Prefer many small focused commits over one large mixed one** — a reviewer can read, revert, or cherry-pick a focused commit; they can't do any of those to a blob.
|
5. **Prefer many small focused commits over one large mixed one** — a reviewer can read, revert, or cherry-pick a focused commit; they can't do any of those to a blob.
|
||||||
5. **Use `git add <specific paths>`** — never `git add -A` or `git add .` when splitting, or you'll sweep in the next commit's work by accident.
|
6. **Use `git add <specific paths>`** — never `git add -A` or `git add .` when splitting, or you'll sweep in the next commit's work by accident.
|
||||||
6. **Verify between commits** with `git status` and `git log -1` to confirm the split landed as intended.
|
7. **Verify between commits** with `git status` and `git log -1` to confirm the split landed as intended.
|
||||||
|
|
||||||
Corollary: if a commit's subject line needs the word "and" to be accurate, it probably should have been two commits.
|
Corollary: if a commit's subject line needs the word "and" to be accurate, it probably should have been two commits.
|
||||||
|
|
||||||
@@ -95,6 +106,7 @@ Cutting a release is its own commit. In a single commit:
|
|||||||
3. Bump `pubspec.yaml` `version:` to `X.Y.Z` (drop the `-dev` suffix for the tag; re-add it on the next development commit if desired).
|
3. Bump `pubspec.yaml` `version:` to `X.Y.Z` (drop the `-dev` suffix for the tag; re-add it on the next development commit if desired).
|
||||||
4. Run `make gen-build-info` so `assets/licenses.yaml` `self.version:` re-syncs from pubspec (it's auto-rewritten by every build but commit the fresh state). Stage the resulting diff alongside step 3.
|
4. Run `make gen-build-info` so `assets/licenses.yaml` `self.version:` re-syncs from pubspec (it's auto-rewritten by every build but commit the fresh state). Stage the resulting diff alongside step 3.
|
||||||
5. Commit subject: `release vX.Y.Z`.
|
5. Commit subject: `release vX.Y.Z`.
|
||||||
|
6. **Tag it.** After the commit lands, run `make release` — it verifies the version/changelog/clean-tree invariants, runs the full gate, and creates the annotated `vX.Y.Z` tag. Then `git push origin main --follow-tags` to publish the commit and the tag together. **Every released version must have a matching `git tag`** — a CHANGELOG heading without a tag is an incomplete release (T-393: tagging had silently lapsed from v2.2.0 through v2.8.0). Don't hand-roll the tag; `make release` keeps the tag, gate, and version in lockstep. If you tag by hand, use an annotated tag (`git tag -a vX.Y.Z -m "clide vX.Y.Z"`); never push a release commit without its tag.
|
||||||
|
|
||||||
`pubspec.yaml` is the single source of truth for the version. Every `make` build/run/test target regenerates `lib/src/build_info.g.dart` (gitignored) and rewrites `assets/licenses.yaml` `self.version:` from it — so the Flutter app sees the current version everywhere without manual sync. Bumping `pubspec.yaml` and the changelog out of sync is the mistake this rule prevents.
|
`pubspec.yaml` is the single source of truth for the version. Every `make` build/run/test target regenerates `lib/src/build_info.g.dart` (gitignored) and rewrites `assets/licenses.yaml` `self.version:` from it — so the Flutter app sees the current version everywhere without manual sync. Bumping `pubspec.yaml` and the changelog out of sync is the mistake this rule prevents.
|
||||||
|
|
||||||
@@ -108,29 +120,32 @@ Co-Authored-By: Claude <noreply@anthropic.com>
|
|||||||
|
|
||||||
The model-identifier variant produced by the Claude Code harness (e.g. `Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>`) is also accepted — don't rewrite it if the harness emits that form.
|
The model-identifier variant produced by the Claude Code harness (e.g. `Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>`) is also accepted — don't rewrite it if the harness emits that form.
|
||||||
|
|
||||||
## HEREDOC discipline
|
## Message-file discipline
|
||||||
|
|
||||||
Pass commit messages via HEREDOC so multi-line formatting survives:
|
Pass commit messages via a message file so multi-line formatting survives
|
||||||
|
and the command stays inside the permission allowlist (command substitution
|
||||||
|
defeats the `git commit` prefix match and triggers permission prompts):
|
||||||
|
|
||||||
|
1. Write the full message to a file in `/tmp` (never inside `.git/` — that
|
||||||
|
directory is git's own state) using the Write tool.
|
||||||
|
2. Commit with it:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git commit -m "$(cat <<'EOF'
|
git commit -F /tmp/commit-msg.txt
|
||||||
short imperative summary
|
|
||||||
|
|
||||||
Optional longer body explaining why this change was needed,
|
|
||||||
wrapped at about 72 characters.
|
|
||||||
|
|
||||||
Co-Authored-By: Claude <noreply@anthropic.com>
|
|
||||||
EOF
|
|
||||||
)"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Never pass multi-line messages via `-m "line1\nline2"` or multiple `-m` flags — Git's behavior differs between shells and quoting regimes and the trailer can end up in the wrong place.
|
Fallback only: the HEREDOC-in-substitution form
|
||||||
|
(`git commit -m "$(cat <<'EOF' … EOF)"`) works but prompts for permission —
|
||||||
|
use it only when writing a file is impossible. Never pass multi-line messages
|
||||||
|
via `-m "line1\nline2"` or multiple `-m` flags — Git's behavior differs
|
||||||
|
between shells and quoting regimes and the trailer can end up in the wrong
|
||||||
|
place.
|
||||||
|
|
||||||
## What not to commit
|
## What not to commit
|
||||||
|
|
||||||
- `.env` and any `*.env.local` — see `.gitignore`.
|
- `.env` and any `*.env.local` — see `.gitignore`.
|
||||||
- `.claude/settings.local.json` — user-specific Claude Code settings, ignored.
|
- `.claude/settings.local.json` — user-specific Claude Code settings, ignored.
|
||||||
- Build artefacts: `sidecar/bin/`, `sidecar/dist/`, `build/` (Flutter output), `app/.dart_tool/` — gitignored.
|
- Build artefacts: `/build/` (Flutter output), `/.dart_tool/` — gitignored.
|
||||||
- SQLite index files (`*.sqlite`, `*.sqlite-wal`, `*.sqlite-shm`, `*.db`) — caches generated against local repos; must never land here. Gitignored defensively.
|
- SQLite index files (`*.sqlite`, `*.sqlite-wal`, `*.sqlite-shm`, `*.db`) — caches generated against local repos; must never land here. Gitignored defensively.
|
||||||
- Coverage / test output (`*.out`, `coverage.*`, `*.test`) — gitignored.
|
- Coverage / test output (`*.out`, `coverage.*`, `*.test`) — gitignored.
|
||||||
|
|
||||||
|
|||||||
@@ -1,104 +0,0 @@
|
|||||||
---
|
|
||||||
name: penpot-login
|
|
||||||
description: Connect to Penpot MCP - starts the MCP server, logs into penpot.schweitz.net, and installs/connects the plugin
|
|
||||||
allowed-tools: Read, Bash, mcp__chrome-devtools__new_page, mcp__chrome-devtools__navigate_page, mcp__chrome-devtools__take_snapshot, mcp__chrome-devtools__take_screenshot, mcp__chrome-devtools__click, mcp__chrome-devtools__fill, mcp__chrome-devtools__press_key, mcp__chrome-devtools__list_pages
|
|
||||||
---
|
|
||||||
|
|
||||||
# Penpot MCP Connection
|
|
||||||
|
|
||||||
This skill connects Claude to Penpot by:
|
|
||||||
1. Starting the Penpot MCP server (if not running)
|
|
||||||
2. Logging into penpot.schweitz.net via Authentik
|
|
||||||
3. Installing and connecting the Penpot MCP plugin
|
|
||||||
|
|
||||||
## Step 1: Start MCP Server
|
|
||||||
|
|
||||||
Check if the MCP server is running, start it if not:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Check if server is running
|
|
||||||
if ! curl -s http://localhost:9880/mcp > /dev/null 2>&1; then
|
|
||||||
# Start the server in background
|
|
||||||
cd ~/Projects/penpot-mcp && ./start-server.sh &
|
|
||||||
sleep 3 # Wait for server to start
|
|
||||||
fi
|
|
||||||
```
|
|
||||||
|
|
||||||
Server endpoints when running:
|
|
||||||
- MCP Server: http://localhost:9880/mcp
|
|
||||||
- Plugin Server: http://localhost:9879/
|
|
||||||
- WebSocket: ws://localhost:4402
|
|
||||||
|
|
||||||
## Step 2: Login Credentials
|
|
||||||
|
|
||||||
Read credentials from the project root file `claude-authentik-credentials.md`:
|
|
||||||
!`cat claude-authentik-credentials.md`
|
|
||||||
|
|
||||||
## Step 3: Login Flow
|
|
||||||
|
|
||||||
1. **Navigate to Penpot**
|
|
||||||
- Use `mcp__chrome-devtools__new_page` to go to `https://penpot.schweitz.net`
|
|
||||||
|
|
||||||
2. **Check if already logged in**
|
|
||||||
- Take a snapshot
|
|
||||||
- If you see "Projects" heading, you're logged in - skip to Step 4
|
|
||||||
- If you see login page, continue with authentication
|
|
||||||
|
|
||||||
3. **Authenticate via Authentik** (if not logged in)
|
|
||||||
- Click the OpenID button to redirect to Authentik
|
|
||||||
- On auth.schweitz.net, fill username textbox
|
|
||||||
- Click "Log in" button
|
|
||||||
- Fill password textbox
|
|
||||||
- Click "Continue" button
|
|
||||||
- If redirected to Authentik user page instead of Penpot, navigate back to `https://penpot.schweitz.net`
|
|
||||||
|
|
||||||
## Step 4: Open Design File
|
|
||||||
|
|
||||||
1. **Navigate to the Clide project**
|
|
||||||
- Double-click on the TUI file to open the workspace
|
|
||||||
|
|
||||||
## Step 5: Install/Connect Plugin
|
|
||||||
|
|
||||||
1. **Open Plugins menu**
|
|
||||||
- Click the Plugins button (puzzle icon, keyboard shortcut: Cmd+Alt+P)
|
|
||||||
|
|
||||||
2. **Check if plugin is installed**
|
|
||||||
- If "Penpot MCP Plugin" appears under "INSTALLED PLUGINS", click OPEN
|
|
||||||
- Otherwise, install it first:
|
|
||||||
|
|
||||||
3. **Install plugin** (if not installed)
|
|
||||||
- Fill the plugin URL textbox with: `http://localhost:9879/manifest.json`
|
|
||||||
- Click INSTALL
|
|
||||||
- Click ALLOW on the permissions dialog
|
|
||||||
|
|
||||||
4. **Connect to MCP server**
|
|
||||||
- In the plugin UI, click "CONNECT TO MCP SERVER"
|
|
||||||
- Verify it shows "Connected to MCP server"
|
|
||||||
|
|
||||||
## Step 6: Configure Claude Code MCP
|
|
||||||
|
|
||||||
Add the Penpot MCP server to Claude Code (if not already configured):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
claude mcp add penpot -t http http://localhost:9880/mcp
|
|
||||||
```
|
|
||||||
|
|
||||||
**Important**: Use HTTP transport (`-t http`) with the `/mcp` endpoint. Do NOT use SSE transport - it causes "Server not initialized" errors.
|
|
||||||
|
|
||||||
## Step 7: Verify Connection
|
|
||||||
|
|
||||||
After connecting, restart the MCP connection in Claude Code:
|
|
||||||
- Use `/mcp` command to reconnect the penpot server
|
|
||||||
- The Penpot MCP tools (execute_code, export_shape, etc.) will then be available
|
|
||||||
|
|
||||||
Test with:
|
|
||||||
```javascript
|
|
||||||
mcp__penpot__execute_code(code="return penpot.currentPage.name;")
|
|
||||||
```
|
|
||||||
|
|
||||||
## Important Notes
|
|
||||||
|
|
||||||
- Keep the Penpot plugin UI window open while using MCP tools
|
|
||||||
- The MCP server must be running for the plugin to connect
|
|
||||||
- If connection fails, check that the server is running on port 9880
|
|
||||||
- Use HTTP transport (`-t http`), NOT SSE transport
|
|
||||||
@@ -1,203 +0,0 @@
|
|||||||
---
|
|
||||||
name: skill-create
|
|
||||||
description: >
|
|
||||||
Guidance for creating effective Claude Code skills (.skill packages).
|
|
||||||
Use when the user wants to create, build, design, or iterate on a skill —
|
|
||||||
including writing SKILL.md files, bundling scripts/references/assets,
|
|
||||||
initializing new skills, packaging skills, or improving existing ones.
|
|
||||||
Triggers on requests like "create a skill", "make a new skill",
|
|
||||||
"build a skill for X", "package this skill", or "improve my skill".
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
# Skill Creator
|
|
||||||
|
|
||||||
## About Skills
|
|
||||||
|
|
||||||
Skills are modular, self-contained packages that extend Claude's capabilities
|
|
||||||
by providing specialized knowledge, workflows, and tools. They transform Claude
|
|
||||||
from a general-purpose agent into a specialized agent equipped with procedural
|
|
||||||
knowledge that no model can fully possess.
|
|
||||||
|
|
||||||
### What Skills Provide
|
|
||||||
|
|
||||||
- **Specialized workflows** — Multi-step procedures for specific domains
|
|
||||||
- **Tool integrations** — Instructions for working with specific file formats or APIs
|
|
||||||
- **Domain expertise** — Company-specific knowledge, schemas, business logic
|
|
||||||
- **Bundled resources** — Scripts, references, and assets for complex and repetitive tasks
|
|
||||||
|
|
||||||
## Core Principles
|
|
||||||
|
|
||||||
### Concise is Key
|
|
||||||
|
|
||||||
The context window is a public good. Skills share it with everything else Claude
|
|
||||||
needs: system prompt, conversation history, other skills' metadata, and the
|
|
||||||
actual user request.
|
|
||||||
|
|
||||||
Default assumption: Claude is already very smart. Only add context Claude doesn't
|
|
||||||
already have. Challenge each piece of information: "Does Claude really need this
|
|
||||||
explanation?" and "Does this paragraph justify its token cost?"
|
|
||||||
|
|
||||||
Prefer concise examples over verbose explanations.
|
|
||||||
|
|
||||||
### Set Appropriate Degrees of Freedom
|
|
||||||
|
|
||||||
Match specificity to the task's fragility and variability:
|
|
||||||
|
|
||||||
- **High freedom** (text-based instructions): Multiple approaches valid, decisions
|
|
||||||
depend on context, heuristics guide the approach.
|
|
||||||
- **Medium freedom** (pseudocode or scripts with parameters): Preferred pattern
|
|
||||||
exists, some variation acceptable, configuration affects behavior.
|
|
||||||
- **Low freedom** (specific scripts, few parameters): Operations are fragile and
|
|
||||||
error-prone, consistency is critical, specific sequence must be followed.
|
|
||||||
|
|
||||||
Think of Claude as exploring a path: a narrow bridge with cliffs needs specific
|
|
||||||
guardrails (low freedom), while an open field allows many routes (high freedom).
|
|
||||||
|
|
||||||
## Anatomy of a Skill
|
|
||||||
|
|
||||||
```
|
|
||||||
skill-name/
|
|
||||||
├── SKILL.md (required)
|
|
||||||
│ ├── YAML frontmatter metadata (required)
|
|
||||||
│ │ ├── name: (required)
|
|
||||||
│ │ ├── description: (required)
|
|
||||||
│ │ └── compatibility: (optional, rarely needed)
|
|
||||||
│ └── Markdown instructions (required)
|
|
||||||
└── Bundled Resources (optional)
|
|
||||||
├── scripts/ - Executable code (Python/Bash/etc.)
|
|
||||||
├── references/ - Documentation loaded into context as needed
|
|
||||||
└── assets/ - Files used in output (templates, icons, fonts, etc.)
|
|
||||||
```
|
|
||||||
|
|
||||||
### SKILL.md (required)
|
|
||||||
|
|
||||||
- **Frontmatter (YAML)**: `name` and `description` fields (required). Only these
|
|
||||||
are read by Claude to determine when the skill triggers — be clear and
|
|
||||||
comprehensive. The `compatibility` field is for environment requirements but
|
|
||||||
most skills don't need it.
|
|
||||||
- **Body (Markdown)**: Instructions and guidance. Only loaded AFTER the skill
|
|
||||||
triggers.
|
|
||||||
|
|
||||||
### Bundled Resources (optional)
|
|
||||||
|
|
||||||
**Scripts (`scripts/`)** — Executable code for tasks requiring deterministic
|
|
||||||
reliability or that are repeatedly rewritten.
|
|
||||||
|
|
||||||
**References (`references/`)** — Documentation loaded as needed into context.
|
|
||||||
Keep SKILL.md lean; move detailed reference material, schemas, and examples here.
|
|
||||||
If files are large (>10k words), include grep search patterns in SKILL.md.
|
|
||||||
|
|
||||||
**Assets (`assets/`)** — Files used in output, not loaded into context (templates,
|
|
||||||
images, icons, boilerplate code, fonts).
|
|
||||||
|
|
||||||
### What to NOT Include
|
|
||||||
|
|
||||||
Do NOT create extraneous files like README.md, INSTALLATION_GUIDE.md,
|
|
||||||
QUICK_REFERENCE.md, CHANGELOG.md, etc. The skill should only contain information
|
|
||||||
needed for an AI agent to do the job.
|
|
||||||
|
|
||||||
## Progressive Disclosure
|
|
||||||
|
|
||||||
Skills use a three-level loading system:
|
|
||||||
|
|
||||||
1. **Metadata** (name + description) — Always in context (~100 words)
|
|
||||||
2. **SKILL.md body** — When skill triggers (<5k words)
|
|
||||||
3. **Bundled resources** — As needed (unlimited; scripts can run without reading)
|
|
||||||
|
|
||||||
Keep SKILL.md body under 500 lines. Split content into separate files when
|
|
||||||
approaching this limit. Reference split files from SKILL.md with clear
|
|
||||||
descriptions of when to read them.
|
|
||||||
|
|
||||||
### Disclosure Patterns
|
|
||||||
|
|
||||||
**Pattern 1: High-level guide with references** — Keep overview in SKILL.md,
|
|
||||||
link to detail files loaded only when needed.
|
|
||||||
|
|
||||||
**Pattern 2: Domain-specific organization** — Organize content by domain
|
|
||||||
(e.g., `references/finance.md`, `references/sales.md`) so only relevant content
|
|
||||||
is loaded.
|
|
||||||
|
|
||||||
**Pattern 3: Conditional details** — Show basic content, link to advanced
|
|
||||||
content loaded only when the user needs those features.
|
|
||||||
|
|
||||||
Guidelines:
|
|
||||||
- Avoid deeply nested references — keep one level deep from SKILL.md
|
|
||||||
- Structure longer reference files with a table of contents at the top
|
|
||||||
|
|
||||||
## Skill Creation Process
|
|
||||||
|
|
||||||
Follow these steps in order, skipping only with clear reason:
|
|
||||||
|
|
||||||
### Step 1: Understand the Skill with Concrete Examples
|
|
||||||
|
|
||||||
Skip only when usage patterns are already clearly understood.
|
|
||||||
|
|
||||||
Ask the user for concrete examples of how the skill will be used:
|
|
||||||
- "What functionality should the skill support?"
|
|
||||||
- "Can you give some examples of how this skill would be used?"
|
|
||||||
- "What would a user say that should trigger this skill?"
|
|
||||||
|
|
||||||
Avoid overwhelming users — start with the most important questions.
|
|
||||||
|
|
||||||
### Step 2: Plan the Reusable Skill Contents
|
|
||||||
|
|
||||||
Analyze each example by considering how to execute from scratch and identifying
|
|
||||||
what scripts, references, and assets would help with repeated execution.
|
|
||||||
|
|
||||||
Establish a list of reusable resources: scripts, references, and assets.
|
|
||||||
|
|
||||||
### Step 3: Initialize the Skill
|
|
||||||
|
|
||||||
Create the skill directory manually:
|
|
||||||
|
|
||||||
```
|
|
||||||
mkdir -p <output-directory>/<skill-name>
|
|
||||||
```
|
|
||||||
|
|
||||||
Then create `SKILL.md` with frontmatter and body. Add `scripts/`, `references/`,
|
|
||||||
and `assets/` subdirectories only as needed.
|
|
||||||
|
|
||||||
Skip if iterating on an existing skill.
|
|
||||||
|
|
||||||
### Step 4: Edit the Skill
|
|
||||||
|
|
||||||
Remember the skill is for another Claude instance to use. Include beneficial,
|
|
||||||
non-obvious information.
|
|
||||||
|
|
||||||
For design patterns, consult:
|
|
||||||
- `references/workflows.md` — Sequential workflows and conditional logic
|
|
||||||
- `references/output-patterns.md` — Template and example patterns
|
|
||||||
|
|
||||||
**Implementation order:**
|
|
||||||
1. Start with reusable resources (`scripts/`, `references/`, `assets/`)
|
|
||||||
2. Test added scripts by running them
|
|
||||||
3. Delete unused example files from initialization
|
|
||||||
4. Update SKILL.md
|
|
||||||
|
|
||||||
**Writing guidelines:** Always use imperative/infinitive form.
|
|
||||||
|
|
||||||
**Frontmatter:**
|
|
||||||
- `name`: The skill name — use **domain-action** naming: `{domain}-{action}`.
|
|
||||||
The domain is the system/area the skill operates on, the action is what it does.
|
|
||||||
Examples: `pr-review`, `sprint-plan`, `docs-search`, `git-commit`, `debt-scan`.
|
|
||||||
Multi-action wrappers (like `ticket`) can use the domain name alone.
|
|
||||||
The directory name must match the `name` field.
|
|
||||||
- `description`: Primary triggering mechanism. Include what the skill does AND
|
|
||||||
specific triggers/contexts. All "when to use" info goes here (not in body).
|
|
||||||
|
|
||||||
**Body:** Instructions for using the skill and its bundled resources.
|
|
||||||
|
|
||||||
### Step 5: Validate the Skill
|
|
||||||
|
|
||||||
Check the skill manually:
|
|
||||||
- Frontmatter has `name` and `description`
|
|
||||||
- SKILL.md body is under 500 lines
|
|
||||||
- No extraneous files (README.md, CHANGELOG.md, etc.)
|
|
||||||
- Scripts are executable and tested
|
|
||||||
- References are referenced from SKILL.md
|
|
||||||
|
|
||||||
### Step 6: Iterate
|
|
||||||
|
|
||||||
After real usage, notice struggles or inefficiencies, identify needed updates,
|
|
||||||
implement changes, and test again.
|
|
||||||
@@ -6,9 +6,10 @@ description: >
|
|||||||
lifecycle, theme loading, or native platform code. Also use when
|
lifecycle, theme loading, or native platform code. Also use when
|
||||||
the user says "run testmode", "test the app", "smoke test", or
|
the user says "run testmode", "test the app", "smoke test", or
|
||||||
"verify the build". Triggers on changes to: lib/kernel/src/toolchain.dart,
|
"verify the build". Triggers on changes to: lib/kernel/src/toolchain.dart,
|
||||||
lib/src/daemon/dispatcher.dart, lib/src/ipc/, lib/extension/,
|
lib/src/daemon/dispatcher.dart, lib/src/ipc/, lib/src/pty/,
|
||||||
lib/kernel/src/theme/, lib/builtin/*/src/extension.dart,
|
lib/builtin/terminal/, lib/extension/, lib/kernel/src/theme/,
|
||||||
linux/CMakeLists.txt, macos/, Makefile (run targets), lib/main.dart.
|
lib/builtin/*/src/extension.dart, linux/CMakeLists.txt, macos/,
|
||||||
|
Makefile (run targets), lib/main.dart.
|
||||||
---
|
---
|
||||||
|
|
||||||
# Testmode harness
|
# Testmode harness
|
||||||
@@ -26,6 +27,7 @@ make run-testmode # all categories, 60s timeout
|
|||||||
make run-testmode TESTMODE_CATEGORY=toolchain
|
make run-testmode TESTMODE_CATEGORY=toolchain
|
||||||
make run-testmode TESTMODE_CATEGORY=ipc
|
make run-testmode TESTMODE_CATEGORY=ipc
|
||||||
make run-testmode TESTMODE_CATEGORY=extensions
|
make run-testmode TESTMODE_CATEGORY=extensions
|
||||||
|
make run-testmode TESTMODE_CATEGORY=terminal
|
||||||
make run-testmode TESTMODE_TIMEOUT=120 # longer timeout for slow builds
|
make run-testmode TESTMODE_TIMEOUT=120 # longer timeout for slow builds
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -47,6 +49,7 @@ Exit code is non-zero when any test fails. The Makefile verifies
|
|||||||
| IPC envelope, dispatcher, schema | `ipc` | Round-trip + error contract |
|
| IPC envelope, dispatcher, schema | `ipc` | Round-trip + error contract |
|
||||||
| Extension manifest, activate, contributions | `extensions` | Register + activate lifecycle |
|
| Extension manifest, activate, contributions | `extensions` | Register + activate lifecycle |
|
||||||
| Theme YAML, loader, palette | `extensions` | Theme parse is in this category |
|
| Theme YAML, loader, palette | `extensions` | Theme parse is in this category |
|
||||||
|
| PTY spawning, terminal pane, xterm wiring | `terminal` | Real PTY spawn + I/O round-trip |
|
||||||
| Platform config (CMakeLists, pbxproj, Makefile) | `all` | Full rebuild validates everything |
|
| Platform config (CMakeLists, pbxproj, Makefile) | `all` | Full rebuild validates everything |
|
||||||
| Any doubt | `all` | ~30s, cheap insurance |
|
| Any doubt | `all` | ~30s, cheap insurance |
|
||||||
|
|
||||||
|
|||||||
@@ -36,8 +36,41 @@ These apply across every reference and every surface:
|
|||||||
- Never use `Material*` or `Cupertino*` widgets or color constants — clide
|
- Never use `Material*` or `Cupertino*` widgets or color constants — clide
|
||||||
is `WidgetsApp` only (D-7).
|
is `WidgetsApp` only (D-7).
|
||||||
- Use `ClideText` for themed text; never bare `Text` in production widgets.
|
- Use `ClideText` for themed text; never bare `Text` in production widgets.
|
||||||
- Typography: `clideFontMono` for code/paths/IDs, `clideFontCaption` for
|
- Typography sizes: `clideFontMono` for code/paths/IDs, `clideFontCaption` for
|
||||||
status/section headers, body inherits from `DefaultTextStyle`.
|
status/section headers, body inherits from `DefaultTextStyle`.
|
||||||
|
- Font *family* comes from the user-selectable facade, not a const: a
|
||||||
|
monospace surface uses `fontFamily: ClideSettings.fonts.monoOf(context)`
|
||||||
|
(and `fontFamilyFallback: clideMonoFamilyFallback`); the UI face is inherited
|
||||||
|
via the root `DefaultTextStyle`, or `ClideSettings.fonts.uiOf(context)` when a
|
||||||
|
widget must set it explicitly. `clideMonoFamily` / `clideUiFamily` are the
|
||||||
|
facade's defaults — don't read them directly in new widgets (D-101). Same
|
||||||
|
facade exposes `ClideSettings.theme.of(context)` and `.i18n.of(context)`.
|
||||||
|
- User-facing strings resolve through the catalog, never a hardcoded literal
|
||||||
|
(D-21/D-102): `ClideSettings.i18n.string(context, 'dotted.key', namespace:
|
||||||
|
<ext id or 'core'>, placeholder: '<English>')` (or `.interpolated` for
|
||||||
|
templated). Add the key→English to `assets/i18n/en_us/<namespace>.json`. The
|
||||||
|
`placeholder` is the English fallback; the extension's own id is its
|
||||||
|
namespace (framework chrome uses `core`). Contribution manifests carry
|
||||||
|
`titleKey`/`labelKey` for the same reason.
|
||||||
|
|
||||||
|
## Localization & string length (D-21/D-102)
|
||||||
|
|
||||||
|
- **Config / layout.** Catalogs are bundled assets at
|
||||||
|
`assets/i18n/<locale>/<namespace>.json` — the locale is a *directory*
|
||||||
|
(`en_us`, `nl_nl`, `nl_be`, `en_eu`, …); a new language is a new folder of the
|
||||||
|
same namespace files. The active language is `app.locale` (Settings →
|
||||||
|
Appearance → Language), applied live by `root_shell` via `i18n.setLocale`;
|
||||||
|
add the `Locale` to `availableLocales` in `main.dart` and a folder under
|
||||||
|
`assets/i18n/`. `en_US` is default; `nl_NL` ships.
|
||||||
|
- **Design for length variation.** Translations are not the same width — Dutch
|
||||||
|
runs ~20% longer than English, German more. So **never hard-size a surface to
|
||||||
|
its English label.** Tight surfaces (status-bar items, chips, buttons, tab
|
||||||
|
titles, menu items) must tolerate ~30% growth: let them wrap, ellipsis, or
|
||||||
|
`Flexible`/`Expanded`, not a fixed width tuned to English. When you add or
|
||||||
|
translate a label, sanity-check the length delta on those tight surfaces (an
|
||||||
|
`*.semantics` label is screen-reader-only, so its length never deforms
|
||||||
|
layout). A quick audit: compare `len(nl)/len(en)` per key and eyeball the
|
||||||
|
short-but-grew cases on real (non-semantics) surfaces.
|
||||||
|
|
||||||
## Conversation-panel cards (T-305)
|
## Conversation-panel cards (T-305)
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -112,9 +112,37 @@ tooltip → tooltipBackground / tooltipForeground / tooltipBorder
|
|||||||
dropdown → dropdownBackground / dropdownForeground / dropdownBorder
|
dropdown → dropdownBackground / dropdownForeground / dropdownBorder
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Settings & grouped lists — sectioned cards
|
||||||
|
|
||||||
|
Settings surfaces and any long grouped list (e.g. the Claude config lists)
|
||||||
|
read as **sectioned cards**, not bare rows floating on the panel. Each logical
|
||||||
|
group gets its own card; the small-caps section label (+ optional count) sits
|
||||||
|
just **above** the card.
|
||||||
|
|
||||||
|
```
|
||||||
|
panel bg → panelBackground (#20202C)
|
||||||
|
card surface → surface (#242838) fill + dividerColor/border (1px), ~6px corners
|
||||||
|
section head → sidebarSectionHeader (small-caps), with the count muted to its right
|
||||||
|
control inset → inputs INSIDE a card recede to panelBackground, so they still
|
||||||
|
read as fields against the elevated card
|
||||||
|
```
|
||||||
|
|
||||||
|
- **One card per group** — a settings table, each config list. The card's
|
||||||
|
elevated fill + border do the visual separation; don't rely on spacing alone.
|
||||||
|
- **Field row inside a card:** label (`globalForeground`) + help
|
||||||
|
(`globalTextMuted`) + the control right-aligned, with the per-field scope tag
|
||||||
|
in the far-right column.
|
||||||
|
- **Scroll, don't cram:** when stacked cards exceed the modal/pane viewport, the
|
||||||
|
pane scrolls vertically (sticky header, scrolling body) — prefer that over
|
||||||
|
shrinking content to fit one screen.
|
||||||
|
- Pattern reference: the settings wireframes under
|
||||||
|
`docs/design/wireframes/settings/` (T-302).
|
||||||
|
|
||||||
## Anti-patterns
|
## Anti-patterns
|
||||||
|
|
||||||
- `globalBackground` for panel fill → use `panelBackground`
|
- `globalBackground` for panel fill → use `panelBackground`
|
||||||
|
- Bare settings rows on the panel where a group of them should be one card →
|
||||||
|
see "Settings & grouped lists".
|
||||||
- `listItemHoverBackground` in sidebar → use `sidebarItemHover`
|
- `listItemHoverBackground` in sidebar → use `sidebarItemHover`
|
||||||
- Tab active bg = `panelBackground` → use `panelHeader` (elevated chrome)
|
- Tab active bg = `panelBackground` → use `panelHeader` (elevated chrome)
|
||||||
- Tab active border = `globalFocus` → use `panelActiveBorder`
|
- Tab active border = `globalFocus` → use `panelActiveBorder`
|
||||||
|
|||||||
Regular → Executable
+17
-23
@@ -3,27 +3,22 @@
|
|||||||
|
|
||||||
Mirrors `assets/fonts/phosphor/codepoints.csv` (the full bundled glyph set)
|
Mirrors `assets/fonts/phosphor/codepoints.csv` (the full bundled glyph set)
|
||||||
into a readable, greppable markdown table at
|
into a readable, greppable markdown table at
|
||||||
`.claude/skills/ui-design/references/phosphor-glyphs.md`, flagging which
|
`.claude/skills/ui-design/references/phosphor-glyphs.md`.
|
||||||
glyphs clide already defines in `lib/widgets/src/icons/phosphor.dart`.
|
|
||||||
|
That table is also the source of truth for the `kPhosphorGlyphs` map — after
|
||||||
|
regenerating it, re-run `dart run tool/gen_phosphor_glyphs.dart` so
|
||||||
|
`lib/widgets/src/icons/phosphor_glyphs.g.dart` stays in sync.
|
||||||
|
|
||||||
Run from the repo root: python3 .claude/skills/ui-design/scripts/gen-phosphor-glyphs.py
|
Run from the repo root: python3 .claude/skills/ui-design/scripts/gen-phosphor-glyphs.py
|
||||||
"""
|
"""
|
||||||
import csv
|
import csv
|
||||||
import pathlib
|
import pathlib
|
||||||
import re
|
|
||||||
|
|
||||||
ROOT = pathlib.Path(__file__).resolve().parents[4]
|
ROOT = pathlib.Path(__file__).resolve().parents[4]
|
||||||
CSV = ROOT / "assets/fonts/phosphor/codepoints.csv"
|
CSV = ROOT / "assets/fonts/phosphor/codepoints.csv"
|
||||||
DART = ROOT / "lib/widgets/src/icons/phosphor.dart"
|
|
||||||
OUT = ROOT / ".claude/skills/ui-design/references/phosphor-glyphs.md"
|
OUT = ROOT / ".claude/skills/ui-design/references/phosphor-glyphs.md"
|
||||||
|
|
||||||
# Codepoint -> camelCase accessor already defined in PhosphorIcons.
|
|
||||||
defined = {}
|
|
||||||
for m in re.finditer(r"static const (\w+) = PhosphorIconPainter\((0x[0-9a-fA-F]+)\)", DART.read_text()):
|
|
||||||
defined[int(m.group(2), 16)] = m.group(1)
|
|
||||||
|
|
||||||
rows = list(csv.DictReader(CSV.open()))
|
rows = list(csv.DictReader(CSV.open()))
|
||||||
n_def = sum(1 for r in rows if int(r["codepoint"], 16) in defined)
|
|
||||||
|
|
||||||
lines = [
|
lines = [
|
||||||
"---",
|
"---",
|
||||||
@@ -37,22 +32,21 @@ lines = [
|
|||||||
f"All **{len(rows)}** glyphs bundled in clide's Phosphor font "
|
f"All **{len(rows)}** glyphs bundled in clide's Phosphor font "
|
||||||
"(`assets/fonts/phosphor/`, MIT). Generated from "
|
"(`assets/fonts/phosphor/`, MIT). Generated from "
|
||||||
"`assets/fonts/phosphor/codepoints.csv` — **do not hand-edit**; regenerate with "
|
"`assets/fonts/phosphor/codepoints.csv` — **do not hand-edit**; regenerate with "
|
||||||
"`python3 .claude/skills/ui-design/scripts/gen-phosphor-glyphs.py`.",
|
"`python3 .claude/skills/ui-design/scripts/gen-phosphor-glyphs.py`, then re-run "
|
||||||
|
"`dart run tool/gen_phosphor_glyphs.dart` (this table is the source for the "
|
||||||
|
"generated `kPhosphorGlyphs` map).",
|
||||||
"",
|
"",
|
||||||
f"The **In clide** column flags the **{n_def}** glyphs already wired into "
|
"Every glyph is available in code via `PhosphorIcons.byName('<kebab-name>')` "
|
||||||
"`PhosphorIcons` (`lib/widgets/src/icons/phosphor.dart`) — reach for those first. "
|
"(T-314) — e.g. `ClideIcon(PhosphorIcons.byName('folder'), size: 13)`. Raw "
|
||||||
"To use any other glyph, add a one-line `static const` to that class with the "
|
"codepoints never appear in feature code; they live only in the generated map. "
|
||||||
"codepoint below, then `ClideIcon(PhosphorIcons.<name>, size: 13)`. Keep additions "
|
"An unknown name renders the `placeholder` glyph, and `phosphor_glyphs_test` "
|
||||||
"to icons we actually use — don't bulk-import.",
|
"asserts every `byName('…')` literal in `lib/` resolves.",
|
||||||
"",
|
"",
|
||||||
"| Codepoint | Name (kebab) | Pascal | In clide |",
|
"| Codepoint | Name (kebab) | Pascal |",
|
||||||
"|---|---|---|---|",
|
"|---|---|---|",
|
||||||
]
|
]
|
||||||
for r in rows:
|
for r in rows:
|
||||||
cp = r["codepoint"]
|
lines.append(f"| `{r['codepoint']}` | {r['name']} | {r['pascal_name']} |")
|
||||||
accessor = defined.get(int(cp, 16))
|
|
||||||
in_clide = f"`PhosphorIcons.{accessor}`" if accessor else ""
|
|
||||||
lines.append(f"| `{cp}` | {r['name']} | {r['pascal_name']} | {in_clide} |")
|
|
||||||
|
|
||||||
OUT.write_text("\n".join(lines) + "\n")
|
OUT.write_text("\n".join(lines) + "\n")
|
||||||
print(f"wrote {OUT.relative_to(ROOT)} — {len(rows)} glyphs, {n_def} already defined")
|
print(f"wrote {OUT.relative_to(ROOT)} — {len(rows)} glyphs")
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ description: >
|
|||||||
Surface the best batch of tickets to pick up next from pql. Walks the
|
Surface the best batch of tickets to pick up next from pql. Walks the
|
||||||
initiative/epic tree, filters to unblocked work, refines context via
|
initiative/epic tree, filters to unblocked work, refines context via
|
||||||
parallel agents (or `pql ticket refine` for empty descriptions), and
|
parallel agents (or `pql ticket refine` for empty descriptions), and
|
||||||
optionally activates the batch on a fresh branch. Use when the user
|
optionally activates the batch (directly on main — no topic branch by
|
||||||
|
default). Use when the user
|
||||||
says "what's next", "next batch", "pick up work", or invokes
|
says "what's next", "next batch", "pick up work", or invokes
|
||||||
/whats-next. NOT triggered by "what should we work on" in a design
|
/whats-next. NOT triggered by "what should we work on" in a design
|
||||||
context — that's a discussion, not a batch selection.
|
context — that's a discussion, not a batch selection.
|
||||||
@@ -18,7 +19,8 @@ Dependency-driven batch selection against pql. Three steps:
|
|||||||
batch selection → refinement review → batch activation.
|
batch selection → refinement review → batch activation.
|
||||||
|
|
||||||
Pql is the single source of truth for tickets and decisions in this repo
|
Pql is the single source of truth for tickets and decisions in this repo
|
||||||
(see [pql skill](../pql/SKILL.md) and [`decisions/README.md`](../../../decisions/README.md)). Always run from the repo root.
|
(see the pql skill — user scope, installed via `pql init` — and
|
||||||
|
[`governance/README.md`](../../../governance/README.md)). Always run from the repo root.
|
||||||
|
|
||||||
## Step 0: Sync state
|
## Step 0: Sync state
|
||||||
|
|
||||||
@@ -158,8 +160,8 @@ Agent({
|
|||||||
|
|
||||||
Your job:
|
Your job:
|
||||||
1. Run `pql decisions show <decision_ref> --with-refs --pretty` and
|
1. Run `pql decisions show <decision_ref> --with-refs --pretty` and
|
||||||
read the linked D/Q-record in decisions/<domain>.md.
|
read the linked D/Q-record in governance/decisions/<domain>.md.
|
||||||
2. Grep decisions/questions-*.md for related Q-records.
|
2. Grep governance/questions/<domain>.md for related Q-records.
|
||||||
3. Verify referenced files, classes, and APIs actually exist in the
|
3. Verify referenced files, classes, and APIs actually exist in the
|
||||||
current tree (Read/Grep). Flag dangling references.
|
current tree (Read/Grep). Flag dangling references.
|
||||||
4. Cross-check against CLAUDE.md guardrails (single process, CLI-first,
|
4. Cross-check against CLAUDE.md guardrails (single process, CLI-first,
|
||||||
@@ -217,24 +219,22 @@ Batch transition (comma-separated IDs):
|
|||||||
pql ticket status T-1,T-2,T-3 in_progress
|
pql ticket status T-1,T-2,T-3 in_progress
|
||||||
```
|
```
|
||||||
|
|
||||||
**Then persist it.** Ticket mutations (status here, and any `ticket new` in
|
**Then make sure it persists.** Ticket mutations (status here, and any
|
||||||
Step 2) land only in the gitignored `.pql/pql.db`. The post-checkout/post-merge
|
`ticket new` in Step 2) land only in the gitignored `.pql/pql.db`. The
|
||||||
hooks rebuild that DB from the committed changelog on every branch switch — so
|
pre-commit hook runs `pql plan export --stage` automatically — the changelog
|
||||||
un-exported changes vanish silently the next time anyone switches branches. After
|
is exported and staged on every commit, so never hand-run the export or
|
||||||
creating or transitioning tickets, always:
|
`git add .pql/changelog`. The rule is simpler: the turn must land at least
|
||||||
|
one commit (through the git-commit skill). A ticket-only turn with no commit
|
||||||
```bash
|
leaves the mutations in `pql.db` only, and the post-checkout/post-merge hooks
|
||||||
pql plan export # regenerates .pql/changelog/*.sql
|
rebuild that DB from the committed changelog on the next branch switch —
|
||||||
git add .pql/changelog && git commit # durable; survives rebuild
|
silently dropping them. See the pql skill's "Versioning planning state"
|
||||||
```
|
section for the full mechanics.
|
||||||
|
|
||||||
See the [pql skill](../pql/SKILL.md#versioning-planning-state--data-loss-footgun-read-this).
|
|
||||||
|
|
||||||
### 3b. Branch? Default no.
|
### 3b. Branch? Default no.
|
||||||
|
|
||||||
Solo-dev flow on this repo — work lands directly on `main` (see recent
|
Solo-dev flow on this repo — work lands directly on `main` (see recent
|
||||||
`git log`). Don't create a topic branch unless the user explicitly asks.
|
`git log`). Don't create a topic branch unless the user explicitly asks.
|
||||||
If they do, plain `git checkout -b` is fine; there is no `gh` CLI.
|
If they do, plain `git checkout -b` is fine.
|
||||||
|
|
||||||
### 3c. Spawn implementation agents (optional)
|
### 3c. Spawn implementation agents (optional)
|
||||||
|
|
||||||
@@ -263,13 +263,13 @@ End with a tight summary:
|
|||||||
## Anti-patterns
|
## Anti-patterns
|
||||||
|
|
||||||
- Don't skip Step 0 — stale `pql.db` makes the rest of the skill lie.
|
- Don't skip Step 0 — stale `pql.db` makes the rest of the skill lie.
|
||||||
- Don't leave ticket changes un-exported — `pql.db` is gitignored and the
|
- Don't hand-export or hand-stage `.pql/changelog/` — the pre-commit hook does
|
||||||
post-checkout/post-merge hooks rebuild it from the committed changelog, so a
|
both on every commit. The real footgun is a turn that mutates tickets but
|
||||||
branch switch silently drops un-exported tickets. Always `pql plan export` +
|
never commits: `pql.db` is gitignored and gets rebuilt from the committed
|
||||||
commit `.pql/changelog/` after mutating tickets (Step 3a).
|
changelog on branch switch, silently dropping un-committed mutations. Land
|
||||||
|
at least one commit per ticket-mutating turn (Step 3a).
|
||||||
- Don't activate a batch the user hasn't confirmed.
|
- Don't activate a batch the user hasn't confirmed.
|
||||||
- Don't spawn refinement agents for tickets that have no description — use
|
- Don't spawn refinement agents for tickets that have no description — use
|
||||||
`pql ticket refine` instead; it's cheaper and writes back through the
|
`pql ticket refine` instead; it's cheaper and writes back through the
|
||||||
proper channel.
|
proper channel.
|
||||||
- Don't reach for `gh` — this system doesn't have it. Plain `git` only.
|
|
||||||
- Don't `cd` into subdirectories — run everything from the repo root.
|
- Don't `cd` into subdirectories — run everything from the repo root.
|
||||||
|
|||||||
@@ -1,92 +0,0 @@
|
|||||||
# Gitea Actions workflow for clide.
|
|
||||||
#
|
|
||||||
# NOT YET ACTIVATED. Gitea Actions must be enabled in the instance
|
|
||||||
# settings before this runs; until then the file is just a ready-made
|
|
||||||
# pipeline Claude + the user can review.
|
|
||||||
#
|
|
||||||
# When the repo eventually lands on GitHub, copy this file verbatim to
|
|
||||||
# `.github/workflows/test.yml` — Gitea Actions consumes GitHub-Actions
|
|
||||||
# syntax, so no rewrite is needed.
|
|
||||||
|
|
||||||
name: test
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [main]
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
unit:
|
|
||||||
name: unit + widget + golden + a11y
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: subosito/flutter-action@v2
|
|
||||||
with: { channel: stable, cache: true }
|
|
||||||
- run: dart pub get
|
|
||||||
- run: (cd app && flutter pub get)
|
|
||||||
- run: ci/test.sh
|
|
||||||
- run: ci/test_a11y.sh
|
|
||||||
- run: ci/coverage_gate.sh
|
|
||||||
|
|
||||||
integration:
|
|
||||||
name: integration_test (xvfb)
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: unit
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: subosito/flutter-action@v2
|
|
||||||
with: { channel: stable, cache: true }
|
|
||||||
- run: sudo apt-get update && sudo apt-get install -y xvfb ninja-build libgtk-3-dev
|
|
||||||
- run: dart pub get
|
|
||||||
- run: (cd app && flutter pub get)
|
|
||||||
- uses: coactions/setup-xvfb@v1
|
|
||||||
with: { run: ci/test_integration.sh }
|
|
||||||
|
|
||||||
startup-bundle:
|
|
||||||
name: bundle smoke (xvfb 5s)
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: unit
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: subosito/flutter-action@v2
|
|
||||||
with: { channel: stable, cache: true }
|
|
||||||
- run: sudo apt-get update && sudo apt-get install -y xvfb ninja-build libgtk-3-dev
|
|
||||||
- run: dart pub get
|
|
||||||
- run: (cd app && flutter pub get)
|
|
||||||
- run: ci/smoke_bundle.sh
|
|
||||||
|
|
||||||
e2e:
|
|
||||||
name: daemon subprocess + web WASM smoke
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: unit
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: subosito/flutter-action@v2
|
|
||||||
with: { channel: stable, cache: true }
|
|
||||||
- uses: actions/setup-node@v4
|
|
||||||
with: { node-version: 20 }
|
|
||||||
- run: dart pub get
|
|
||||||
- run: (cd app && flutter pub get)
|
|
||||||
- run: (cd tools/ui && npm install && npx playwright install --with-deps chromium)
|
|
||||||
- run: ci/test_e2e.sh
|
|
||||||
|
|
||||||
docs:
|
|
||||||
name: dart doc (lib API)
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: subosito/flutter-action@v2
|
|
||||||
with: { channel: stable, cache: true }
|
|
||||||
- run: dart pub get
|
|
||||||
- name: dart doc --validate-links (fail on warning)
|
|
||||||
run: |
|
|
||||||
set -o pipefail
|
|
||||||
dart doc --validate-links 2>&1 | tee dartdoc.log
|
|
||||||
if grep -q "^ warning:" dartdoc.log; then
|
|
||||||
echo "::error::dartdoc emitted warnings — see log above"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
- uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: dart-api-docs
|
|
||||||
path: doc/api/
|
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# pql: source .pql/hooks/post-checkout (rebuild pql.db on branch checkout)
|
# pql: source .pql/hooks/post-checkout (rebuild pql.db on branch checkout).
|
||||||
. "$(git rev-parse --show-toplevel)/.pql/hooks/post-checkout"
|
# The pql hook is untracked (a local `pql init` install), so a fresh
|
||||||
|
# `git worktree add` has no .pql/hooks — source it only when present, and
|
||||||
|
# always exit 0: post-checkout is best-effort and must never abort the
|
||||||
|
# checkout / worktree creation.
|
||||||
|
hook="$(git rev-parse --show-toplevel)/.pql/hooks/post-checkout"
|
||||||
|
if [ -f "$hook" ]; then . "$hook"; fi
|
||||||
|
exit 0
|
||||||
|
|||||||
+20
-12
@@ -5,14 +5,16 @@
|
|||||||
# Bypass: never. If this runs slowly, fix the slow test; don't reach
|
# Bypass: never. If this runs slowly, fix the slow test; don't reach
|
||||||
# for --no-verify (git-commit skill forbids it).
|
# for --no-verify (git-commit skill forbids it).
|
||||||
#
|
#
|
||||||
# Fast path (T-348): run the full ~2min test suite only when the push touches
|
# Fast path (T-348, widened T-393): run the full ~2min test suite when the push
|
||||||
# lib/ (app + runtime Dart source) or pubspec.* (deps / version). test/,
|
# touches lib/ (app + runtime Dart source), pubspec.* (deps / version), or the
|
||||||
# assets/, docs, and tooling changes ride along with a lib change in practice,
|
# things that can themselves break the suite or this gate — test/, ci/, and
|
||||||
# and an otherwise-skipped push is covered by the next one that does touch lib.
|
# .githooks/. (The old regex matched only lib/ and pubspec.*, so a push that
|
||||||
# The full suite is always available via `make push-check`, and the release CI
|
# ONLY changed a test, a ci/ gate script, or this hook skipped the whole suite.)
|
||||||
# runs it forced on a tagged version. So a lib/pubspec-free push runs just the
|
# Pure assets/docs changes still ride along with the next lib-touching push.
|
||||||
# instant decisions + changelog gates. A state we can't classify (unfetched
|
# There is no release CI — the full suite is only ever run here or via
|
||||||
# remote, new branch) runs the full gate.
|
# `make push-check`. So a push touching none of the above runs just the instant
|
||||||
|
# decisions + changelog gates. A state we can't classify (unfetched remote, new
|
||||||
|
# branch) runs the full gate.
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
cd "$(git rev-parse --show-toplevel)"
|
cd "$(git rev-parse --show-toplevel)"
|
||||||
@@ -40,16 +42,22 @@ while read -r _local_ref local_sha _remote_ref remote_sha; do
|
|||||||
changed+=$'\n'"$(git diff --name-only "$base" "$local_sha")"
|
changed+=$'\n'"$(git diff --name-only "$base" "$local_sha")"
|
||||||
done
|
done
|
||||||
|
|
||||||
# Run the full gate when lib/ (app + runtime source) or pubspec.* (deps /
|
# Paths that force the full gate: source (lib/), deps/version (pubspec.*), and
|
||||||
# version) is touched, or when we couldn't classify above.
|
# the dirs that can themselves break the suite or this gate (test/, ci/,
|
||||||
|
# .githooks/). Single source of truth — test/tooling/pre_push_hook_test.dart
|
||||||
|
# reads this exact pattern, so narrowing it fails that test (the T-393 guard).
|
||||||
|
trigger_re='^(lib/|test/|ci/|\.githooks/|pubspec\.)'
|
||||||
|
|
||||||
|
# Run the full gate when a trigger path is touched, or when we couldn't classify
|
||||||
|
# above.
|
||||||
needs_gate=1
|
needs_gate=1
|
||||||
if [[ "$force_full" -eq 0 ]]; then
|
if [[ "$force_full" -eq 0 ]]; then
|
||||||
trigger_files="$(printf '%s\n' "$changed" | grep -E '^(lib/|pubspec\.)' || true)"
|
trigger_files="$(printf '%s\n' "$changed" | grep -E "$trigger_re" || true)"
|
||||||
[[ -z "$trigger_files" ]] && needs_gate=0
|
[[ -z "$trigger_files" ]] && needs_gate=0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$needs_gate" -eq 0 ]]; then
|
if [[ "$needs_gate" -eq 0 ]]; then
|
||||||
echo "==> pre-push: no lib/ or pubspec change — decisions + changelog gates, skipping tests"
|
echo "==> pre-push: no source/test/ci/hook/pubspec change — decisions + changelog gates, skipping tests"
|
||||||
make decisions-validate changelog-gate
|
make decisions-validate changelog-gate
|
||||||
else
|
else
|
||||||
echo "==> pre-push: make push-check"
|
echo "==> pre-push: make push-check"
|
||||||
|
|||||||
@@ -0,0 +1,104 @@
|
|||||||
|
name: release
|
||||||
|
|
||||||
|
# Build + publish versioned Windows and Linux release bundles when the version
|
||||||
|
# in pubspec.yaml changes on main. The `version` job only proceeds when the
|
||||||
|
# v<version> tag doesn't already exist, so an unrelated pubspec edit is a no-op.
|
||||||
|
#
|
||||||
|
# FIRST CUT — neither build has run in CI yet (Windows has never been built at
|
||||||
|
# all), so expect to iterate on these from the first run's logs. The repo's own
|
||||||
|
# `make` targets are the build contract (gen-build-info + clide-cli + flutter
|
||||||
|
# build, all wired in `make build`).
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
paths: ['pubspec.yaml']
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write # create the tag + the release
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
version:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
version: ${{ steps.v.outputs.version }}
|
||||||
|
fresh: ${{ steps.v.outputs.fresh }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with: { fetch-depth: 0 } # tags, to tell new vs. already-released
|
||||||
|
- id: v
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
version=$(awk -F': *' '/^version:/ {gsub(/[" ]/,"",$2); print $2; exit}' pubspec.yaml)
|
||||||
|
echo "version=$version" >> "$GITHUB_OUTPUT"
|
||||||
|
if git rev-parse "v$version" >/dev/null 2>&1; then
|
||||||
|
echo "fresh=false" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "v$version already tagged — nothing to release."
|
||||||
|
else
|
||||||
|
echo "fresh=true" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "v$version is new — building."
|
||||||
|
fi
|
||||||
|
|
||||||
|
build-linux:
|
||||||
|
needs: version
|
||||||
|
if: needs.version.outputs.fresh == 'true'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: subosito/flutter-action@v2
|
||||||
|
with: { channel: stable }
|
||||||
|
- run: sudo apt-get update && sudo apt-get install -y ninja-build libgtk-3-dev
|
||||||
|
- run: make dugite-fetch
|
||||||
|
- run: make build # gen-build-info + clide-cli + flutter build linux
|
||||||
|
- name: package
|
||||||
|
run: tar -C build/linux/x64/release/bundle -czf clide-linux-x64-${{ needs.version.outputs.version }}.tar.gz .
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with: { name: linux, path: clide-linux-x64-*.tar.gz }
|
||||||
|
|
||||||
|
build-windows:
|
||||||
|
needs: version
|
||||||
|
if: needs.version.outputs.fresh == 'true'
|
||||||
|
runs-on: windows-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: subosito/flutter-action@v2
|
||||||
|
with: { channel: stable }
|
||||||
|
- run: choco install -y make
|
||||||
|
- name: build
|
||||||
|
shell: bash
|
||||||
|
run: make dugite-fetch && make build # MSVC + bash already on windows-latest
|
||||||
|
- name: package
|
||||||
|
shell: pwsh
|
||||||
|
run: Compress-Archive -Path build/windows/x64/runner/Release/* -DestinationPath clide-windows-x64-${{ needs.version.outputs.version }}.zip
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with: { name: windows, path: clide-windows-x64-*.zip }
|
||||||
|
|
||||||
|
publish:
|
||||||
|
needs: [version, build-linux, build-windows]
|
||||||
|
if: needs.version.outputs.fresh == 'true'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: changelog notes for this version
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
ver="${{ needs.version.outputs.version }}"
|
||||||
|
# Pull the entries under `## [<version>]` — the changelog cut that the
|
||||||
|
# version-bump commit lands per the changelog discipline — as the
|
||||||
|
# release body; fall back to a one-liner if the section is absent.
|
||||||
|
awk -v ver="$ver" '
|
||||||
|
$0 ~ "^## \\[" ver "\\]" {grab=1; next}
|
||||||
|
grab && /^## \[/ {exit}
|
||||||
|
grab {print}
|
||||||
|
' CHANGELOG.md > release-notes.md
|
||||||
|
[ -s release-notes.md ] || echo "Release v$ver." > release-notes.md
|
||||||
|
- uses: actions/download-artifact@v4
|
||||||
|
with: { path: dist }
|
||||||
|
- uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
tag_name: v${{ needs.version.outputs.version }}
|
||||||
|
name: clide v${{ needs.version.outputs.version }}
|
||||||
|
body_path: release-notes.md # the version's CHANGELOG section
|
||||||
|
generate_release_notes: true # + auto commit list appended
|
||||||
|
files: dist/**/* # the built versioned bundles
|
||||||
@@ -0,0 +1,152 @@
|
|||||||
|
name: test
|
||||||
|
|
||||||
|
# Linux CI for clide (GitHub Actions). Moved here from .gitea/workflows/ when CI
|
||||||
|
# consolidated onto GitHub (the primary remote); the Gitea secondary has Actions
|
||||||
|
# disabled. Pairs with windows.yml (ConPTY suite on windows-latest) and
|
||||||
|
# release.yml (versioned release bundles).
|
||||||
|
#
|
||||||
|
# Steps go through the make targets (the repo's tooling-discipline rule: the
|
||||||
|
# make layer sets up the environment — gen-build-info etc. — and stays correct
|
||||||
|
# if a wrapped script moves).
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
unit:
|
||||||
|
name: unit + widget + golden + a11y + coverage gate
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: subosito/flutter-action@v2
|
||||||
|
with: { channel: stable, cache: true }
|
||||||
|
- run: flutter pub get
|
||||||
|
- name: install pql
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ github.token }}
|
||||||
|
run: |
|
||||||
|
gh release download --repo postmeridiem/pql --pattern 'pql_*_Linux_x86_64.tar.gz' --output /tmp/pql.tgz
|
||||||
|
tar -xzf /tmp/pql.tgz -C /tmp
|
||||||
|
sudo install -m 0755 /tmp/pql /usr/local/bin/pql
|
||||||
|
pql --version
|
||||||
|
# The pql tests query the repo's vault, but .pql/pql.db is gitignored
|
||||||
|
# (the post-checkout hook rebuilds it from the committed changelog).
|
||||||
|
# A fresh CI checkout has the changelog but no db — materialize it,
|
||||||
|
# and sync decision records from the governance/ DQR markdown tree
|
||||||
|
# (tickets come from the changelog; decisions from `decisions sync`).
|
||||||
|
pql plan import
|
||||||
|
pql decisions sync
|
||||||
|
# test-coverage runs the full fast suite WITH coverage (it includes the
|
||||||
|
# a11y suite — see the push-check note in the Makefile), which is what
|
||||||
|
# coverage-gate consumes.
|
||||||
|
- run: make test-coverage
|
||||||
|
- run: make coverage-gate
|
||||||
|
|
||||||
|
integration:
|
||||||
|
name: integration_test (xvfb)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: unit
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: subosito/flutter-action@v2
|
||||||
|
with: { channel: stable, cache: true }
|
||||||
|
- run: sudo apt-get update && sudo apt-get install -y xvfb ninja-build libgtk-3-dev
|
||||||
|
- run: flutter pub get
|
||||||
|
- name: install pql
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ github.token }}
|
||||||
|
run: |
|
||||||
|
gh release download --repo postmeridiem/pql --pattern 'pql_*_Linux_x86_64.tar.gz' --output /tmp/pql.tgz
|
||||||
|
tar -xzf /tmp/pql.tgz -C /tmp
|
||||||
|
sudo install -m 0755 /tmp/pql /usr/local/bin/pql
|
||||||
|
pql --version
|
||||||
|
# The pql tests query the repo's vault, but .pql/pql.db is gitignored
|
||||||
|
# (the post-checkout hook rebuilds it from the committed changelog).
|
||||||
|
# A fresh CI checkout has the changelog but no db — materialize it,
|
||||||
|
# and sync decision records from the governance/ DQR markdown tree
|
||||||
|
# (tickets come from the changelog; decisions from `decisions sync`).
|
||||||
|
pql plan import
|
||||||
|
pql decisions sync
|
||||||
|
- uses: coactions/setup-xvfb@v1
|
||||||
|
with: { run: make test-integration }
|
||||||
|
|
||||||
|
startup-bundle:
|
||||||
|
name: bundle smoke (xvfb 5s)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: unit
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: subosito/flutter-action@v2
|
||||||
|
with: { channel: stable, cache: true }
|
||||||
|
- run: sudo apt-get update && sudo apt-get install -y xvfb ninja-build libgtk-3-dev
|
||||||
|
- run: flutter pub get
|
||||||
|
- name: install pql
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ github.token }}
|
||||||
|
run: |
|
||||||
|
gh release download --repo postmeridiem/pql --pattern 'pql_*_Linux_x86_64.tar.gz' --output /tmp/pql.tgz
|
||||||
|
tar -xzf /tmp/pql.tgz -C /tmp
|
||||||
|
sudo install -m 0755 /tmp/pql /usr/local/bin/pql
|
||||||
|
pql --version
|
||||||
|
# The pql tests query the repo's vault, but .pql/pql.db is gitignored
|
||||||
|
# (the post-checkout hook rebuilds it from the committed changelog).
|
||||||
|
# A fresh CI checkout has the changelog but no db — materialize it,
|
||||||
|
# and sync decision records from the governance/ DQR markdown tree
|
||||||
|
# (tickets come from the changelog; decisions from `decisions sync`).
|
||||||
|
pql plan import
|
||||||
|
pql decisions sync
|
||||||
|
# Point the real release app's crash logs at an uploadable workspace dir
|
||||||
|
# (T-436): if the bundle wedges on boot, the watchdog heartbeat/sample +
|
||||||
|
# FileLogSink land here and get uploaded below. CLIDE_LOG=debug so the
|
||||||
|
# file sink captures info/debug, not just the release-default warn.
|
||||||
|
- name: bundle smoke (logs → artifact)
|
||||||
|
env:
|
||||||
|
CLIDE_LOG: debug
|
||||||
|
CLIDE_LOG_DIR: ${{ github.workspace }}/clide-logs
|
||||||
|
run: make smoke-bundle
|
||||||
|
- name: Upload crash logs
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: bundle-crash-logs
|
||||||
|
path: ${{ github.workspace }}/clide-logs
|
||||||
|
if-no-files-found: ignore
|
||||||
|
|
||||||
|
web-wasm:
|
||||||
|
name: web build (wasm compile gate)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: subosito/flutter-action@v2
|
||||||
|
with: { channel: stable, cache: true }
|
||||||
|
- run: flutter pub get
|
||||||
|
# Compile gate for the dart:ffi web fence (D-100 / T-438, resolving Q-50):
|
||||||
|
# every native binding lives behind a `dart.library.ffi` conditional import
|
||||||
|
# with a web stub. If a new one lands without its stub, this fails — the
|
||||||
|
# fence can't silently rot. Build-only for now; the full web-WASM Playwright
|
||||||
|
# e2e (`make test-e2e`: setup-node + playwright install in tools/ui +
|
||||||
|
# serve) is the follow-on once the harness is wired back up.
|
||||||
|
- run: flutter build web --wasm
|
||||||
|
|
||||||
|
docs:
|
||||||
|
name: dart doc (lib API)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: subosito/flutter-action@v2
|
||||||
|
with: { channel: stable, cache: true }
|
||||||
|
- run: flutter pub get
|
||||||
|
- name: dart doc --validate-links (fail on warning)
|
||||||
|
run: |
|
||||||
|
set -o pipefail
|
||||||
|
dart doc --validate-links 2>&1 | tee dartdoc.log
|
||||||
|
if grep -q "^ warning:" dartdoc.log; then
|
||||||
|
echo "::error::dartdoc emitted warnings — see log above"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: dart-api-docs
|
||||||
|
path: doc/api/
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
name: windows-soak
|
||||||
|
|
||||||
|
# ConPTY orphan-leak soak on a GitHub-hosted Windows runner — the cheap
|
||||||
|
# alternative to a dedicated Windows VM. The freeze hypothesis (T-424) is that
|
||||||
|
# each WindowsPty.start() leaks its conhost/OpenConsole host because the child
|
||||||
|
# is not in a kill-on-close Job Object; across many runs those hosts pile up
|
||||||
|
# until the box starves. tools/windows-verify/soak-conpty.ps1 reproduces that
|
||||||
|
# WITHOUT crashing: it runs the ConPTY suite many times IN ONE job and counts
|
||||||
|
# the hosts that survive each dart.exe exit. A throwaway runner is fine — we
|
||||||
|
# watch the accumulation (the leading indicator), not the reboot. The repeated
|
||||||
|
# runs happen inside this single job, so the leak can build up here even though
|
||||||
|
# the runner is discarded afterwards (cf. the note in windows.yml, which only
|
||||||
|
# runs the suite once).
|
||||||
|
#
|
||||||
|
# Diagnostic, never a gate: it always exits 0 and just publishes the verdict +
|
||||||
|
# CSV. Runs on demand (workflow_dispatch) and when the soak kit itself changes.
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
iterations:
|
||||||
|
description: How many times to run the ConPTY suite (clean-path soak)
|
||||||
|
default: "25"
|
||||||
|
kill_iterations:
|
||||||
|
description: Spawn+force-kill cycles (abrupt-death orphan probe)
|
||||||
|
default: "15"
|
||||||
|
ptys_per_iter:
|
||||||
|
description: WindowsPty sessions spawned per kill cycle
|
||||||
|
default: "2"
|
||||||
|
push:
|
||||||
|
branches: [windows-support]
|
||||||
|
paths:
|
||||||
|
- tools/windows-verify/**
|
||||||
|
- .github/workflows/windows-soak.yml
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
conpty-soak:
|
||||||
|
runs-on: windows-latest
|
||||||
|
timeout-minutes: 30
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: subosito/flutter-action@v2
|
||||||
|
with:
|
||||||
|
channel: stable
|
||||||
|
- run: flutter --version
|
||||||
|
- run: flutter pub get
|
||||||
|
- name: ConPTY orphan-leak soak
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
$iters = "${{ github.event.inputs.iterations }}"
|
||||||
|
if (-not $iters) { $iters = "25" }
|
||||||
|
tools/windows-verify/soak-conpty.ps1 -Iterations ([int]$iters) -OutDir "$env:GITHUB_WORKSPACE/soak-out"
|
||||||
|
- name: Publish verdict to job summary
|
||||||
|
if: always()
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
$s = Get-ChildItem "$env:GITHUB_WORKSPACE/soak-out/*.summary.txt" -ErrorAction SilentlyContinue | Select-Object -First 1
|
||||||
|
if ($s) { Get-Content $s.FullName | Add-Content $env:GITHUB_STEP_SUMMARY }
|
||||||
|
- name: Upload soak CSV + summary
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: conpty-soak
|
||||||
|
path: soak-out
|
||||||
|
if-no-files-found: warn
|
||||||
|
|
||||||
|
conpty-kill-probe:
|
||||||
|
# Abrupt-death half: force-kill the parent dart.exe mid-life (no close(),
|
||||||
|
# no Job Object) and count the ConPTY hosts that survive. This is the path
|
||||||
|
# the freeze hypothesis (T-424) actually implicates — the clean-path soak
|
||||||
|
# above never exercises it. Diagnostic only; always succeeds.
|
||||||
|
runs-on: windows-latest
|
||||||
|
timeout-minutes: 30
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: subosito/flutter-action@v2
|
||||||
|
with:
|
||||||
|
channel: stable
|
||||||
|
- run: flutter --version
|
||||||
|
- run: flutter pub get
|
||||||
|
- name: ConPTY abrupt-death orphan probe
|
||||||
|
shell: pwsh
|
||||||
|
# CLIDE_LOG_DIR makes the probe emit FFI breadcrumbs (T-436): when a
|
||||||
|
# parent is force-killed mid-life, its reader/waiter isolates' last
|
||||||
|
# crumb ("ReadFile enter" / "WaitForSingleObject enter") is fsynced to
|
||||||
|
# clide-pty.crumbs.log and uploaded below — naming what the wedged
|
||||||
|
# isolate was doing at the instant of death.
|
||||||
|
env:
|
||||||
|
CLIDE_LOG_DIR: ${{ github.workspace }}/kill-crumbs
|
||||||
|
run: |
|
||||||
|
$iters = "${{ github.event.inputs.kill_iterations }}"
|
||||||
|
if (-not $iters) { $iters = "15" }
|
||||||
|
$ptys = "${{ github.event.inputs.ptys_per_iter }}"
|
||||||
|
if (-not $ptys) { $ptys = "2" }
|
||||||
|
tools/windows-verify/soak-conpty-kill.ps1 -Iterations ([int]$iters) -PtysPerIter ([int]$ptys) -OutDir "$env:GITHUB_WORKSPACE/kill-out"
|
||||||
|
- name: Publish verdict to job summary
|
||||||
|
if: always()
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
$s = Get-ChildItem "$env:GITHUB_WORKSPACE/kill-out/*.summary.txt" -ErrorAction SilentlyContinue | Select-Object -First 1
|
||||||
|
if ($s) { Get-Content $s.FullName | Add-Content $env:GITHUB_STEP_SUMMARY }
|
||||||
|
- name: Upload kill-probe CSV + summary
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: conpty-kill-probe
|
||||||
|
path: kill-out
|
||||||
|
if-no-files-found: warn
|
||||||
|
- name: Upload FFI breadcrumbs (last act of each killed reader/waiter)
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: conpty-kill-crumbs
|
||||||
|
path: ${{ github.workspace }}/kill-crumbs
|
||||||
|
if-no-files-found: ignore
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
name: windows
|
||||||
|
|
||||||
|
# Windows CI on GitHub-hosted runners — the only hosted Windows available, and
|
||||||
|
# GitHub is clide's primary remote (the Gitea secondary is self-hosted Linux and
|
||||||
|
# keeps running the Linux suite). This is the first real execution of the ConPTY
|
||||||
|
# backend (lib/src/pty/windows_pty.dart), so expect genuine failures until the
|
||||||
|
# Windows fixes land (T-424). Keep this OUT of required status checks until it's
|
||||||
|
# reliably green — it reports + uploads artifacts without blocking merges. Each
|
||||||
|
# run is a fresh, discarded runner, so the accumulation freeze (which needs
|
||||||
|
# repeated runs on one machine) can't build up here.
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main, windows-support]
|
||||||
|
pull_request:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
windows-pty:
|
||||||
|
runs-on: windows-latest
|
||||||
|
timeout-minutes: 25
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: subosito/flutter-action@v2
|
||||||
|
with:
|
||||||
|
channel: stable
|
||||||
|
- run: flutter --version
|
||||||
|
- run: flutter pub get
|
||||||
|
# No `flutter analyze` here: it's platform-agnostic — the Linux job already
|
||||||
|
# analyzes windows_pty.dart and everything else statically, and the
|
||||||
|
# `flutter build windows` release job catches Windows-specific compile
|
||||||
|
# errors. Skipping it also avoids needing `make gen-build-info`, since the
|
||||||
|
# pty tests import the pty libraries directly, not the build_info-bearing
|
||||||
|
# barrel (lib/clide.dart). This job's unique value is running real ConPTY.
|
||||||
|
- name: ConPTY + Windows-arg unit tests
|
||||||
|
# windows_pty_test.dart drives real ConPTY (it self-skips off-Windows);
|
||||||
|
# the args/size suites are the pure-logic coverage. --timeout 60s so a
|
||||||
|
# wedged reader fails fast instead of hanging the runner.
|
||||||
|
run: dart test --concurrency=1 --timeout 60s test/pty/windows_pty_test.dart test/pty/windows_pty_args_test.dart test/pty/pty_size_test.dart
|
||||||
|
- name: Upload test output / logs
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: windows-test-output
|
||||||
|
# T-425 (crash-survivable FileLogSink) writes under %LOCALAPPDATA%\clide\logs;
|
||||||
|
# add that path here once it lands so a freeze leaves a downloadable log.
|
||||||
|
path: test/.test-output
|
||||||
|
if-no-files-found: ignore
|
||||||
@@ -58,6 +58,8 @@ tools/ui/.serve.pid
|
|||||||
/native/linux-x64/clide
|
/native/linux-x64/clide
|
||||||
/native/macos-arm64/clide
|
/native/macos-arm64/clide
|
||||||
/native/macos-x64/clide
|
/native/macos-x64/clide
|
||||||
|
/native/windows-x64/clide.exe
|
||||||
|
/native/windows-x64/clide.obj
|
||||||
|
|
||||||
# -- Test, coverage, profile output ------------------------------------
|
# -- Test, coverage, profile output ------------------------------------
|
||||||
*.test
|
*.test
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
# This file should be version controlled and should not be manually edited.
|
# This file should be version controlled and should not be manually edited.
|
||||||
|
|
||||||
version:
|
version:
|
||||||
revision: "cc0734ac716fbb8b90f3f9db8020958b1553afa7"
|
revision: "c9a6c484230f8b5e408ec57be1ef71dee1e77020"
|
||||||
channel: "stable"
|
channel: "stable"
|
||||||
|
|
||||||
project_type: app
|
project_type: app
|
||||||
@@ -13,11 +13,11 @@ project_type: app
|
|||||||
migration:
|
migration:
|
||||||
platforms:
|
platforms:
|
||||||
- platform: root
|
- platform: root
|
||||||
create_revision: cc0734ac716fbb8b90f3f9db8020958b1553afa7
|
create_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020
|
||||||
base_revision: cc0734ac716fbb8b90f3f9db8020958b1553afa7
|
base_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020
|
||||||
- platform: web
|
- platform: windows
|
||||||
create_revision: cc0734ac716fbb8b90f3f9db8020958b1553afa7
|
create_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020
|
||||||
base_revision: cc0734ac716fbb8b90f3f9db8020958b1553afa7
|
base_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020
|
||||||
|
|
||||||
# User provided section
|
# User provided section
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
-- Changelog format marker, written by pql. Comments only: this file
|
||||||
|
-- is never executed — Import descends into the per-table directories
|
||||||
|
-- and does not read the changelog root.
|
||||||
|
--
|
||||||
|
-- A changelog carrying no marker is format 1, the shape that existed
|
||||||
|
-- before formats were versioned. An older format is migrated forward
|
||||||
|
-- by `pql plan upgrade` (and automatically from the post-merge hook);
|
||||||
|
-- a newer one is refused rather than replayed under rules this binary
|
||||||
|
-- does not know. See D-28 and docs/versions.md.
|
||||||
|
-- pql:changelog_format: 2.0.0
|
||||||
|
-- pql:written_by: 2.0.0
|
||||||
@@ -1,37 +1,37 @@
|
|||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4AV8YXV4NYWS2ZQYW', '06FB0TNQM6KY9JVRKF22GGFMXR', '2026-05-18 11:59:28', '2026-05-18 11:59:28', NULL, 'ade2722e88d76b4ea6264545ff9b5398', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4AV8YXV4NYWS2ZQYW', '06FB0TNQM6KY9JVRKF22GGFMXR', '2026-05-18 11:59:28', '2026-05-18 11:59:28', NULL, 'ade2722e88d76b4ea6264545ff9b5398', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4AV8YXV4NYWS2ZQYW', '06FB0TNQM78E2NAM4YK3A2AV6R', '2026-05-18 11:59:31', '2026-05-18 11:59:31', NULL, 'd996c0868b309fd7719ab4a8c2e0dd2b', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4AV8YXV4NYWS2ZQYW', '06FB0TNQM78E2NAM4YK3A2AV6R', '2026-05-18 11:59:31', '2026-05-18 11:59:31', NULL, 'd996c0868b309fd7719ab4a8c2e0dd2b', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6KY9JVRKF22GGFMXR', '06FB0TNQM78E2NAM4YK3A2AV6R', '2026-05-18 11:59:34', '2026-05-18 11:59:34', NULL, '05db5396eae627dbfae19415bf12802b', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6KY9JVRKF22GGFMXR', '06FB0TNQM78E2NAM4YK3A2AV6R', '2026-05-18 11:59:34', '2026-05-18 11:59:34', NULL, '05db5396eae627dbfae19415bf12802b', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4AV8YXV4NYWS2ZQYW', '06FB0TNQM7J40S0A8Q8PC0PDY8', '2026-05-18 11:59:37', '2026-05-18 11:59:37', NULL, '44a606dc211dc172a0b7e45dca353555', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4AV8YXV4NYWS2ZQYW', '06FB0TNQM7J40S0A8Q8PC0PDY8', '2026-05-18 11:59:37', '2026-05-18 11:59:37', NULL, '44a606dc211dc172a0b7e45dca353555', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7J40S0A8Q8PC0PDY8', '06FB0TNQM6KEY6593FMW8Y40VC', '2026-05-18 11:59:41', '2026-05-18 11:59:41', NULL, 'a5958fcc4bc52bcba6c5d22119c1152a', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7J40S0A8Q8PC0PDY8', '06FB0TNQM6KEY6593FMW8Y40VC', '2026-05-18 11:59:41', '2026-05-18 11:59:41', NULL, 'a5958fcc4bc52bcba6c5d22119c1152a', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4AV8YXV4NYWS2ZQYW', '06FB0TNQM40XWGSN99DBDQDHJR', '2026-05-18 11:59:44', '2026-05-18 11:59:44', NULL, 'fd9d60cea050f1b2a8657664150e977c', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4AV8YXV4NYWS2ZQYW', '06FB0TNQM40XWGSN99DBDQDHJR', '2026-05-18 11:59:44', '2026-05-18 11:59:44', NULL, 'fd9d60cea050f1b2a8657664150e977c', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM78E2NAM4YK3A2AV6R', '06FB0TNQM40XWGSN99DBDQDHJR', '2026-05-18 11:59:47', '2026-05-18 11:59:47', NULL, '32e0aec7ec29068519dbd31c8a8cdc80', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM78E2NAM4YK3A2AV6R', '06FB0TNQM40XWGSN99DBDQDHJR', '2026-05-18 11:59:47', '2026-05-18 11:59:47', NULL, '32e0aec7ec29068519dbd31c8a8cdc80', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4AV8YXV4NYWS2ZQYW', '06FB0TNQM5MW2V3QCMWKMY4VQM', '2026-05-18 11:59:51', '2026-05-18 11:59:51', NULL, 'cd33e0846477b82b5cf7e00781783b8c', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4AV8YXV4NYWS2ZQYW', '06FB0TNQM5MW2V3QCMWKMY4VQM', '2026-05-18 11:59:51', '2026-05-18 11:59:51', NULL, 'cd33e0846477b82b5cf7e00781783b8c', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM78E2NAM4YK3A2AV6R', '06FB0TNQM5ZSRZARG7SXCC71NM', '2026-05-18 11:59:54', '2026-05-18 11:59:54', NULL, '4ce716dceb22197381bbf6f7f5cb339c', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM78E2NAM4YK3A2AV6R', '06FB0TNQM5ZSRZARG7SXCC71NM', '2026-05-18 11:59:54', '2026-05-18 11:59:54', NULL, '4ce716dceb22197381bbf6f7f5cb339c', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6KEY6593FMW8Y40VC', '06FB0TNQM5ZSRZARG7SXCC71NM', '2026-05-18 11:59:54', '2026-05-18 11:59:54', NULL, '51d502ceb0a41091beb46513618b5b04', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6KEY6593FMW8Y40VC', '06FB0TNQM5ZSRZARG7SXCC71NM', '2026-05-18 11:59:54', '2026-05-18 11:59:54', NULL, '51d502ceb0a41091beb46513618b5b04', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6KY9JVRKF22GGFMXR', '06FB0TNQM5ZSRZARG7SXCC71NM', '2026-05-18 11:59:54', '2026-05-18 11:59:54', NULL, '7f4410ea5c072aaac3317a9ed4a99912', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6KY9JVRKF22GGFMXR', '06FB0TNQM5ZSRZARG7SXCC71NM', '2026-05-18 11:59:54', '2026-05-18 11:59:54', NULL, '7f4410ea5c072aaac3317a9ed4a99912', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7J40S0A8Q8PC0PDY8', '06FB0TNQM5ZSRZARG7SXCC71NM', '2026-05-18 11:59:54', '2026-05-18 11:59:54', NULL, 'ccd6da9f9358922bc665133b792c65ed', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7J40S0A8Q8PC0PDY8', '06FB0TNQM5ZSRZARG7SXCC71NM', '2026-05-18 11:59:54', '2026-05-18 11:59:54', NULL, 'ccd6da9f9358922bc665133b792c65ed', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4AV8YXV4NYWS2ZQYW', '06FB0TNQM5ZSRZARG7SXCC71NM', '2026-05-18 11:59:54', '2026-05-18 11:59:54', NULL, 'd89ba28926b6472133096d779a20f079', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4AV8YXV4NYWS2ZQYW', '06FB0TNQM5ZSRZARG7SXCC71NM', '2026-05-18 11:59:54', '2026-05-18 11:59:54', NULL, 'd89ba28926b6472133096d779a20f079', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6SRMD12DMXCX6N7DM', '06FB0TNQM6E3X5WWRS09GCDGK8', '2026-05-22 15:59:56', '2026-05-22 15:59:56', NULL, '129c875883b4e5a53cdc0683045ace03', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6SRMD12DMXCX6N7DM', '06FB0TNQM6E3X5WWRS09GCDGK8', '2026-05-22 15:59:56', '2026-05-22 15:59:56', NULL, '129c875883b4e5a53cdc0683045ace03', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM54N0ZDJRS7G6MP1XC', '06FB0TNQM6E3X5WWRS09GCDGK8', '2026-05-22 15:59:56', '2026-05-22 15:59:56', NULL, '1b4d4dcf6933819d32df98dff4f89d83', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM54N0ZDJRS7G6MP1XC', '06FB0TNQM6E3X5WWRS09GCDGK8', '2026-05-22 15:59:56', '2026-05-22 15:59:56', NULL, '1b4d4dcf6933819d32df98dff4f89d83', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM653J6604KYDK6RT8R', '06FB0TNQM5AVSMKD15KBJYX48W', '2026-05-22 15:59:56', '2026-05-22 15:59:56', NULL, '1c81cdedd045c46a2f1264bcd1067d11', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM653J6604KYDK6RT8R', '06FB0TNQM5AVSMKD15KBJYX48W', '2026-05-22 15:59:56', '2026-05-22 15:59:56', NULL, '1c81cdedd045c46a2f1264bcd1067d11', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6E3X5WWRS09GCDGK8', '06FB0TNQM4V1PZ0EK6G60699EM', '2026-05-22 15:59:56', '2026-05-22 15:59:56', NULL, '23b6fb946d9de5e730bd186a9ed350e0', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6E3X5WWRS09GCDGK8', '06FB0TNQM4V1PZ0EK6G60699EM', '2026-05-22 15:59:56', '2026-05-22 15:59:56', NULL, '23b6fb946d9de5e730bd186a9ed350e0', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6E3X5WWRS09GCDGK8', '06FB0TNQM5AVSMKD15KBJYX48W', '2026-05-22 15:59:56', '2026-05-22 15:59:56', NULL, '876ead25db98c91cadc5ea7caa65b513', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6E3X5WWRS09GCDGK8', '06FB0TNQM5AVSMKD15KBJYX48W', '2026-05-22 15:59:56', '2026-05-22 15:59:56', NULL, '876ead25db98c91cadc5ea7caa65b513', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4EQAERS4J9X9RAETR', '06FB0TNQM4V1PZ0EK6G60699EM', '2026-05-22 15:59:56', '2026-05-22 15:59:56', NULL, '91e9aa2d0ffd1f32a52bb5cdf019f3fc', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4EQAERS4J9X9RAETR', '06FB0TNQM4V1PZ0EK6G60699EM', '2026-05-22 15:59:56', '2026-05-22 15:59:56', NULL, '91e9aa2d0ffd1f32a52bb5cdf019f3fc', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM653J6604KYDK6RT8R', '06FB0TNQM5V9RNW2BGT5GHRTRG', '2026-05-22 15:59:56', '2026-05-22 15:59:56', NULL, 'a8c93af5185bec5604246916460fea08', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM653J6604KYDK6RT8R', '06FB0TNQM5V9RNW2BGT5GHRTRG', '2026-05-22 15:59:56', '2026-05-22 15:59:56', NULL, 'a8c93af5185bec5604246916460fea08', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4EQAERS4J9X9RAETR', '06FB0TNQM653J6604KYDK6RT8R', '2026-05-22 15:59:56', '2026-05-22 15:59:56', NULL, 'f05aa1ae12d538345bc451d332395b9c', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4EQAERS4J9X9RAETR', '06FB0TNQM653J6604KYDK6RT8R', '2026-05-22 15:59:56', '2026-05-22 15:59:56', NULL, 'f05aa1ae12d538345bc451d332395b9c', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5KN50C7A723SEKZXG', '06FB0TNQM5V9RNW2BGT5GHRTRG', '2026-05-23 06:08:24', '2026-05-23 06:08:24', NULL, 'a0eacf85ca484d159a3dcc6c170f1760', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5KN50C7A723SEKZXG', '06FB0TNQM5V9RNW2BGT5GHRTRG', '2026-05-23 06:08:24', '2026-05-23 06:08:24', NULL, 'a0eacf85ca484d159a3dcc6c170f1760', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM77GWREHKA9K45P020', '06FB0TNQM6YSQYCE096R2SFRXG', '2026-05-23 09:52:40', '2026-05-23 09:52:40', NULL, 'bc99438a38a478190cae7e43c4342526', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM77GWREHKA9K45P020', '06FB0TNQM6YSQYCE096R2SFRXG', '2026-05-23 09:52:40', '2026-05-23 09:52:40', NULL, 'bc99438a38a478190cae7e43c4342526', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM77GWREHKA9K45P020', '06FB0TNQM7BJS5E1JJGSJ9XHG0', '2026-05-23 09:52:43', '2026-05-23 09:52:43', NULL, '2a604702bb0023631d5a98810f695439', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM77GWREHKA9K45P020', '06FB0TNQM7BJS5E1JJGSJ9XHG0', '2026-05-23 09:52:43', '2026-05-23 09:52:43', NULL, '2a604702bb0023631d5a98810f695439', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM77GWREHKA9K45P020', '06FB0TNQM4XM8EY708NAM1JK00', '2026-05-23 09:52:45', '2026-05-23 09:52:45', NULL, '4303c0c52bfcc9f3dbd48f784ef1adf8', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM77GWREHKA9K45P020', '06FB0TNQM4XM8EY708NAM1JK00', '2026-05-23 09:52:45', '2026-05-23 09:52:45', NULL, '4303c0c52bfcc9f3dbd48f784ef1adf8', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4AHSN3BXZFFWS0EPM', '06FB0TNQM78W48QX3JZP0QYAVW', '2026-05-24 16:27:29', '2026-05-24 16:27:29', NULL, '01db76f1732be386944e3da80fcdc0b4', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4AHSN3BXZFFWS0EPM', '06FB0TNQM78W48QX3JZP0QYAVW', '2026-05-24 16:27:29', '2026-05-24 16:27:29', NULL, '01db76f1732be386944e3da80fcdc0b4', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4AHSN3BXZFFWS0EPM', '06FB0TNQM7G7MK8MP3BGQC36HG', '2026-05-24 16:27:29', '2026-05-24 16:27:29', NULL, 'c71b201e5cbe1f75ccda37657808e448', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4AHSN3BXZFFWS0EPM', '06FB0TNQM7G7MK8MP3BGQC36HG', '2026-05-24 16:27:29', '2026-05-24 16:27:29', NULL, 'c71b201e5cbe1f75ccda37657808e448', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4AHSN3BXZFFWS0EPM', '06FB0TNQM7KA37YDBJ89GJ27H4', '2026-05-24 16:27:29', '2026-05-24 16:27:29', NULL, 'c9369a0c50aa82e2afa9a7fa70534b61', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4AHSN3BXZFFWS0EPM', '06FB0TNQM7KA37YDBJ89GJ27H4', '2026-05-24 16:27:29', '2026-05-24 16:27:29', NULL, 'c9369a0c50aa82e2afa9a7fa70534b61', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4AHSN3BXZFFWS0EPM', '06FB0TNQM48P8T23ZPR0BRK6PR', '2026-05-24 16:27:37', '2026-05-24 16:27:37', NULL, '7f6b0dddd7ba67b4db049f3d69b7c807', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4AHSN3BXZFFWS0EPM', '06FB0TNQM48P8T23ZPR0BRK6PR', '2026-05-24 16:27:37', '2026-05-24 16:27:37', NULL, '7f6b0dddd7ba67b4db049f3d69b7c807', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM48P8T23ZPR0BRK6PR', '06FB0TNQM654XV2TG4K0RVV1CW', '2026-05-24 16:27:43', '2026-05-24 16:27:43', NULL, 'ad5cfd3ff355cd44017ea0898ea14780', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM48P8T23ZPR0BRK6PR', '06FB0TNQM654XV2TG4K0RVV1CW', '2026-05-24 16:27:43', '2026-05-24 16:27:43', NULL, 'ad5cfd3ff355cd44017ea0898ea14780', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM48P8T23ZPR0BRK6PR', '06FB0TNQM6FMAHXM1XAHHCQC60', '2026-05-24 16:27:46', '2026-05-24 16:27:46', NULL, '7365404994faf148b33ab5ddc83fa01d', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM48P8T23ZPR0BRK6PR', '06FB0TNQM6FMAHXM1XAHHCQC60', '2026-05-24 16:27:46', '2026-05-24 16:27:46', NULL, '7365404994faf148b33ab5ddc83fa01d', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM654XV2TG4K0RVV1CW', '06FB0TNQM6FMAHXM1XAHHCQC60', '2026-05-24 16:27:52', '2026-05-24 16:27:52', NULL, 'e3930f2673b82e4e6e0938450c522946', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM654XV2TG4K0RVV1CW', '06FB0TNQM6FMAHXM1XAHHCQC60', '2026-05-24 16:27:52', '2026-05-24 16:27:52', NULL, 'e3930f2673b82e4e6e0938450c522946', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM48P8T23ZPR0BRK6PR', '06FB0TNQM71N3YMS82BAYD3M9R', '2026-05-24 16:27:56', '2026-05-24 16:27:56', NULL, '856fdd59d24643888245f06c621f40b8', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM48P8T23ZPR0BRK6PR', '06FB0TNQM71N3YMS82BAYD3M9R', '2026-05-24 16:27:56', '2026-05-24 16:27:56', NULL, '856fdd59d24643888245f06c621f40b8', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM654XV2TG4K0RVV1CW', '06FB0TNQM6V6TKRPA106D5SMMM', '2026-05-25 09:16:24', '2026-05-25 09:16:24', NULL, '329210f950241271814a8ed1255aa993', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM654XV2TG4K0RVV1CW', '06FB0TNQM6V6TKRPA106D5SMMM', '2026-05-25 09:16:24', '2026-05-25 09:16:24', NULL, '329210f950241271814a8ed1255aa993', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM48P8T23ZPR0BRK6PR', '06FB0TNQM67ET3VQP90WRXVSMG', '2026-05-25 09:16:24', '2026-05-25 09:16:24', NULL, '8a8027ce60a1ec2566c0b32f67f7759b', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM48P8T23ZPR0BRK6PR', '06FB0TNQM67ET3VQP90WRXVSMG', '2026-05-25 09:16:24', '2026-05-25 09:16:24', NULL, '8a8027ce60a1ec2566c0b32f67f7759b', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4W624VD4JW1GHDHAR', '06FB0TNQM7WE0SD9N4HCP9BB64', '2026-05-25 09:26:48', '2026-05-25 09:26:48', NULL, '388878e0c968776f9bc7a61934dbd3d6', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4W624VD4JW1GHDHAR', '06FB0TNQM7WE0SD9N4HCP9BB64', '2026-05-25 09:26:48', '2026-05-25 09:26:48', NULL, '388878e0c968776f9bc7a61934dbd3d6', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6YYG4X5R1GX97TJB4', '06FB0TNQM452XPSG99PA60ZZ48', '2026-05-31 18:01:19', '2026-05-31 18:01:19', NULL, '06723eeaf4ac4b3ca32e24df249de904', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6YYG4X5R1GX97TJB4', '06FB0TNQM452XPSG99PA60ZZ48', '2026-05-31 18:01:19', '2026-05-31 18:01:19', NULL, '06723eeaf4ac4b3ca32e24df249de904', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
|
|||||||
@@ -1,28 +1,58 @@
|
|||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM65R8CNFNE1MA5GGR0', '06FB0TNQM4PH1J6ENYT4PJZRHG', '2026-06-01 18:48:57', '2026-06-01 18:48:57', NULL, '1faf4292ceab6cfe3550dfedad554efe', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM65R8CNFNE1MA5GGR0', '06FB0TNQM4PH1J6ENYT4PJZRHG', '2026-06-01 18:48:57', '2026-06-01 18:48:57', NULL, '1faf4292ceab6cfe3550dfedad554efe', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4PH1J6ENYT4PJZRHG', '06FB0TNQM5REFZXMY8ESWN0Z90', '2026-06-01 18:48:57', '2026-06-01 18:48:57', NULL, 'ca9731f8247e19ee44e99f51b4c33ba2', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4PH1J6ENYT4PJZRHG', '06FB0TNQM5REFZXMY8ESWN0Z90', '2026-06-01 18:48:57', '2026-06-01 18:48:57', NULL, 'ca9731f8247e19ee44e99f51b4c33ba2', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6M83TTXHRXESFZY14', '06FB0TNQM5REFZXMY8ESWN0Z90', '2026-06-01 18:48:58', '2026-06-01 18:48:58', NULL, '097bef3723659e681584982688cb242f', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6M83TTXHRXESFZY14', '06FB0TNQM5REFZXMY8ESWN0Z90', '2026-06-01 18:48:58', '2026-06-01 18:48:58', NULL, '097bef3723659e681584982688cb242f', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM54WTNQDMYT0AVR4WM', '06FB0TNQM78J2H2S0R79SSSPW8', '2026-06-02 18:13:52', '2026-06-02 18:13:52', NULL, '112f7b091860de0dc7246f2c1b0eea45', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM54WTNQDMYT0AVR4WM', '06FB0TNQM78J2H2S0R79SSSPW8', '2026-06-02 18:13:52', '2026-06-02 18:13:52', NULL, '112f7b091860de0dc7246f2c1b0eea45', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6Y5SET5WGSS2W78F8', '06FB0TNQM758PXMJH16PA3JHFW', '2026-06-02 18:13:52', '2026-06-02 18:13:52', NULL, '497eb0cb7db0b11194031874d6e8d89d', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6Y5SET5WGSS2W78F8', '06FB0TNQM758PXMJH16PA3JHFW', '2026-06-02 18:13:52', '2026-06-02 18:13:52', NULL, '497eb0cb7db0b11194031874d6e8d89d', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7171NRB1T82TGP5RG', '06FB0TNQM78J2H2S0R79SSSPW8', '2026-06-02 18:13:52', '2026-06-02 18:13:52', NULL, '5102b2f239c5c18631997cbc1f2d998c', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7171NRB1T82TGP5RG', '06FB0TNQM78J2H2S0R79SSSPW8', '2026-06-02 18:13:52', '2026-06-02 18:13:52', NULL, '5102b2f239c5c18631997cbc1f2d998c', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6EGSD0SB7NYNSP1BM', '06FB0TNQM758PXMJH16PA3JHFW', '2026-06-02 18:13:52', '2026-06-02 18:13:52', NULL, '9d0c7bbff8117a3569cf3b7937228184', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6EGSD0SB7NYNSP1BM', '06FB0TNQM758PXMJH16PA3JHFW', '2026-06-02 18:13:52', '2026-06-02 18:13:52', NULL, '9d0c7bbff8117a3569cf3b7937228184', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4C2PSN2GVJY9JDSZG', '06FB0TNQM7171NRB1T82TGP5RG', '2026-06-02 18:13:52', '2026-06-02 18:13:52', NULL, 'd935e3d2978a3584efb0767e75737e84', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4C2PSN2GVJY9JDSZG', '06FB0TNQM7171NRB1T82TGP5RG', '2026-06-02 18:13:52', '2026-06-02 18:13:52', NULL, 'd935e3d2978a3584efb0767e75737e84', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM45HHRBCRMV2166Y6M', '06FB0TNQM5YYMMKFD5Z8WG9F60', '2026-06-07 08:49:16', '2026-06-07 08:49:16', NULL, '11d94aab7a635da1ffb610aa2ade2061', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM45HHRBCRMV2166Y6M', '06FB0TNQM5YYMMKFD5Z8WG9F60', '2026-06-07 08:49:16', '2026-06-07 08:49:16', NULL, '11d94aab7a635da1ffb610aa2ade2061', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM551VZ2NYV6PD0XQRC', '06FB0TNQM4XBRZJ6DEHFWREWC0', '2026-06-07 10:42:46', '2026-06-07 10:42:46', NULL, 'daa1e2dd097721230deca67500c1c00d', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM551VZ2NYV6PD0XQRC', '06FB0TNQM4XBRZJ6DEHFWREWC0', '2026-06-07 10:42:46', '2026-06-07 10:42:46', NULL, 'daa1e2dd097721230deca67500c1c00d', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM551VZ2NYV6PD0XQRC', '06FB0TNQM67PDXAFTPPW7B1WDR', '2026-06-07 10:42:50', '2026-06-07 10:42:50', NULL, '50bb0fcfafb5aacdd747bd9fcd6a3ea6', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM551VZ2NYV6PD0XQRC', '06FB0TNQM67PDXAFTPPW7B1WDR', '2026-06-07 10:42:50', '2026-06-07 10:42:50', NULL, '50bb0fcfafb5aacdd747bd9fcd6a3ea6', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2ERREMEEF26KKHGNZBWW64', '06FB234WP4Y6Q16A0HFW8BSXMG', '2026-06-10 11:12:11', '2026-06-10 11:12:11', NULL, 'e0876fe73623c4063849a13f99d552f5', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2ERREMEEF26KKHGNZBWW64', '06FB234WP4Y6Q16A0HFW8BSXMG', '2026-06-10 11:12:11', '2026-06-10 11:12:11', NULL, 'e0876fe73623c4063849a13f99d552f5', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2ERREMEEF26KKHGNZBWW64', '06FB234WP4Y6Q16A0HFW8BSXMG', '2026-06-10 11:12:11', '2026-06-10 11:12:14', NULL, 'cd39602b20a0681e3cca2dfee38d1734', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2ERREMEEF26KKHGNZBWW64', '06FB234WP4Y6Q16A0HFW8BSXMG', '2026-06-10 11:12:11', '2026-06-10 11:12:14', NULL, 'cd39602b20a0681e3cca2dfee38d1734', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2ERREMEEF26KKHGNZBWW64', '06FB2ESCR4V6V07CRH18FBCDN8', '2026-06-10 11:12:18', '2026-06-10 11:12:18', NULL, 'c74a2c5d562157c24c11c8fa5d04799e', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2ERREMEEF26KKHGNZBWW64', '06FB2ESCR4V6V07CRH18FBCDN8', '2026-06-10 11:12:18', '2026-06-10 11:12:18', NULL, 'c74a2c5d562157c24c11c8fa5d04799e', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2ERREMEEF26KKHGNZBWW64', '06FB2ETJQP0CT6X7W3CWZ6NS9G', '2026-06-10 11:12:20', '2026-06-10 11:12:20', NULL, 'cb20764a77d2a15290ed61a186542095', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2ERREMEEF26KKHGNZBWW64', '06FB2ETJQP0CT6X7W3CWZ6NS9G', '2026-06-10 11:12:20', '2026-06-10 11:12:20', NULL, 'cb20764a77d2a15290ed61a186542095', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2ERREMEEF26KKHGNZBWW64', '06FB2EV29HSK6EJ5VF50R87VC4', '2026-06-10 11:12:25', '2026-06-10 11:12:25', NULL, 'dd9434426790edcaa556221f74c431ba', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2ERREMEEF26KKHGNZBWW64', '06FB2EV29HSK6EJ5VF50R87VC4', '2026-06-10 11:12:25', '2026-06-10 11:12:25', NULL, 'dd9434426790edcaa556221f74c431ba', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2ERREMEEF26KKHGNZBWW64', '06FB2G1WD1839Z90AQ5C0BHNV4', '2026-06-10 11:17:25', '2026-06-10 11:17:25', NULL, '5535e3d16bee2a2cdfcbeb84ea3fca99', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2ERREMEEF26KKHGNZBWW64', '06FB2G1WD1839Z90AQ5C0BHNV4', '2026-06-10 11:17:25', '2026-06-10 11:17:25', NULL, '5535e3d16bee2a2cdfcbeb84ea3fca99', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5TWC00GW0P3X02HZW', '06FB2TY91VHK7TPKPMZ11EG3TM', '2026-06-10 12:04:53', '2026-06-10 12:04:53', NULL, 'ed3717d8f6467c0a77236eda670efce5', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5TWC00GW0P3X02HZW', '06FB2TY91VHK7TPKPMZ11EG3TM', '2026-06-10 12:04:53', '2026-06-10 12:04:53', NULL, 'ed3717d8f6467c0a77236eda670efce5', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5TWC00GW0P3X02HZW', '06FB2TY91VHK7TPKPMZ11EG3TM', '2026-06-10 12:04:53', '2026-06-10 12:05:01', '2026-06-10 12:05:01', '137cd047c9eaec01cac955b49fedd839', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5TWC00GW0P3X02HZW', '06FB2TY91VHK7TPKPMZ11EG3TM', '2026-06-10 12:04:53', '2026-06-10 12:05:01', '2026-06-10 12:05:01', '137cd047c9eaec01cac955b49fedd839', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DJZDDZ00BSA04B660RS7M', '06FB3DKQQJ583944DG8561VQ3G', '2026-06-10 13:27:04', '2026-06-10 13:27:04', NULL, '73383d1011fbad641395f27271b141e6', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DJZDDZ00BSA04B660RS7M', '06FB3DKQQJ583944DG8561VQ3G', '2026-06-10 13:27:04', '2026-06-10 13:27:04', NULL, '73383d1011fbad641395f27271b141e6', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DKQQJ583944DG8561VQ3G', '06FB3DMF20SYFDT6WX2RFBQXKW', '2026-06-10 13:27:04', '2026-06-10 13:27:04', NULL, '45533aa2b124e6547a3804294fcf3aaf', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DKQQJ583944DG8561VQ3G', '06FB3DMF20SYFDT6WX2RFBQXKW', '2026-06-10 13:27:04', '2026-06-10 13:27:04', NULL, '45533aa2b124e6547a3804294fcf3aaf', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DJZDDZ00BSA04B660RS7M', '06FB3DQEMTDHF8SV27AKAB8JHW', '2026-06-10 13:27:05', '2026-06-10 13:27:05', NULL, '0eb2faf91e36a4d37a8a3aa97a8edb71', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DJZDDZ00BSA04B660RS7M', '06FB3DQEMTDHF8SV27AKAB8JHW', '2026-06-10 13:27:05', '2026-06-10 13:27:05', NULL, '0eb2faf91e36a4d37a8a3aa97a8edb71', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DKQQJ583944DG8561VQ3G', '06FB3DQEMTDHF8SV27AKAB8JHW', '2026-06-10 13:27:05', '2026-06-10 13:27:05', NULL, 'b329ff8925097a977f528e7e114d6055', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DKQQJ583944DG8561VQ3G', '06FB3DQEMTDHF8SV27AKAB8JHW', '2026-06-10 13:27:05', '2026-06-10 13:27:05', NULL, 'b329ff8925097a977f528e7e114d6055', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DMF20SYFDT6WX2RFBQXKW', '06FB3DN94MBCTYJW17ZCYVSXE0', '2026-06-10 13:27:08', '2026-06-10 13:27:08', NULL, 'f494f6efad2377e6fc6d0bbf7ae35f07', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DMF20SYFDT6WX2RFBQXKW', '06FB3DN94MBCTYJW17ZCYVSXE0', '2026-06-10 13:27:08', '2026-06-10 13:27:08', NULL, 'f494f6efad2377e6fc6d0bbf7ae35f07', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DQEMTDHF8SV27AKAB8JHW', '06FB3DN94MBCTYJW17ZCYVSXE0', '2026-06-10 13:27:09', '2026-06-10 13:27:09', NULL, 'e5d02fc3a99106d29a9ce6af0626f68e', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DQEMTDHF8SV27AKAB8JHW', '06FB3DN94MBCTYJW17ZCYVSXE0', '2026-06-10 13:27:09', '2026-06-10 13:27:09', NULL, 'e5d02fc3a99106d29a9ce6af0626f68e', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DMF20SYFDT6WX2RFBQXKW', '06FB3DNQZKV20F7YG5PJH8V8SM', '2026-06-10 13:27:09', '2026-06-10 13:27:09', NULL, '1d5185ae9c9676bd70d0e02e3a5e79a1', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DMF20SYFDT6WX2RFBQXKW', '06FB3DNQZKV20F7YG5PJH8V8SM', '2026-06-10 13:27:09', '2026-06-10 13:27:09', NULL, '1d5185ae9c9676bd70d0e02e3a5e79a1', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DQEMTDHF8SV27AKAB8JHW', '06FB3DNQZKV20F7YG5PJH8V8SM', '2026-06-10 13:27:10', '2026-06-10 13:27:10', NULL, '90dca94aa700c143290b2b1afaca09ed', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DQEMTDHF8SV27AKAB8JHW', '06FB3DNQZKV20F7YG5PJH8V8SM', '2026-06-10 13:27:10', '2026-06-10 13:27:10', NULL, '90dca94aa700c143290b2b1afaca09ed', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DMF20SYFDT6WX2RFBQXKW', '06FB3DP48FS33CQGRDF7EB9GT0', '2026-06-10 13:27:10', '2026-06-10 13:27:10', NULL, '9b9081edc77f0e9a4b689bbc191771db', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DMF20SYFDT6WX2RFBQXKW', '06FB3DP48FS33CQGRDF7EB9GT0', '2026-06-10 13:27:10', '2026-06-10 13:27:10', NULL, '9b9081edc77f0e9a4b689bbc191771db', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DJZDDZ00BSA04B660RS7M', '06FB3DQEMTDHF8SV27AKAB8JHW', '2026-06-10 13:27:05', '2026-06-12 01:11:12', NULL, '17f1c884268a172f803f407a2ad47c8c', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DQEMTDHF8SV27AKAB8JHW', '06FB3DN94MBCTYJW17ZCYVSXE0', '2026-06-10 13:27:09', '2026-06-12 01:11:17', NULL, 'a67368ff15089dce57838840632fe07e', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DQEMTDHF8SV27AKAB8JHW', '06FB3DNQZKV20F7YG5PJH8V8SM', '2026-06-10 13:27:10', '2026-06-12 01:11:22', NULL, '0ec8ff6c455136e45fbb1d06a2a690f1', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DMF20SYFDT6WX2RFBQXKW', '06FB3DP48FS33CQGRDF7EB9GT0', '2026-06-10 13:27:10', '2026-06-12 01:11:26', NULL, '3c985828c591c88d492eb261c6d26d33', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DQEMTDHF8SV27AKAB8JHW', '06FB3DMF20SYFDT6WX2RFBQXKW', '2026-06-12 01:11:31', '2026-06-12 01:11:31', NULL, '81fd318a43138a3bef82e31f928ff0b2', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBKMV7Y13PAYKZC0WB4FQXKC', '06FBKMXSVCE98K1H76N00TYCQR', '2026-06-12 03:16:35', '2026-06-12 03:16:35', NULL, '28d9785a1f9696b6b579a1dbb9fdb889', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBKMV7Y13PAYKZC0WB4FQXKC', '06FBKN09R21H3AWR2Q2ZTSGNSW', '2026-06-12 03:16:40', '2026-06-12 03:16:40', NULL, '7e00348c10432c65b03f9dce36520e48', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBKMXSVCE98K1H76N00TYCQR', '06FBKN2MP35NPPK1BRDYY2M428', '2026-06-12 03:16:44', '2026-06-12 03:16:44', NULL, 'a6b1c20279ac30f692a30c802cf8f3e5', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBKMV7Y13PAYKZC0WB4FQXKC', '06FBKN4QVFVE51MY2N0CWCVXHM', '2026-06-12 03:16:49', '2026-06-12 03:16:49', NULL, '9063328f18ba32c0737997ac9af0911a', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBDSM0PRGYR61R0NWYAT9VDC', '06FFW49VYMPF18PYQXD9PCMHN8', '2026-06-25 10:24:38', '2026-06-25 10:24:38', NULL, 'a5146a3cfb2f6a3fd904224150836336', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FFW49VYMPF18PYQXD9PCMHN8', '06FFW49W3V175EM4F8ZHC6JFM4', '2026-06-25 10:24:38', '2026-06-25 10:24:38', NULL, 'd57042b235b73ed2d25252d5253e6e4a', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FFW49VYMPF18PYQXD9PCMHN8', '06FFW49W6GP535GR8XD1XEHYWG', '2026-06-25 10:24:38', '2026-06-25 10:24:38', NULL, '07fe1945cb3e60c43cce0989366af8fb', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FFW49VYMPF18PYQXD9PCMHN8', '06FFW49W95HJK08BCRQSWFZBF4', '2026-06-25 10:24:38', '2026-06-25 10:24:38', NULL, 'e4484230e2202044baaa5ce7a2438bbb', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FFW49W3V175EM4F8ZHC6JFM4', '06FFW49W95HJK08BCRQSWFZBF4', '2026-06-25 10:24:38', '2026-06-25 10:24:38', NULL, '24cc5602737e75d30377522f38b3e7b5', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FFW49W95HJK08BCRQSWFZBF4', '06FFW49WBTT3ESK6QG0XZ1VN2G', '2026-06-25 10:24:38', '2026-06-25 10:24:38', NULL, '51f4759153b30d2a62ed6c69ab62b84d', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FFW49VYMPF18PYQXD9PCMHN8', '06FFW49WEE5N4PESF5G1G5JRHR', '2026-06-25 10:24:38', '2026-06-25 10:24:38', NULL, 'b348cfc357b73fb28366459795752d8b', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FFW49W95HJK08BCRQSWFZBF4', '06FFW49WEE5N4PESF5G1G5JRHR', '2026-06-25 10:24:38', '2026-06-25 10:24:38', NULL, 'e114eff56fef8c92fe3b19df2b8b6e3c', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSQ789MDB00EQAXTXBVJDXM', '06FGSQ8B7WDKZ174GJDGWW0GS0', '2026-06-28 06:14:17.763', '2026-06-28 06:14:17.763', NULL, '973169c6f426d9b4bcfd925ce0f36f32', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSQ8B7WDKZ174GJDGWW0GS0', '06FGSQ8YSZA5YNP1JE8SJHXWBG', '2026-06-28 06:14:17.799', '2026-06-28 06:14:17.799', NULL, '60769ef20f951c01c5d20f512913b946', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2AD3HPR3HXSVASVZEX8PK0', '06FB2ACSDBDZARV3NNGYD9NYYR', '2026-06-28 13:28:39.768', '2026-06-28 13:28:39.768', NULL, 'd5a7084fa717846475fad88d8f30febd', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB234WP4Y6Q16A0HFW8BSXMG', '06FB2ACSDBDZARV3NNGYD9NYYR', '2026-06-28 13:28:39.808', '2026-06-28 13:28:39.808', NULL, '79027c30d19f6f7d43c3068fd80ba8ed', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2ETJQP0CT6X7W3CWZ6NS9G', '06FGX26B0NAC9WRJMVB0QE6CV8', '2026-06-28 14:01:13.773', '2026-06-28 14:01:13.773', NULL, '68cfce9178bbb310b87c76a908781c76', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2ERREMEEF26KKHGNZBWW64', '06FB2ETJQP0CT6X7W3CWZ6NS9G', '2026-06-10 11:12:20', '2026-06-28 15:29:40.913', '2026-06-28 15:29:40.913', '16d8a936aa3083cd16ca25a57a2e1b86', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2ETJQP0CT6X7W3CWZ6NS9G', '06FB2ERREMEEF26KKHGNZBWW64', '2026-06-28 15:29:44.904', '2026-06-28 15:29:44.904', NULL, '545d2ce4f863fd5bb2eee240b696be0c', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2ERREMEEF26KKHGNZBWW64', '06FB234WP4Y6Q16A0HFW8BSXMG', '2026-06-10 11:12:11', '2026-06-28 15:29:57.491', NULL, '6e43179e6b211be30766ca56f5ed5885', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2ERREMEEF26KKHGNZBWW64', '06FB2AD3HPR3HXSVASVZEX8PK0', '2026-06-28 15:30:00.399', '2026-06-28 15:30:00.399', NULL, 'e0961be9550747530f530a7fd300583f', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2ERREMEEF26KKHGNZBWW64', '06FGX26B0NAC9WRJMVB0QE6CV8', '2026-06-28 15:30:03.803', '2026-06-28 15:30:03.803', NULL, 'fa47a4a4aff706215efa3a449681d18f', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2G2KHKT5CJYR0TK1WQGMD0', '06FB2EV29HSK6EJ5VF50R87VC4', '2026-06-28 15:30:10.567', '2026-06-28 15:30:10.567', NULL, '52cd02f3a176cd078db479ef850cbcf4', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGYPJ6FTEPP4JK3D7D01ZSMM', '06FGX26B0NAC9WRJMVB0QE6CV8', '2026-06-28 17:50:13.767', '2026-06-28 17:50:13.767', NULL, '3e0ac1d814ac13a12b68714c7320075f', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
|
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2G2KHKT5CJYR0TK1WQGMD0', '06FB2EV29HSK6EJ5VF50R87VC4', '2026-06-28 15:30:10.567', '2026-06-29 21:58:13.907', '2026-06-29 21:58:13.907', '3b7ec3277f971c3646a7587b06606335', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_deps.updated_at;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,111 @@
|
|||||||
|
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2G2KHKT5CJYR0TK1WQGMD0', 'description', 'Tier-5 graph VIEW, absorbed from the former T-7 into the unified canvas epic (T-317). Force-directed layout of the vault (or a filtered subset): nodes are notes, edges are wikilinks. Hover highlights the connected subgraph; click opens the note in the editor. Filter pane: tag include/exclude, file glob, depth-from-active. pql provides the link data (pql backlinks / pql outlinks); rendering is owned in-app (CustomPaint, own-the-rendering-stack). Lives in its own slot per D-47 (context panel), uses MultitabPane (T-83). DISTINCT from the in-card graph TEMPLATE (T-321): T-321 renders a graph passed into the conversation drawing card; this is the full interactive graph pane over the whole vault. Relates to the core renderer (T-318) but has its own force-directed layout.
|
||||||
|
|
||||||
|
PROGRESS (2026-06-29): force-directed layout SOLVER built + tested (lib/src/graph/force_layout.dart, 6 dart-test cases, commit bcef3a6f) — deterministic Fruchterman-Reingold, Flutter-free. REMAINING (the bulk, multi-session): graph data model from pql backlinks/outlinks over the vault; CustomPaint rendering (nodes+edges); pan/zoom; hover-highlight-subgraph; click-opens-note; filter pane (tag/glob/depth); MultitabPane + context-panel slot (D-47) wiring; widget/golden tests. This is a full interactive Tier-5 pane, a fresh-session undertaking — only its solver core is done.', 'Tier-5 graph VIEW, absorbed from the former T-7 into the unified canvas epic (T-317). Force-directed layout of the vault (or a filtered subset): nodes are notes, edges are wikilinks. Hover highlights the connected subgraph; click opens the note in the editor. Filter pane: tag include/exclude, file glob, depth-from-active. pql provides the link data (pql backlinks / pql outlinks); rendering is owned in-app (CustomPaint, own-the-rendering-stack). Lives in its own slot per D-47 (context panel), uses MultitabPane (T-83). DISTINCT from the in-card graph TEMPLATE (T-321): T-321 renders a graph passed into the conversation drawing card; this is the full interactive graph pane over the whole vault. Relates to the core renderer (T-318) but has its own force-directed layout.
|
||||||
|
|
||||||
|
PROGRESS (2026-06-29): force-directed layout SOLVER built + tested (lib/src/graph/force_layout.dart, 6 dart-test cases, commit bcef3a6f) — deterministic Fruchterman-Reingold, Flutter-free. REMAINING (the bulk, multi-session): graph data model from pql backlinks/outlinks over the vault; CustomPaint rendering (nodes+edges); pan/zoom; hover-highlight-subgraph; click-opens-note; filter pane (tag/glob/depth); MultitabPane + context-panel slot (D-47) wiring; widget/golden tests. This is a full interactive Tier-5 pane, a fresh-session undertaking — only its solver core is done.
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02): the graph rendering + interaction foundation is BUILT + tested (4 slices, all committed). (1) force-directed solver — force_layout.dart (bcef3a6f). (2) link-graph model — vault_graph.dart: VaultGraph.fromOutlinks, neighborhood, edgePairs (084bf842). (3) CustomPaint renderer — graph_painter.dart: edges/nodes/labels, hover-dim, fit transform (6bea1723). (4) interactive GraphView — graph_view.dart: hover-highlight + click-to-open, shared GraphViewport hit-testing (c529703b). The graph is a fully working WIDGET (renders + hover + click). REMAINING = the app-integration phase: pql link-data wiring (pql outlinks over the vault -> the file->outlinks map -> VaultGraph), the pane shell (async load + filter: tag/glob/depth + pan/zoom), and MultitabPane + context-panel slot (D-47) + GraphExtension registration.', NULL, '2026-07-02 06:35:03', '2026-07-02 06:35:03.555', '2026-07-02 06:35:03.555', NULL, '33a6fd1c81f2e1142d15ce5791ce3b24', 2) ON CONFLICT(hash) DO NOTHING;
|
||||||
|
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2G2KHKT5CJYR0TK1WQGMD0', 'description', 'Tier-5 graph VIEW, absorbed from the former T-7 into the unified canvas epic (T-317). Force-directed layout of the vault (or a filtered subset): nodes are notes, edges are wikilinks. Hover highlights the connected subgraph; click opens the note in the editor. Filter pane: tag include/exclude, file glob, depth-from-active. pql provides the link data (pql backlinks / pql outlinks); rendering is owned in-app (CustomPaint, own-the-rendering-stack). Lives in its own slot per D-47 (context panel), uses MultitabPane (T-83). DISTINCT from the in-card graph TEMPLATE (T-321): T-321 renders a graph passed into the conversation drawing card; this is the full interactive graph pane over the whole vault. Relates to the core renderer (T-318) but has its own force-directed layout.
|
||||||
|
|
||||||
|
PROGRESS (2026-06-29): force-directed layout SOLVER built + tested (lib/src/graph/force_layout.dart, 6 dart-test cases, commit bcef3a6f) — deterministic Fruchterman-Reingold, Flutter-free. REMAINING (the bulk, multi-session): graph data model from pql backlinks/outlinks over the vault; CustomPaint rendering (nodes+edges); pan/zoom; hover-highlight-subgraph; click-opens-note; filter pane (tag/glob/depth); MultitabPane + context-panel slot (D-47) wiring; widget/golden tests. This is a full interactive Tier-5 pane, a fresh-session undertaking — only its solver core is done.
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02): the graph rendering + interaction foundation is BUILT + tested (4 slices, all committed). (1) force-directed solver — force_layout.dart (bcef3a6f). (2) link-graph model — vault_graph.dart: VaultGraph.fromOutlinks, neighborhood, edgePairs (084bf842). (3) CustomPaint renderer — graph_painter.dart: edges/nodes/labels, hover-dim, fit transform (6bea1723). (4) interactive GraphView — graph_view.dart: hover-highlight + click-to-open, shared GraphViewport hit-testing (c529703b). The graph is a fully working WIDGET (renders + hover + click). REMAINING = the app-integration phase: pql link-data wiring (pql outlinks over the vault -> the file->outlinks map -> VaultGraph), the pane shell (async load + filter: tag/glob/depth + pan/zoom), and MultitabPane + context-panel slot (D-47) + GraphExtension registration.', 'Tier-5 graph VIEW, absorbed from the former T-7 into the unified canvas epic (T-317). Force-directed layout of the vault (or a filtered subset): nodes are notes, edges are wikilinks. Hover highlights the connected subgraph; click opens the note in the editor. Filter pane: tag include/exclude, file glob, depth-from-active. pql provides the link data (pql backlinks / pql outlinks); rendering is owned in-app (CustomPaint, own-the-rendering-stack). Lives in its own slot per D-47 (context panel), uses MultitabPane (T-83). DISTINCT from the in-card graph TEMPLATE (T-321): T-321 renders a graph passed into the conversation drawing card; this is the full interactive graph pane over the whole vault. Relates to the core renderer (T-318) but has its own force-directed layout.
|
||||||
|
|
||||||
|
PROGRESS (2026-06-29): force-directed layout SOLVER built + tested (lib/src/graph/force_layout.dart, 6 dart-test cases, commit bcef3a6f) — deterministic Fruchterman-Reingold, Flutter-free. REMAINING (the bulk, multi-session): graph data model from pql backlinks/outlinks over the vault; CustomPaint rendering (nodes+edges); pan/zoom; hover-highlight-subgraph; click-opens-note; filter pane (tag/glob/depth); MultitabPane + context-panel slot (D-47) wiring; widget/golden tests. This is a full interactive Tier-5 pane, a fresh-session undertaking — only its solver core is done.
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02): the graph rendering + interaction foundation is BUILT + tested (4 slices, all committed). (1) force-directed solver — force_layout.dart (bcef3a6f). (2) link-graph model — vault_graph.dart: VaultGraph.fromOutlinks, neighborhood, edgePairs (084bf842). (3) CustomPaint renderer — graph_painter.dart: edges/nodes/labels, hover-dim, fit transform (6bea1723). (4) interactive GraphView — graph_view.dart: hover-highlight + click-to-open, shared GraphViewport hit-testing (c529703b). The graph is a fully working WIDGET (renders + hover + click). REMAINING = the app-integration phase: pql link-data wiring (pql outlinks over the vault -> the file->outlinks map -> VaultGraph), the pane shell (async load + filter: tag/glob/depth + pan/zoom), and MultitabPane + context-panel slot (D-47) + GraphExtension registration.
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02, session 2): app-integration phase — 3 slices committed. (1) GraphController (graph_controller.dart, 3b67725b) — pql.files + per-file pql.outlinks over the vault -> VaultGraph; loading/error state; debounced files.changed refresh; 6 tests. (2) GraphPanel shell (graph_panel.dart, 6fae1bc4) — loading/empty/error states + GraphView + click-to-open via editor.open; 5 widget tests. (3) GraphExtension registration (extension.dart + builtin.graph i18n, a5acb6ac) — graph.view context-panel tab (D-47), activates after builtin.pql dep; 4 tests; CHANGELOG entry. The graph is now REACHABLE end-to-end (21 graph tests green). REMAINING (T-323 enrichment): pan/zoom on the view; filter controls (tag include/exclude, glob, depth-from-active).', NULL, '2026-07-02 08:33:27', '2026-07-02 08:33:27.519', '2026-07-02 08:33:27.519', NULL, '65090e3a71c9f5f49b8070a112216210', 2) ON CONFLICT(hash) DO NOTHING;
|
||||||
|
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FJ4D0GAXM1FN42PJKG7FE34G', 'status', 'backlog', 'done', NULL, '2026-07-02 09:55:52', '2026-07-02 09:55:52.114', '2026-07-02 09:55:52.114', NULL, 'a417eec1fa067a31e46b21578a6228fb', 2) ON CONFLICT(hash) DO NOTHING;
|
||||||
|
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2G2KHKT5CJYR0TK1WQGMD0', 'description', 'Tier-5 graph VIEW, absorbed from the former T-7 into the unified canvas epic (T-317). Force-directed layout of the vault (or a filtered subset): nodes are notes, edges are wikilinks. Hover highlights the connected subgraph; click opens the note in the editor. Filter pane: tag include/exclude, file glob, depth-from-active. pql provides the link data (pql backlinks / pql outlinks); rendering is owned in-app (CustomPaint, own-the-rendering-stack). Lives in its own slot per D-47 (context panel), uses MultitabPane (T-83). DISTINCT from the in-card graph TEMPLATE (T-321): T-321 renders a graph passed into the conversation drawing card; this is the full interactive graph pane over the whole vault. Relates to the core renderer (T-318) but has its own force-directed layout.
|
||||||
|
|
||||||
|
PROGRESS (2026-06-29): force-directed layout SOLVER built + tested (lib/src/graph/force_layout.dart, 6 dart-test cases, commit bcef3a6f) — deterministic Fruchterman-Reingold, Flutter-free. REMAINING (the bulk, multi-session): graph data model from pql backlinks/outlinks over the vault; CustomPaint rendering (nodes+edges); pan/zoom; hover-highlight-subgraph; click-opens-note; filter pane (tag/glob/depth); MultitabPane + context-panel slot (D-47) wiring; widget/golden tests. This is a full interactive Tier-5 pane, a fresh-session undertaking — only its solver core is done.
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02): the graph rendering + interaction foundation is BUILT + tested (4 slices, all committed). (1) force-directed solver — force_layout.dart (bcef3a6f). (2) link-graph model — vault_graph.dart: VaultGraph.fromOutlinks, neighborhood, edgePairs (084bf842). (3) CustomPaint renderer — graph_painter.dart: edges/nodes/labels, hover-dim, fit transform (6bea1723). (4) interactive GraphView — graph_view.dart: hover-highlight + click-to-open, shared GraphViewport hit-testing (c529703b). The graph is a fully working WIDGET (renders + hover + click). REMAINING = the app-integration phase: pql link-data wiring (pql outlinks over the vault -> the file->outlinks map -> VaultGraph), the pane shell (async load + filter: tag/glob/depth + pan/zoom), and MultitabPane + context-panel slot (D-47) + GraphExtension registration.
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02, session 2): app-integration phase — 3 slices committed. (1) GraphController (graph_controller.dart, 3b67725b) — pql.files + per-file pql.outlinks over the vault -> VaultGraph; loading/error state; debounced files.changed refresh; 6 tests. (2) GraphPanel shell (graph_panel.dart, 6fae1bc4) — loading/empty/error states + GraphView + click-to-open via editor.open; 5 widget tests. (3) GraphExtension registration (extension.dart + builtin.graph i18n, a5acb6ac) — graph.view context-panel tab (D-47), activates after builtin.pql dep; 4 tests; CHANGELOG entry. The graph is now REACHABLE end-to-end (21 graph tests green). REMAINING (T-323 enrichment): pan/zoom on the view; filter controls (tag include/exclude, glob, depth-from-active).', 'Tier-5 graph VIEW, absorbed from the former T-7 into the unified canvas epic (T-317). Force-directed layout of the vault (or a filtered subset): nodes are notes, edges are wikilinks. Hover highlights the connected subgraph; click opens the note in the editor. Filter pane: tag include/exclude, file glob, depth-from-active. pql provides the link data (pql backlinks / pql outlinks); rendering is owned in-app (CustomPaint, own-the-rendering-stack). Lives in its own slot per D-47 (context panel), uses MultitabPane (T-83). DISTINCT from the in-card graph TEMPLATE (T-321): T-321 renders a graph passed into the conversation drawing card; this is the full interactive graph pane over the whole vault. Relates to the core renderer (T-318) but has its own force-directed layout.
|
||||||
|
|
||||||
|
PROGRESS (2026-06-29): force-directed layout SOLVER built + tested (lib/src/graph/force_layout.dart, 6 dart-test cases, commit bcef3a6f) — deterministic Fruchterman-Reingold, Flutter-free. REMAINING (the bulk, multi-session): graph data model from pql backlinks/outlinks over the vault; CustomPaint rendering (nodes+edges); pan/zoom; hover-highlight-subgraph; click-opens-note; filter pane (tag/glob/depth); MultitabPane + context-panel slot (D-47) wiring; widget/golden tests. This is a full interactive Tier-5 pane, a fresh-session undertaking — only its solver core is done.
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02): the graph rendering + interaction foundation is BUILT + tested (4 slices, all committed). (1) force-directed solver — force_layout.dart (bcef3a6f). (2) link-graph model — vault_graph.dart: VaultGraph.fromOutlinks, neighborhood, edgePairs (084bf842). (3) CustomPaint renderer — graph_painter.dart: edges/nodes/labels, hover-dim, fit transform (6bea1723). (4) interactive GraphView — graph_view.dart: hover-highlight + click-to-open, shared GraphViewport hit-testing (c529703b). The graph is a fully working WIDGET (renders + hover + click). REMAINING = the app-integration phase: pql link-data wiring (pql outlinks over the vault -> the file->outlinks map -> VaultGraph), the pane shell (async load + filter: tag/glob/depth + pan/zoom), and MultitabPane + context-panel slot (D-47) + GraphExtension registration.
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02, session 2): app-integration phase — 3 slices committed. (1) GraphController (graph_controller.dart, 3b67725b) — pql.files + per-file pql.outlinks over the vault -> VaultGraph; loading/error state; debounced files.changed refresh; 6 tests. (2) GraphPanel shell (graph_panel.dart, 6fae1bc4) — loading/empty/error states + GraphView + click-to-open via editor.open; 5 widget tests. (3) GraphExtension registration (extension.dart + builtin.graph i18n, a5acb6ac) — graph.view context-panel tab (D-47), activates after builtin.pql dep; 4 tests; CHANGELOG entry. The graph is now REACHABLE end-to-end (21 graph tests green). REMAINING (T-323 enrichment): pan/zoom on the view; filter controls (tag include/exclude, glob, depth-from-active).
|
||||||
|
|
||||||
|
COMPLETE (2026-07-02, session 2). All scope delivered + tested (56 graph tests, make test green, real-boot verified via testmode). Slices this session: GraphController (3b67725b), pane shell (6fae1bc4), extension+i18n registration (a5acb6ac), pan+zoom (e6556401), testmode coverage (46d9b403), filter model (f859173b), filter bar (aabec87d). Final feature: force-directed vault graph in the context panel (graph.view, D-47) — hover-highlight, click-to-open, scroll-zoom, drag-pan, and filters (path glob re-queries pql; depth-from-active local graph; tri-state tag include/exclude). Controller uses pql.meta (outlinks+tags in one call) and strips #heading fragments so heading links connect. NOTE: pql data load is 1 files + N meta calls (sequential); batching is a future optimisation if large vaults feel slow.', NULL, '2026-07-02 19:47:37', '2026-07-02 19:47:37.694', '2026-07-02 19:47:37.694', NULL, 'a9f6b8b38858b687f106d1bda236821d', 2) ON CONFLICT(hash) DO NOTHING;
|
||||||
|
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2G2KHKT5CJYR0TK1WQGMD0', 'status', 'in_progress', 'done', NULL, '2026-07-02 19:47:44', '2026-07-02 19:47:44.357', '2026-07-02 19:47:44.357', NULL, 'c8bf520d62290050e6d0feb4a9a6a68d', 2) ON CONFLICT(hash) DO NOTHING;
|
||||||
|
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2G1WD1839Z90AQ5C0BHNV4', 'description', 'Tier-5 canvas PANE, absorbed from the former T-7 into the unified canvas epic (T-317, decision D-91). A full workspace pane that renders .canvas files by CONVERTING them into the drawing-card JSON (per D-91: .canvas is an import format, not a native schema) and painting via the shared canvas renderer (T-318). Scope: nodes (note, text, group, image) + edges + layout state; pan/zoom; node selection, drag, resize; edit affordances (add note from file picker, add text node, draw edge between nodes); persist layout back to the .canvas file on disk. Uses MultitabPane (T-83) for tabs and its own slot per D-47; panels are extension-shaped (D-17). Depends on the core renderer (T-318). NOTE: unlike the conversation drawing card (display-only, D-78), this pane is interactive/editable — it is a pane, not a conversation widget.
|
||||||
|
|
||||||
|
SCOPE NOTE (2026-06-29): currently a 17-line stub. This is a from-scratch interactive Tier-5 pane (parse .canvas -> drawing-card JSON, CustomPaint render, pan/zoom, node select/drag/resize, edit affordances, persist .canvas) — a multi-session feature, NOT template-class work. The drawing-card TEMPLATE half of epic T-317 is now complete (svg/d2/image/icon/compare/graph + stdin).', 'Tier-5 canvas PANE, absorbed from the former T-7 into the unified canvas epic (T-317, decision D-91). A full workspace pane that renders .canvas files by CONVERTING them into the drawing-card JSON (per D-91: .canvas is an import format, not a native schema) and painting via the shared canvas renderer (T-318). Scope: nodes (note, text, group, image) + edges + layout state; pan/zoom; node selection, drag, resize; edit affordances (add note from file picker, add text node, draw edge between nodes); persist layout back to the .canvas file on disk. Uses MultitabPane (T-83) for tabs and its own slot per D-47; panels are extension-shaped (D-17). Depends on the core renderer (T-318). NOTE: unlike the conversation drawing card (display-only, D-78), this pane is interactive/editable — it is a pane, not a conversation widget.
|
||||||
|
|
||||||
|
SCOPE NOTE (2026-06-29): currently a 17-line stub. This is a from-scratch interactive Tier-5 pane (parse .canvas -> drawing-card JSON, CustomPaint render, pan/zoom, node select/drag/resize, edit affordances, persist .canvas) — a multi-session feature, NOT template-class work. The drawing-card TEMPLATE half of epic T-317 is now complete (svg/d2/image/icon/compare/graph + stdin).
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02): two foundation slices built + tested (from the 17-line stub). (1) JSONCanvas parser/model — lib/src/canvas/json_canvas.dart (2eb5d0f1): typed CanvasDoc (text/file/link/group nodes + edges with sides/ends/color/label), parse + toJson round-trip, skips unknown/malformed; pure Dart, 8 dart-test cases. (2) CustomPaint renderer — lib/builtin/canvas/src/canvas_painter.dart (035a37a1): CanvasBounds + pan/zoom CanvasViewport, group frames + edges (arrowheads) + node cards; node colours from the file (Obsidian presets/hex, NOT clide tokens per arbitrary-content rule), chrome themed; 7 tests (pixel-probe + viewport + colour). DECISION NOTE: the interactive pane paints the CanvasDoc model directly via CustomPaint (hit-testable, cheap re-paint) rather than re-lowering to SVG each frame — the ticket''s ''convert to drawing-card JSON'' path (D-91 SVG substrate) is for the display-only viewer; an editable pane needs direct model painting. Mirrors the graph pane. REMAINING (multi-session): interactive CanvasView (hit-test nodes + pan/zoom + click-select), pane shell (load .canvas from disk, workspace slot D-47, MultitabPane), CanvasExtension registration + open-.canvas routing, then edit affordances (add node/edge, drag, resize) + persist back to disk.', NULL, '2026-07-02 20:27:03', '2026-07-02 20:27:03.493', '2026-07-02 20:27:03.493', NULL, '7a661d8cc999f526e26cb1a14b7839c4', 2) ON CONFLICT(hash) DO NOTHING;
|
||||||
|
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FJ91RYFXBJH99HJ18QTHY2B0', 'description', NULL, 'REPORTED (2026-07-02, Jeroen): can''t trust that the model switch and the effort toggle actually took effect when used — the UI feedback + positioning leave it uncertain whether the change applied. INVESTIGATE: what confirmation (if any) fires today when the model or effort is changed, and where it surfaces relative to the control. Likely-related surfaces: the Config tab controls (T-414), /effort ownership (T-412), account/model settings control. IMPROVE: give an unmistakable, well-positioned confirmation that the change landed — e.g. the control reflects the new value immediately (selected state), and/or a brief toast/inline acknowledgement near the control, not somewhere the eye isn''t. Goal: after a switch, the user is certain which model/effort is now active.', NULL, '2026-07-02 20:31:02', '2026-07-02 20:31:02.807', '2026-07-02 20:31:02.807', NULL, '5030849d297f6312073802a0641a2594', 2) ON CONFLICT(hash) DO NOTHING;
|
||||||
|
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2G1WD1839Z90AQ5C0BHNV4', 'status', 'backlog', 'in_progress', NULL, '2026-07-02 20:35:12', '2026-07-02 20:35:12.739', '2026-07-02 20:35:12.739', NULL, 'd971e23e05c7547672b6989ca0a98434', 2) ON CONFLICT(hash) DO NOTHING;
|
||||||
|
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FJ91RYFXBJH99HJ18QTHY2B0', 'description', 'REPORTED (2026-07-02, Jeroen): can''t trust that the model switch and the effort toggle actually took effect when used — the UI feedback + positioning leave it uncertain whether the change applied. INVESTIGATE: what confirmation (if any) fires today when the model or effort is changed, and where it surfaces relative to the control. Likely-related surfaces: the Config tab controls (T-414), /effort ownership (T-412), account/model settings control. IMPROVE: give an unmistakable, well-positioned confirmation that the change landed — e.g. the control reflects the new value immediately (selected state), and/or a brief toast/inline acknowledgement near the control, not somewhere the eye isn''t. Goal: after a switch, the user is certain which model/effort is now active.', 'REPORTED (2026-07-02, Jeroen): can''t trust that the model switch and the effort toggle actually took effect when used — the UI feedback + positioning leave it uncertain whether the change applied. INVESTIGATE: what confirmation (if any) fires today when the model or effort is changed, and where it surfaces relative to the control. Likely-related surfaces: the Config tab controls (T-414), /effort ownership (T-412), account/model settings control. IMPROVE: give an unmistakable, well-positioned confirmation that the change landed — e.g. the control reflects the new value immediately (selected state), and/or a brief toast/inline acknowledgement near the control, not somewhere the eye isn''t. Goal: after a switch, the user is certain which model/effort is now active.
|
||||||
|
|
||||||
|
EVIDENCE + ROOT CAUSE (2026-07-02, from a /model screenshot). The confirmation renders as a raw, unstyled line: literally ''<local-command-stdout>Set model to claude-fable-5[1m] (claude-fable-5)</local-command-stdout>'', shown under the ''you'' (user) speaker stripe. Three distinct defects in that one line: (a) the CLI''s <local-command-stdout> wrapper tag is displayed verbatim instead of being unwrapped; (b) an ANSI SGR bold code leaks through as literal ''[1m]'' (a \x1b[1m) — slash-command stdout is not ANSI-stripped; (c) it is attributed to the USER speaker, so a system/command acknowledgement masquerades as something the user typed. ROOT CAUSE: clide has NO handling for local-command-stdout at all (grep in lib/ = zero hits) — the slash-command result falls through and is rendered as plain user prose. ENTRY POINTS for the fix: inbound message parse / role attribution in lib/builtin/claude/src/transcript_reader.dart; existing ANSI-strip refs in transcript_reader.dart + claude_composer.dart. IMPROVE: detect local-command-stdout content, unwrap the tag + strip ANSI, and render it as a distinct, clearly-positioned system/command-acknowledgement (NOT the user stripe) so a /model or /effort change is an unmistakable confirmation. Affects all slash-command stdout (model, effort, etc.), so fix at the render/parse path, not per-command.', NULL, '2026-07-02 20:39:06', '2026-07-02 20:39:06.684', '2026-07-02 20:39:06.684', NULL, '02ea6e2dbb60929aed687275f5329a4f', 2) ON CONFLICT(hash) DO NOTHING;
|
||||||
|
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FJ91RYFXBJH99HJ18QTHY2B0', 'description', 'REPORTED (2026-07-02, Jeroen): can''t trust that the model switch and the effort toggle actually took effect when used — the UI feedback + positioning leave it uncertain whether the change applied. INVESTIGATE: what confirmation (if any) fires today when the model or effort is changed, and where it surfaces relative to the control. Likely-related surfaces: the Config tab controls (T-414), /effort ownership (T-412), account/model settings control. IMPROVE: give an unmistakable, well-positioned confirmation that the change landed — e.g. the control reflects the new value immediately (selected state), and/or a brief toast/inline acknowledgement near the control, not somewhere the eye isn''t. Goal: after a switch, the user is certain which model/effort is now active.
|
||||||
|
|
||||||
|
EVIDENCE + ROOT CAUSE (2026-07-02, from a /model screenshot). The confirmation renders as a raw, unstyled line: literally ''<local-command-stdout>Set model to claude-fable-5[1m] (claude-fable-5)</local-command-stdout>'', shown under the ''you'' (user) speaker stripe. Three distinct defects in that one line: (a) the CLI''s <local-command-stdout> wrapper tag is displayed verbatim instead of being unwrapped; (b) an ANSI SGR bold code leaks through as literal ''[1m]'' (a \x1b[1m) — slash-command stdout is not ANSI-stripped; (c) it is attributed to the USER speaker, so a system/command acknowledgement masquerades as something the user typed. ROOT CAUSE: clide has NO handling for local-command-stdout at all (grep in lib/ = zero hits) — the slash-command result falls through and is rendered as plain user prose. ENTRY POINTS for the fix: inbound message parse / role attribution in lib/builtin/claude/src/transcript_reader.dart; existing ANSI-strip refs in transcript_reader.dart + claude_composer.dart. IMPROVE: detect local-command-stdout content, unwrap the tag + strip ANSI, and render it as a distinct, clearly-positioned system/command-acknowledgement (NOT the user stripe) so a /model or /effort change is an unmistakable confirmation. Affects all slash-command stdout (model, effort, etc.), so fix at the render/parse path, not per-command.', 'REPORTED (2026-07-02, Jeroen): can''t trust that the model switch and the effort toggle actually took effect when used — the UI feedback + positioning leave it uncertain whether the change applied. INVESTIGATE: what confirmation (if any) fires today when the model or effort is changed, and where it surfaces relative to the control. Likely-related surfaces: the Config tab controls (T-414), /effort ownership (T-412), account/model settings control. IMPROVE: give an unmistakable, well-positioned confirmation that the change landed — e.g. the control reflects the new value immediately (selected state), and/or a brief toast/inline acknowledgement near the control, not somewhere the eye isn''t. Goal: after a switch, the user is certain which model/effort is now active.
|
||||||
|
|
||||||
|
EVIDENCE + ROOT CAUSE (2026-07-02, from a /model screenshot). The confirmation renders as a raw, unstyled line: literally ''<local-command-stdout>Set model to claude-fable-5[1m] (claude-fable-5)</local-command-stdout>'', shown under the ''you'' (user) speaker stripe. Three distinct defects in that one line: (a) the CLI''s <local-command-stdout> wrapper tag is displayed verbatim instead of being unwrapped; (b) an ANSI SGR bold code leaks through as literal ''[1m]'' (a \x1b[1m) — slash-command stdout is not ANSI-stripped; (c) it is attributed to the USER speaker, so a system/command acknowledgement masquerades as something the user typed. ROOT CAUSE: clide has NO handling for local-command-stdout at all (grep in lib/ = zero hits) — the slash-command result falls through and is rendered as plain user prose. ENTRY POINTS for the fix: inbound message parse / role attribution in lib/builtin/claude/src/transcript_reader.dart; existing ANSI-strip refs in transcript_reader.dart + claude_composer.dart. IMPROVE: detect local-command-stdout content, unwrap the tag + strip ANSI, and render it as a distinct, clearly-positioned system/command-acknowledgement (NOT the user stripe) so a /model or /effort change is an unmistakable confirmation. Affects all slash-command stdout (model, effort, etc.), so fix at the render/parse path, not per-command.
|
||||||
|
|
||||||
|
SCOPE (do not narrow): the local-command-stdout rendering defect above is ONE symptom, not the whole ticket. The core problem is that after switching model or effort the user has no reliable, well-placed signal that it took effect — so this stays a broad investigate-and-improve of the switch/toggle trust UX, with the render bug as just the first concrete instance. Other symptoms/questions to investigate (non-exhaustive): does the control itself (Config tab picker / effort control / any menu) visibly update to the NEW active value after a switch, or does it look unchanged? is there ANY acknowledgement at the point of interaction, or only (mangled) output buried in the transcript far from where the user clicked? do model vs effort behave consistently, or differently? can clide''s shown ''active'' value drift from what actually took effect (e.g. a switch that silently no-ops)? is the confirmation positioned where the eye already is? The deliverable is: across all these controls, a consistent and unmistakable ''this is now active'' — fixing the render path is necessary but not sufficient. Enumerate the full symptom set during investigation before designing the fix.', NULL, '2026-07-02 20:41:13', '2026-07-02 20:41:13.402', '2026-07-02 20:41:13.402', NULL, '1c7d99c842cc857d5978d91e5b23ab8b', 2) ON CONFLICT(hash) DO NOTHING;
|
||||||
|
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2G1WD1839Z90AQ5C0BHNV4', 'description', 'Tier-5 canvas PANE, absorbed from the former T-7 into the unified canvas epic (T-317, decision D-91). A full workspace pane that renders .canvas files by CONVERTING them into the drawing-card JSON (per D-91: .canvas is an import format, not a native schema) and painting via the shared canvas renderer (T-318). Scope: nodes (note, text, group, image) + edges + layout state; pan/zoom; node selection, drag, resize; edit affordances (add note from file picker, add text node, draw edge between nodes); persist layout back to the .canvas file on disk. Uses MultitabPane (T-83) for tabs and its own slot per D-47; panels are extension-shaped (D-17). Depends on the core renderer (T-318). NOTE: unlike the conversation drawing card (display-only, D-78), this pane is interactive/editable — it is a pane, not a conversation widget.
|
||||||
|
|
||||||
|
SCOPE NOTE (2026-06-29): currently a 17-line stub. This is a from-scratch interactive Tier-5 pane (parse .canvas -> drawing-card JSON, CustomPaint render, pan/zoom, node select/drag/resize, edit affordances, persist .canvas) — a multi-session feature, NOT template-class work. The drawing-card TEMPLATE half of epic T-317 is now complete (svg/d2/image/icon/compare/graph + stdin).
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02): two foundation slices built + tested (from the 17-line stub). (1) JSONCanvas parser/model — lib/src/canvas/json_canvas.dart (2eb5d0f1): typed CanvasDoc (text/file/link/group nodes + edges with sides/ends/color/label), parse + toJson round-trip, skips unknown/malformed; pure Dart, 8 dart-test cases. (2) CustomPaint renderer — lib/builtin/canvas/src/canvas_painter.dart (035a37a1): CanvasBounds + pan/zoom CanvasViewport, group frames + edges (arrowheads) + node cards; node colours from the file (Obsidian presets/hex, NOT clide tokens per arbitrary-content rule), chrome themed; 7 tests (pixel-probe + viewport + colour). DECISION NOTE: the interactive pane paints the CanvasDoc model directly via CustomPaint (hit-testable, cheap re-paint) rather than re-lowering to SVG each frame — the ticket''s ''convert to drawing-card JSON'' path (D-91 SVG substrate) is for the display-only viewer; an editable pane needs direct model painting. Mirrors the graph pane. REMAINING (multi-session): interactive CanvasView (hit-test nodes + pan/zoom + click-select), pane shell (load .canvas from disk, workspace slot D-47, MultitabPane), CanvasExtension registration + open-.canvas routing, then edit affordances (add node/edge, drag, resize) + persist back to disk.', 'Tier-5 canvas PANE, absorbed from the former T-7 into the unified canvas epic (T-317, decision D-91). A full workspace pane that renders .canvas files by CONVERTING them into the drawing-card JSON (per D-91: .canvas is an import format, not a native schema) and painting via the shared canvas renderer (T-318). Scope: nodes (note, text, group, image) + edges + layout state; pan/zoom; node selection, drag, resize; edit affordances (add note from file picker, add text node, draw edge between nodes); persist layout back to the .canvas file on disk. Uses MultitabPane (T-83) for tabs and its own slot per D-47; panels are extension-shaped (D-17). Depends on the core renderer (T-318). NOTE: unlike the conversation drawing card (display-only, D-78), this pane is interactive/editable — it is a pane, not a conversation widget.
|
||||||
|
|
||||||
|
SCOPE NOTE (2026-06-29): currently a 17-line stub. This is a from-scratch interactive Tier-5 pane (parse .canvas -> drawing-card JSON, CustomPaint render, pan/zoom, node select/drag/resize, edit affordances, persist .canvas) — a multi-session feature, NOT template-class work. The drawing-card TEMPLATE half of epic T-317 is now complete (svg/d2/image/icon/compare/graph + stdin).
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02): two foundation slices built + tested (from the 17-line stub). (1) JSONCanvas parser/model — lib/src/canvas/json_canvas.dart (2eb5d0f1): typed CanvasDoc (text/file/link/group nodes + edges with sides/ends/color/label), parse + toJson round-trip, skips unknown/malformed; pure Dart, 8 dart-test cases. (2) CustomPaint renderer — lib/builtin/canvas/src/canvas_painter.dart (035a37a1): CanvasBounds + pan/zoom CanvasViewport, group frames + edges (arrowheads) + node cards; node colours from the file (Obsidian presets/hex, NOT clide tokens per arbitrary-content rule), chrome themed; 7 tests (pixel-probe + viewport + colour). DECISION NOTE: the interactive pane paints the CanvasDoc model directly via CustomPaint (hit-testable, cheap re-paint) rather than re-lowering to SVG each frame — the ticket''s ''convert to drawing-card JSON'' path (D-91 SVG substrate) is for the display-only viewer; an editable pane needs direct model painting. Mirrors the graph pane. REMAINING (multi-session): interactive CanvasView (hit-test nodes + pan/zoom + click-select), pane shell (load .canvas from disk, workspace slot D-47, MultitabPane), CanvasExtension registration + open-.canvas routing, then edit affordances (add node/edge, drag, resize) + persist back to disk.
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02, cont.): third foundation slice landed — interactive CanvasView (lib/builtin/canvas/src/canvas_view.dart, 7700fc7a): hitTestCanvasNode (topmost node under a point; cards beat the group frames behind, via the painter''s own viewport) + scroll-zoom + drag-pan + click-select with a focus ring; 6 tests. The canvas rendering + interaction FOUNDATION is now complete + tested (parser 2eb5d0f1, renderer 035a37a1, view 7700fc7a — 21 canvas tests), mirroring where T-323''s foundation was before its integration phase. NOT yet reachable. REACHABLE-INTEGRATION PHASE (next, fresh session): (a) pane shell — a StatefulWidget that loads a .canvas from disk (files.read/editor.open path), holds the CanvasDoc, embeds CanvasView; (b) CanvasExtension registration as a workspace pane (own slot D-47, MultitabPane T-83); (c) FILE-OPEN ROUTING — how opening a .canvas lands in this pane instead of the text editor: NOTE the TabContribution.fileGlobs field is DECLARED but has ZERO consumers in lib/, so this routing must be built (wire fileGlobs, or have the editor delegate by extension, or a command + workspace tab); (d) i18n + tests. THEN the edit phase: add node/text/edge affordances, node drag + resize, and persist the CanvasDoc back to the .canvas file (encode() already exists).', NULL, '2026-07-02 21:22:59', '2026-07-02 21:22:59.395', '2026-07-02 21:22:59.395', NULL, '6b17245b0d3d39a0d61bc90a2a0a034b', 2) ON CONFLICT(hash) DO NOTHING;
|
||||||
|
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2G1WD1839Z90AQ5C0BHNV4', 'description', 'Tier-5 canvas PANE, absorbed from the former T-7 into the unified canvas epic (T-317, decision D-91). A full workspace pane that renders .canvas files by CONVERTING them into the drawing-card JSON (per D-91: .canvas is an import format, not a native schema) and painting via the shared canvas renderer (T-318). Scope: nodes (note, text, group, image) + edges + layout state; pan/zoom; node selection, drag, resize; edit affordances (add note from file picker, add text node, draw edge between nodes); persist layout back to the .canvas file on disk. Uses MultitabPane (T-83) for tabs and its own slot per D-47; panels are extension-shaped (D-17). Depends on the core renderer (T-318). NOTE: unlike the conversation drawing card (display-only, D-78), this pane is interactive/editable — it is a pane, not a conversation widget.
|
||||||
|
|
||||||
|
SCOPE NOTE (2026-06-29): currently a 17-line stub. This is a from-scratch interactive Tier-5 pane (parse .canvas -> drawing-card JSON, CustomPaint render, pan/zoom, node select/drag/resize, edit affordances, persist .canvas) — a multi-session feature, NOT template-class work. The drawing-card TEMPLATE half of epic T-317 is now complete (svg/d2/image/icon/compare/graph + stdin).
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02): two foundation slices built + tested (from the 17-line stub). (1) JSONCanvas parser/model — lib/src/canvas/json_canvas.dart (2eb5d0f1): typed CanvasDoc (text/file/link/group nodes + edges with sides/ends/color/label), parse + toJson round-trip, skips unknown/malformed; pure Dart, 8 dart-test cases. (2) CustomPaint renderer — lib/builtin/canvas/src/canvas_painter.dart (035a37a1): CanvasBounds + pan/zoom CanvasViewport, group frames + edges (arrowheads) + node cards; node colours from the file (Obsidian presets/hex, NOT clide tokens per arbitrary-content rule), chrome themed; 7 tests (pixel-probe + viewport + colour). DECISION NOTE: the interactive pane paints the CanvasDoc model directly via CustomPaint (hit-testable, cheap re-paint) rather than re-lowering to SVG each frame — the ticket''s ''convert to drawing-card JSON'' path (D-91 SVG substrate) is for the display-only viewer; an editable pane needs direct model painting. Mirrors the graph pane. REMAINING (multi-session): interactive CanvasView (hit-test nodes + pan/zoom + click-select), pane shell (load .canvas from disk, workspace slot D-47, MultitabPane), CanvasExtension registration + open-.canvas routing, then edit affordances (add node/edge, drag, resize) + persist back to disk.
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02, cont.): third foundation slice landed — interactive CanvasView (lib/builtin/canvas/src/canvas_view.dart, 7700fc7a): hitTestCanvasNode (topmost node under a point; cards beat the group frames behind, via the painter''s own viewport) + scroll-zoom + drag-pan + click-select with a focus ring; 6 tests. The canvas rendering + interaction FOUNDATION is now complete + tested (parser 2eb5d0f1, renderer 035a37a1, view 7700fc7a — 21 canvas tests), mirroring where T-323''s foundation was before its integration phase. NOT yet reachable. REACHABLE-INTEGRATION PHASE (next, fresh session): (a) pane shell — a StatefulWidget that loads a .canvas from disk (files.read/editor.open path), holds the CanvasDoc, embeds CanvasView; (b) CanvasExtension registration as a workspace pane (own slot D-47, MultitabPane T-83); (c) FILE-OPEN ROUTING — how opening a .canvas lands in this pane instead of the text editor: NOTE the TabContribution.fileGlobs field is DECLARED but has ZERO consumers in lib/, so this routing must be built (wire fileGlobs, or have the editor delegate by extension, or a command + workspace tab); (d) i18n + tests. THEN the edit phase: add node/text/edge affordances, node drag + resize, and persist the CanvasDoc back to the .canvas file (encode() already exists).', 'Tier-5 canvas PANE, absorbed from the former T-7 into the unified canvas epic (T-317, decision D-91). A full workspace pane that renders .canvas files by CONVERTING them into the drawing-card JSON (per D-91: .canvas is an import format, not a native schema) and painting via the shared canvas renderer (T-318). Scope: nodes (note, text, group, image) + edges + layout state; pan/zoom; node selection, drag, resize; edit affordances (add note from file picker, add text node, draw edge between nodes); persist layout back to the .canvas file on disk. Uses MultitabPane (T-83) for tabs and its own slot per D-47; panels are extension-shaped (D-17). Depends on the core renderer (T-318). NOTE: unlike the conversation drawing card (display-only, D-78), this pane is interactive/editable — it is a pane, not a conversation widget.
|
||||||
|
|
||||||
|
SCOPE NOTE (2026-06-29): currently a 17-line stub. This is a from-scratch interactive Tier-5 pane (parse .canvas -> drawing-card JSON, CustomPaint render, pan/zoom, node select/drag/resize, edit affordances, persist .canvas) — a multi-session feature, NOT template-class work. The drawing-card TEMPLATE half of epic T-317 is now complete (svg/d2/image/icon/compare/graph + stdin).
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02): two foundation slices built + tested (from the 17-line stub). (1) JSONCanvas parser/model — lib/src/canvas/json_canvas.dart (2eb5d0f1): typed CanvasDoc (text/file/link/group nodes + edges with sides/ends/color/label), parse + toJson round-trip, skips unknown/malformed; pure Dart, 8 dart-test cases. (2) CustomPaint renderer — lib/builtin/canvas/src/canvas_painter.dart (035a37a1): CanvasBounds + pan/zoom CanvasViewport, group frames + edges (arrowheads) + node cards; node colours from the file (Obsidian presets/hex, NOT clide tokens per arbitrary-content rule), chrome themed; 7 tests (pixel-probe + viewport + colour). DECISION NOTE: the interactive pane paints the CanvasDoc model directly via CustomPaint (hit-testable, cheap re-paint) rather than re-lowering to SVG each frame — the ticket''s ''convert to drawing-card JSON'' path (D-91 SVG substrate) is for the display-only viewer; an editable pane needs direct model painting. Mirrors the graph pane. REMAINING (multi-session): interactive CanvasView (hit-test nodes + pan/zoom + click-select), pane shell (load .canvas from disk, workspace slot D-47, MultitabPane), CanvasExtension registration + open-.canvas routing, then edit affordances (add node/edge, drag, resize) + persist back to disk.
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02, cont.): third foundation slice landed — interactive CanvasView (lib/builtin/canvas/src/canvas_view.dart, 7700fc7a): hitTestCanvasNode (topmost node under a point; cards beat the group frames behind, via the painter''s own viewport) + scroll-zoom + drag-pan + click-select with a focus ring; 6 tests. The canvas rendering + interaction FOUNDATION is now complete + tested (parser 2eb5d0f1, renderer 035a37a1, view 7700fc7a — 21 canvas tests), mirroring where T-323''s foundation was before its integration phase. NOT yet reachable. REACHABLE-INTEGRATION PHASE (next, fresh session): (a) pane shell — a StatefulWidget that loads a .canvas from disk (files.read/editor.open path), holds the CanvasDoc, embeds CanvasView; (b) CanvasExtension registration as a workspace pane (own slot D-47, MultitabPane T-83); (c) FILE-OPEN ROUTING — how opening a .canvas lands in this pane instead of the text editor: NOTE the TabContribution.fileGlobs field is DECLARED but has ZERO consumers in lib/, so this routing must be built (wire fileGlobs, or have the editor delegate by extension, or a command + workspace tab); (d) i18n + tests. THEN the edit phase: add node/text/edge affordances, node drag + resize, and persist the CanvasDoc back to the .canvas file (encode() already exists).
|
||||||
|
|
||||||
|
Refinement (2026-07-03, user-confirmed): (1) SLOT: Slots.workspace — diff/editor recipe, center column; coexists with Claude the way diff does (D-47). (2) TABS: real MultitabPane<CanvasDoc> — N .canvas files open as tabs (user explicitly chose over the single-TabContribution graph/diff precedent; needs MultitabController plumbing like Claude sessions). (3) FILE-OPEN ROUTING resolved by inspection: TabContribution.fileGlobs is dead (zero consumers) — do NOT wire it. Add a .canvas branch in lib/kernel/src/file_open.dart openWorkspaceFile() publishing to ''builtin.canvas''/''selection'' (mirror of the .md branch), and D-6 CLI parity via a ''canvas'' entry in the _readers map at lib/src/daemon/ui_command.dart:34 → clide ui open canvas <path> (diff precedent). (4) Fix stale doc header lib/src/canvas/json_canvas.dart:5-7 (claims SVG-lowering; actual architecture paints CanvasDoc directly per the ticket''s DECISION NOTE) in the same pass. (5) Edit phase later needs a mutation path (CanvasView has no onChanged; CanvasDoc is immutable-construction only) — deferred, flagged now.', NULL, '2026-07-03 20:20:00', '2026-07-03 20:20:00.827', '2026-07-03 20:20:00.827', NULL, '541312e6b1f559f60934ad1a1b784d76', 2) ON CONFLICT(hash) DO NOTHING;
|
||||||
|
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2G1WD1839Z90AQ5C0BHNV4', 'description', 'Tier-5 canvas PANE, absorbed from the former T-7 into the unified canvas epic (T-317, decision D-91). A full workspace pane that renders .canvas files by CONVERTING them into the drawing-card JSON (per D-91: .canvas is an import format, not a native schema) and painting via the shared canvas renderer (T-318). Scope: nodes (note, text, group, image) + edges + layout state; pan/zoom; node selection, drag, resize; edit affordances (add note from file picker, add text node, draw edge between nodes); persist layout back to the .canvas file on disk. Uses MultitabPane (T-83) for tabs and its own slot per D-47; panels are extension-shaped (D-17). Depends on the core renderer (T-318). NOTE: unlike the conversation drawing card (display-only, D-78), this pane is interactive/editable — it is a pane, not a conversation widget.
|
||||||
|
|
||||||
|
SCOPE NOTE (2026-06-29): currently a 17-line stub. This is a from-scratch interactive Tier-5 pane (parse .canvas -> drawing-card JSON, CustomPaint render, pan/zoom, node select/drag/resize, edit affordances, persist .canvas) — a multi-session feature, NOT template-class work. The drawing-card TEMPLATE half of epic T-317 is now complete (svg/d2/image/icon/compare/graph + stdin).
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02): two foundation slices built + tested (from the 17-line stub). (1) JSONCanvas parser/model — lib/src/canvas/json_canvas.dart (2eb5d0f1): typed CanvasDoc (text/file/link/group nodes + edges with sides/ends/color/label), parse + toJson round-trip, skips unknown/malformed; pure Dart, 8 dart-test cases. (2) CustomPaint renderer — lib/builtin/canvas/src/canvas_painter.dart (035a37a1): CanvasBounds + pan/zoom CanvasViewport, group frames + edges (arrowheads) + node cards; node colours from the file (Obsidian presets/hex, NOT clide tokens per arbitrary-content rule), chrome themed; 7 tests (pixel-probe + viewport + colour). DECISION NOTE: the interactive pane paints the CanvasDoc model directly via CustomPaint (hit-testable, cheap re-paint) rather than re-lowering to SVG each frame — the ticket''s ''convert to drawing-card JSON'' path (D-91 SVG substrate) is for the display-only viewer; an editable pane needs direct model painting. Mirrors the graph pane. REMAINING (multi-session): interactive CanvasView (hit-test nodes + pan/zoom + click-select), pane shell (load .canvas from disk, workspace slot D-47, MultitabPane), CanvasExtension registration + open-.canvas routing, then edit affordances (add node/edge, drag, resize) + persist back to disk.
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02, cont.): third foundation slice landed — interactive CanvasView (lib/builtin/canvas/src/canvas_view.dart, 7700fc7a): hitTestCanvasNode (topmost node under a point; cards beat the group frames behind, via the painter''s own viewport) + scroll-zoom + drag-pan + click-select with a focus ring; 6 tests. The canvas rendering + interaction FOUNDATION is now complete + tested (parser 2eb5d0f1, renderer 035a37a1, view 7700fc7a — 21 canvas tests), mirroring where T-323''s foundation was before its integration phase. NOT yet reachable. REACHABLE-INTEGRATION PHASE (next, fresh session): (a) pane shell — a StatefulWidget that loads a .canvas from disk (files.read/editor.open path), holds the CanvasDoc, embeds CanvasView; (b) CanvasExtension registration as a workspace pane (own slot D-47, MultitabPane T-83); (c) FILE-OPEN ROUTING — how opening a .canvas lands in this pane instead of the text editor: NOTE the TabContribution.fileGlobs field is DECLARED but has ZERO consumers in lib/, so this routing must be built (wire fileGlobs, or have the editor delegate by extension, or a command + workspace tab); (d) i18n + tests. THEN the edit phase: add node/text/edge affordances, node drag + resize, and persist the CanvasDoc back to the .canvas file (encode() already exists).
|
||||||
|
|
||||||
|
Refinement (2026-07-03, user-confirmed): (1) SLOT: Slots.workspace — diff/editor recipe, center column; coexists with Claude the way diff does (D-47). (2) TABS: real MultitabPane<CanvasDoc> — N .canvas files open as tabs (user explicitly chose over the single-TabContribution graph/diff precedent; needs MultitabController plumbing like Claude sessions). (3) FILE-OPEN ROUTING resolved by inspection: TabContribution.fileGlobs is dead (zero consumers) — do NOT wire it. Add a .canvas branch in lib/kernel/src/file_open.dart openWorkspaceFile() publishing to ''builtin.canvas''/''selection'' (mirror of the .md branch), and D-6 CLI parity via a ''canvas'' entry in the _readers map at lib/src/daemon/ui_command.dart:34 → clide ui open canvas <path> (diff precedent). (4) Fix stale doc header lib/src/canvas/json_canvas.dart:5-7 (claims SVG-lowering; actual architecture paints CanvasDoc directly per the ticket''s DECISION NOTE) in the same pass. (5) Edit phase later needs a mutation path (CanvasView has no onChanged; CanvasDoc is immutable-construction only) — deferred, flagged now.', 'Tier-5 canvas PANE, absorbed from the former T-7 into the unified canvas epic (T-317, decision D-91). A full workspace pane that renders .canvas files by CONVERTING them into the drawing-card JSON (per D-91: .canvas is an import format, not a native schema) and painting via the shared canvas renderer (T-318). Scope: nodes (note, text, group, image) + edges + layout state; pan/zoom; node selection, drag, resize; edit affordances (add note from file picker, add text node, draw edge between nodes); persist layout back to the .canvas file on disk. Uses MultitabPane (T-83) for tabs and its own slot per D-47; panels are extension-shaped (D-17). Depends on the core renderer (T-318). NOTE: unlike the conversation drawing card (display-only, D-78), this pane is interactive/editable — it is a pane, not a conversation widget.
|
||||||
|
|
||||||
|
SCOPE NOTE (2026-06-29): currently a 17-line stub. This is a from-scratch interactive Tier-5 pane (parse .canvas -> drawing-card JSON, CustomPaint render, pan/zoom, node select/drag/resize, edit affordances, persist .canvas) — a multi-session feature, NOT template-class work. The drawing-card TEMPLATE half of epic T-317 is now complete (svg/d2/image/icon/compare/graph + stdin).
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02): two foundation slices built + tested (from the 17-line stub). (1) JSONCanvas parser/model — lib/src/canvas/json_canvas.dart (2eb5d0f1): typed CanvasDoc (text/file/link/group nodes + edges with sides/ends/color/label), parse + toJson round-trip, skips unknown/malformed; pure Dart, 8 dart-test cases. (2) CustomPaint renderer — lib/builtin/canvas/src/canvas_painter.dart (035a37a1): CanvasBounds + pan/zoom CanvasViewport, group frames + edges (arrowheads) + node cards; node colours from the file (Obsidian presets/hex, NOT clide tokens per arbitrary-content rule), chrome themed; 7 tests (pixel-probe + viewport + colour). DECISION NOTE: the interactive pane paints the CanvasDoc model directly via CustomPaint (hit-testable, cheap re-paint) rather than re-lowering to SVG each frame — the ticket''s ''convert to drawing-card JSON'' path (D-91 SVG substrate) is for the display-only viewer; an editable pane needs direct model painting. Mirrors the graph pane. REMAINING (multi-session): interactive CanvasView (hit-test nodes + pan/zoom + click-select), pane shell (load .canvas from disk, workspace slot D-47, MultitabPane), CanvasExtension registration + open-.canvas routing, then edit affordances (add node/edge, drag, resize) + persist back to disk.
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02, cont.): third foundation slice landed — interactive CanvasView (lib/builtin/canvas/src/canvas_view.dart, 7700fc7a): hitTestCanvasNode (topmost node under a point; cards beat the group frames behind, via the painter''s own viewport) + scroll-zoom + drag-pan + click-select with a focus ring; 6 tests. The canvas rendering + interaction FOUNDATION is now complete + tested (parser 2eb5d0f1, renderer 035a37a1, view 7700fc7a — 21 canvas tests), mirroring where T-323''s foundation was before its integration phase. NOT yet reachable. REACHABLE-INTEGRATION PHASE (next, fresh session): (a) pane shell — a StatefulWidget that loads a .canvas from disk (files.read/editor.open path), holds the CanvasDoc, embeds CanvasView; (b) CanvasExtension registration as a workspace pane (own slot D-47, MultitabPane T-83); (c) FILE-OPEN ROUTING — how opening a .canvas lands in this pane instead of the text editor: NOTE the TabContribution.fileGlobs field is DECLARED but has ZERO consumers in lib/, so this routing must be built (wire fileGlobs, or have the editor delegate by extension, or a command + workspace tab); (d) i18n + tests. THEN the edit phase: add node/text/edge affordances, node drag + resize, and persist the CanvasDoc back to the .canvas file (encode() already exists).
|
||||||
|
|
||||||
|
Refinement (2026-07-03, user-confirmed): (1) SLOT: Slots.workspace — diff/editor recipe, center column; coexists with Claude the way diff does (D-47). (2) TABS: real MultitabPane<CanvasDoc> — N .canvas files open as tabs (user explicitly chose over the single-TabContribution graph/diff precedent; needs MultitabController plumbing like Claude sessions). (3) FILE-OPEN ROUTING resolved by inspection: TabContribution.fileGlobs is dead (zero consumers) — do NOT wire it. Add a .canvas branch in lib/kernel/src/file_open.dart openWorkspaceFile() publishing to ''builtin.canvas''/''selection'' (mirror of the .md branch), and D-6 CLI parity via a ''canvas'' entry in the _readers map at lib/src/daemon/ui_command.dart:34 → clide ui open canvas <path> (diff precedent). (4) Fix stale doc header lib/src/canvas/json_canvas.dart:5-7 (claims SVG-lowering; actual architecture paints CanvasDoc directly per the ticket''s DECISION NOTE) in the same pass. (5) Edit phase later needs a mutation path (CanvasView has no onChanged; CanvasDoc is immutable-construction only) — deferred, flagged now.
|
||||||
|
|
||||||
|
PROGRESS (2026-07-05): REACHABLE-INTEGRATION PHASE COMPLETE (e2e305de). CanvasExtension is a real workspace pane: app-scoped MultitabController on the extension (diff/T-233 pattern) with real per-document sub-tabs (MultitabPane keepAlive, per refinement decision), CanvasPaneHost + CanvasDocumentTab (files.read -> CanvasDoc.parse -> CanvasView; loading/error states), routing wired (openWorkspaceFile .canvas branch; ui.open ''canvas'' reader so clide ui open canvas <path> works; fileGlobs left dead as decided), en_us+nl_nl catalogs, json_canvas doc header corrected. Tests: extension lifecycle (7), pane-host widget (6), file_open routing (5, new file), ui_command canvas case; testmode extension roster now includes builtin.canvas (26/26 real-boot pass). REMAINING (edit phase, fresh session): node drag + resize, add note/text/edge affordances, persist CanvasDoc back to disk — encode() exists; CanvasView needs an onChanged/mutation path (refinement note item 5).', NULL, '2026-07-05 07:29:15', '2026-07-05 07:29:15.452', '2026-07-05 07:29:15.452', NULL, '0d0ff6c05b550d4a85296eb38adc830f', 2) ON CONFLICT(hash) DO NOTHING;
|
||||||
|
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FK3CDZQD2JM95ZQY5MH53PWC', 'status', 'backlog', 'in_progress', NULL, '2026-07-05 09:52:54', '2026-07-05 09:52:54.013', '2026-07-05 09:52:54.013', NULL, '59efe4bd0a098bfea3f146af21b0caf3', 2) ON CONFLICT(hash) DO NOTHING;
|
||||||
|
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FK3CDZQD2JM95ZQY5MH53PWC', 'status', 'in_progress', 'done', NULL, '2026-07-05 10:54:23', '2026-07-05 10:54:23.532', '2026-07-05 10:54:23.532', NULL, '941d08bde0cc4479860e015aded3d664', 2) ON CONFLICT(hash) DO NOTHING;
|
||||||
|
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FNR3DP0D48AZZ3NRA8JF3Q10', 'status', 'backlog', 'in_progress', NULL, '2026-07-13 15:17:17', '2026-07-13 15:17:17.537', '2026-07-13 15:17:17.537', NULL, 'fb951233b5fc242889cae1156dc1d0d8', 2) ON CONFLICT(hash) DO NOTHING;
|
||||||
|
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FNR3DP0D48AZZ3NRA8JF3Q10', 'description', NULL, 'Implements D-106 (FR-1 + worktree addendum). Storage: user-scope key app.env.pathPrepend.<fnv1a64Hex(canonicalWorkspaceKey(presetRoot))> in ~/.config/clide/settings.yaml — never committed; presetRootFor() resolves a linked-worktree workspace (gitdir: pointer file, e.g. .worktrees/<name>) to the main repo root so all worktrees share the repo''s preset.
|
||||||
|
|
||||||
|
Injection (prepend, dedup, next-spawn semantics): PTY panes via PaneRegistry.pathForSpawn hook (main.dart wires the preset-aware closure); hosted Claude via agentEnvDelta(prependDirs:) — now exports PATH whenever a preset exists even if clide is already on PATH (previous gap) — threaded orchestrator.pathPresetFor ← claude extension ← ctx.settings. Toolchain/supporter-binary resolution deliberately preset-blind (T-98/D-92 fence).
|
||||||
|
|
||||||
|
CLI (D-6): one cmd id env.path → clide env path list|set|add|remove|clear|capture; Flutter-free handler lib/src/daemon/env_path_commands.dart over an injected PathPresetStore port (adapter in main.dart); mutations publish on envPathChannel; capture diffs loginShellPathOrNull() (new shell_env getter) vs process PATH. UI: Settings → Tools → Workspace PATH section, custom control (ordered list, add/remove/reorder, missing-dir warning, worktree note, capture suggestions) in builtin.tools-settings; en+nl catalogs.
|
||||||
|
|
||||||
|
.worktrees/ added to IgnoreSet.builtin() and the project-init gitignore scaffold. Tests: path_preset_test (pure fns + real worktree layout), env_path_commands_test (all verbs), agent_bootstrap prependDirs cases, PaneRegistry pathForSpawn PTY test, widget tests for the control incl. worktree key sharing + capture. make test (4048) + make test-a11y green.', NULL, '2026-07-13 15:39:31', '2026-07-13 15:39:31.309', '2026-07-13 15:39:31.309', NULL, '44007d87d28b52050716cd913009d341', 2) ON CONFLICT(hash) DO NOTHING;
|
||||||
|
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FNR3DP0D48AZZ3NRA8JF3Q10', 'status', 'in_progress', 'done', NULL, '2026-07-13 16:48:56', '2026-07-13 16:48:56.833', '2026-07-13 16:48:56.833', NULL, 'd6c02324e60b8d412840b1ffd600a13f', 2) ON CONFLICT(hash) DO NOTHING;
|
||||||
|
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FNTF7KE5Y497PQC7SCFGR1KC', 'status', 'backlog', 'done', NULL, '2026-07-13 20:49:17', '2026-07-13 20:49:17.282', '2026-07-13 20:49:17.282', NULL, 'd2d3b437c1063f835e5b34c0cd996f9d', 2) ON CONFLICT(hash) DO NOTHING;
|
||||||
@@ -0,0 +1,364 @@
|
|||||||
|
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FD0ABC7QNEC3XCTV73YPSGR4', 'description', 'User report 2026-06-16: Claude Code''s **remote-control** feature (start / monitor / steer a running Claude Code session remotely — e.g. from claude.ai or the mobile app) is **not plumbed into clide**.
|
||||||
|
|
||||||
|
clide hosts the `claude` CLI as a stream-json child (`--session-id` / `--resume`, D-77). For remote control to work through clide, a clide-hosted session needs to be discoverable + steerable by the remote-control surface the same way a terminal-launched `claude` is.
|
||||||
|
|
||||||
|
**Step 1 — characterize (don''t assume the mechanism):** determine exactly what Claude Code exposes for remote control on the running CLI version. Likely touch points:
|
||||||
|
- the `~/.claude/sessions/<pid>.json` live-session registry we characterized in T-437 (PID-keyed: sessionId, cwd, version, kind, entrypoint, status) — is this what the remote-control surface enumerates? clide-spawned sessions DO write an entry (we saw `entrypoint: sdk-cli`). Confirm whether clide''s entry is visible/controllable remotely, or whether `entrypoint: sdk-cli` / headless spawn excludes it.
|
||||||
|
- any flag / capability in the `initialize` stream-json probe (T-411/T-151 cache) advertising remote control.
|
||||||
|
- whether enrollment requires the interactive TUI (and so is suppressed under clide''s stream-json spawn).
|
||||||
|
|
||||||
|
**Step 2 — plumb:** wire clide so a clide-hosted session participates in remote control (register correctly / pass the needed flag), and surface its state in the UI (e.g. an indicator that the session is remote-controllable / being driven remotely). If it conflicts with clide''s session ownership (pane pins a session-id, T-156), document the boundary.
|
||||||
|
|
||||||
|
**Open question:** is the goal (a) clide sessions become remotely controllable from claude.ai/mobile, or (b) clide can act as a remote controller of other sessions? Default read is (a). Confirm with the user before building.
|
||||||
|
|
||||||
|
Related: D-77 (stream-json session model), T-437 (sessions registry characterization), T-156 (clide owns session lifecycle), T-411 (capability probe).', 'User report 2026-06-16: Claude Code''s **remote-control** feature (start / monitor / steer a running Claude Code session remotely — e.g. from claude.ai or the mobile app) is **not plumbed into clide**.
|
||||||
|
|
||||||
|
clide hosts the `claude` CLI as a stream-json child (`--session-id` / `--resume`, D-77). For remote control to work through clide, a clide-hosted session needs to be discoverable + steerable by the remote-control surface the same way a terminal-launched `claude` is.
|
||||||
|
|
||||||
|
**Step 1 — characterize (don''t assume the mechanism):** determine exactly what Claude Code exposes for remote control on the running CLI version. Likely touch points:
|
||||||
|
- the `~/.claude/sessions/<pid>.json` live-session registry we characterized in T-437 (PID-keyed: sessionId, cwd, version, kind, entrypoint, status) — is this what the remote-control surface enumerates? clide-spawned sessions DO write an entry (we saw `entrypoint: sdk-cli`). Confirm whether clide''s entry is visible/controllable remotely, or whether `entrypoint: sdk-cli` / headless spawn excludes it.
|
||||||
|
- any flag / capability in the `initialize` stream-json probe (T-411/T-151 cache) advertising remote control.
|
||||||
|
- whether enrollment requires the interactive TUI (and so is suppressed under clide''s stream-json spawn).
|
||||||
|
|
||||||
|
**Step 2 — plumb:** wire clide so a clide-hosted session participates in remote control (register correctly / pass the needed flag), and surface its state in the UI (e.g. an indicator that the session is remote-controllable / being driven remotely). If it conflicts with clide''s session ownership (pane pins a session-id, T-156), document the boundary.
|
||||||
|
|
||||||
|
**Open question:** is the goal (a) clide sessions become remotely controllable from claude.ai/mobile, or (b) clide can act as a remote controller of other sessions? Default read is (a). Confirm with the user before building.
|
||||||
|
|
||||||
|
Related: D-77 (stream-json session model), T-437 (sessions registry characterization), T-156 (clide owns session lifecycle), T-411 (capability probe).
|
||||||
|
|
||||||
|
## Step 1 COMPLETE — mechanism characterized and empirically proven (2026-08-07)
|
||||||
|
|
||||||
|
**Goal confirmed as (a):** clide-hosted sessions become remotely controllable from
|
||||||
|
claude.ai / the mobile app. (b) is not in scope.
|
||||||
|
|
||||||
|
### The mechanism is a control_request, not the sessions registry
|
||||||
|
|
||||||
|
The Step-1 hypothesis (that `~/.claude/sessions/<pid>.json` is what the remote
|
||||||
|
surface enumerates) is **wrong**. That registry is incidental. Remote Control is
|
||||||
|
enabled per-session over the stream-json control channel clide already owns.
|
||||||
|
|
||||||
|
Claude Code 2.1.220 ships two bridge integrations:
|
||||||
|
- `[bridge:repl]` — the interactive TUI path (`--remote-control` flag, `/remote-control`)
|
||||||
|
- `[bridge:sdk]` — a **stream-json/SDK path**, which is the one clide needs
|
||||||
|
|
||||||
|
No interactive session, no extra flag, and no CLI changes are required.
|
||||||
|
|
||||||
|
### Wire contract (verified live)
|
||||||
|
|
||||||
|
```
|
||||||
|
→ {"type":"control_request","request_id":"…",
|
||||||
|
"request":{"subtype":"remote_control","enabled":true,"name":"<session name>"}}
|
||||||
|
|
||||||
|
← {"type":"system","subtype":"bridge_state","state":"ready"}
|
||||||
|
← {"type":"control_response","response":{"subtype":"success","response":{
|
||||||
|
"session_url":"https://claude.ai/code/session_0127…",
|
||||||
|
"connect_url":"https://claude.ai/code?environment=",
|
||||||
|
"environment_id":""}}}
|
||||||
|
← {"type":"system","subtype":"bridge_state","state":"connected"}
|
||||||
|
|
||||||
|
→ {"request":{"subtype":"remote_control","enabled":false}} # clean teardown
|
||||||
|
← {"type":"control_response","response":{"subtype":"success"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Proven by probe against clide''s exact spawn flags (`stream_json_session.dart:78`).
|
||||||
|
`ready → connected` in ~420ms. Debug log confirms `[bridge:sdk] State change: ready`
|
||||||
|
then `connected`; transport is CCR v2 over SSE, shared with the repl bridge.
|
||||||
|
|
||||||
|
**Surface `session_url`, not `connect_url`.** `connect_url` came back as
|
||||||
|
`https://claude.ai/code?environment=` with an empty `environment_id` — the
|
||||||
|
environment concept is not populated on the bare-SDK path (it appears to be filled
|
||||||
|
in only when the `claude remote-control` daemon owns a registered directory).
|
||||||
|
`session_url` is the complete, live link. Confirm before building a QR affordance.
|
||||||
|
|
||||||
|
### CLI-side callback surface (from binary analysis)
|
||||||
|
|
||||||
|
| Callback | Effect |
|
||||||
|
|---|---|
|
||||||
|
| `onInboundMessage` | remote message injected as a user turn (tagged `bridgeOrigin`, `clientPlatform`, `origin`) |
|
||||||
|
| `onPermissionResponse` | → `injectControlResponse` — the remote can answer permission prompts |
|
||||||
|
| `onInterrupt` | remote cancel of the running turn |
|
||||||
|
| `onSetModel` / `onSetPermissionMode` / `onSetMaxThinkingTokens` | remote session control |
|
||||||
|
| `onStateChange` | emits `system/bridge_state` (`ready`\|`connected`\|`failed` + `detail`) on the normal output stream |
|
||||||
|
|
||||||
|
Plus outbound `writeSdkMessages` forwarding of task/thinking/vcs events.
|
||||||
|
|
||||||
|
### Prompt arbitration — resolved, no clide policy to invent
|
||||||
|
|
||||||
|
Decided model (user, 2026-08-07): **first-to-apply wins, both sides linked by the
|
||||||
|
same `request_id`, loser''s prompt retracts on that link, clear is idempotent.**
|
||||||
|
|
||||||
|
This is already the shipped protocol, and it is symmetric:
|
||||||
|
- `setOnControlRequestSent` forwards the pending request to the remote;
|
||||||
|
`setOnControlRequestResolved` → `sendControlCancelRequest(request_id)` retracts it.
|
||||||
|
- `RemoteSessionManager.handleMessage` handles inbound `control_cancel_request` by
|
||||||
|
looking up `pendingPermissionRequests` / `pendingDialogRequests` and retracting;
|
||||||
|
unknown ids are ignored ("nothing pending, ignoring").
|
||||||
|
- The refusal schema states the rule directly: *"Evict on RESOLUTION (your own
|
||||||
|
response — any choice — or `control_cancel_request` retirement), never on receipt
|
||||||
|
… Eviction is idempotent."*
|
||||||
|
|
||||||
|
**The clide gap:** `stream_json_session.dart` parses `control_request` but has **no
|
||||||
|
`control_cancel_request` handling at all**. If the remote answers first, clide''s
|
||||||
|
prompt widget hangs with no retraction. Since pending prompts are already keyed by
|
||||||
|
`request_id` for `resolvePrompt()` (`:758`), the fix is a delete + UI clear on the
|
||||||
|
same key. NOT YET OBSERVED live — the probe ran no tools, so the retraction path is
|
||||||
|
confirmed by decompile only. Verify during implementation.
|
||||||
|
|
||||||
|
### Step 2 scope (remaining)
|
||||||
|
|
||||||
|
1. `enableRemoteControl({String? name})` / `disableRemoteControl()` on
|
||||||
|
`StreamJsonSession` — shaped exactly like `setModel()` (`:932`): request with
|
||||||
|
`request_id`, pending map, reconcile response into `SessionStatus`.
|
||||||
|
2. Handle `system/bridge_state` in the event switch → connection state.
|
||||||
|
3. **Handle inbound `control_cancel_request` → retract the matching pending
|
||||||
|
`ToolPrompt`.** (The arbitration work above; also correct on its own merits.)
|
||||||
|
4. Two `SessionStatus` fields (`session_url`, bridge state).
|
||||||
|
5. Cockpit affordance: connect link / QR + connected indicator.
|
||||||
|
6. `clide claude remote-control <on|off>` verb for D-6 parity.
|
||||||
|
7. Teardown on pane close; pass clide''s derived pane name as `name` (the CLI
|
||||||
|
already names clide sessions e.g. `clide-18`).
|
||||||
|
|
||||||
|
### Constraints found
|
||||||
|
|
||||||
|
- Requires a logged-in subscription account; bridge is skipped on non-first-party
|
||||||
|
providers (`isFirstPartyProvider` check) — needs a disabled UI state.
|
||||||
|
- Help text for the daemon path notes the workspace trust dialog must have been
|
||||||
|
accepted by running `claude` interactively in the directory once. clide spawns
|
||||||
|
non-interactively where trust is auto-skipped — verify this doesn''t block the bridge.
|
||||||
|
- `remoteControlAtStartup` is a user setting ("Start Remote Control bridge
|
||||||
|
automatically each session") — a zero-code way to A/B the behaviour, and a
|
||||||
|
setting clide should probably respect rather than fight.
|
||||||
|
- Related but out of scope: `isolatePeerMachines` (cross-machine `SendMessage`
|
||||||
|
between peer sessions); `claude remote-control` hidden subcommand (`bridgeMain`)
|
||||||
|
which runs a per-directory daemon with `--spawn same-dir|worktree|session`.', NULL, '2026-08-07 12:21:08', '2026-08-07 12:21:08.809', '2026-08-07 12:21:08.809', NULL, '3908441f5df127b533670e4b4e35b283', 2) ON CONFLICT(hash) DO NOTHING;
|
||||||
|
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGYS06SDJGZ4W3Z9V9HDEATW', 'description', 'The pre-commit hook re-exports + stages .pql/changelog on commit but only catches the tickets + ticket_history tables — it leaves ticket_deps (blocker edges) and ticket_idmap (new T-NNN <-> record_id mappings) UNSTAGED. Seen repeatedly this session (D-103 re-sequencing blockers; T-495 id mapping), each needing a manual follow-up commit; otherwise the planning state silently doesn''t persist and a later branch switch drops it — exactly the failure the hook exists to prevent. Fix: stage ALL of .pql/changelog/ (git add .pql/changelog/), not just the tables the export rewrote. Repro: pql ticket block X --by Y + create a ticket, commit unrelated files, observe ticket_deps/ticket_idmap still modified afterward.', 'The pre-commit hook re-exports + stages .pql/changelog on commit but only catches the tickets + ticket_history tables — it leaves ticket_deps (blocker edges) and ticket_idmap (new T-NNN <-> record_id mappings) UNSTAGED. Seen repeatedly this session (D-103 re-sequencing blockers; T-495 id mapping), each needing a manual follow-up commit; otherwise the planning state silently doesn''t persist and a later branch switch drops it — exactly the failure the hook exists to prevent. Fix: stage ALL of .pql/changelog/ (git add .pql/changelog/), not just the tables the export rewrote. Repro: pql ticket block X --by Y + create a ticket, commit unrelated files, observe ticket_deps/ticket_idmap still modified afterward.
|
||||||
|
|
||||||
|
## Widened 2026-08-07 — broader than the title, and the root cause is different
|
||||||
|
|
||||||
|
### The scope is wrong: tickets + ticket_history are NOT immune
|
||||||
|
|
||||||
|
This ticket states the hook "only catches the tickets + ticket_history tables."
|
||||||
|
That is not the failure mode. On 2026-08-07 a ticket-only turn (appending Step-1
|
||||||
|
findings to T-454) left **`tickets/2026-08.sql` and `ticket_history/2026-08.sql`
|
||||||
|
untracked and unstaged** — the two tables assumed to work. The commit aborted
|
||||||
|
with "nothing added to commit but untracked files present" and needed an explicit
|
||||||
|
`git add` of both paths.
|
||||||
|
|
||||||
|
So no table is reliably staged. Retitle accordingly.
|
||||||
|
|
||||||
|
### Likely root cause: staging is gated on rows appended, not on file dirtiness
|
||||||
|
|
||||||
|
The pre-commit hook is a one-liner that delegates everything to pql:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# .pql/hooks/pre-commit
|
||||||
|
''/…/pql'' plan export --stage 2>/dev/null || true
|
||||||
|
```
|
||||||
|
|
||||||
|
Its output on the failing commit:
|
||||||
|
|
||||||
|
```
|
||||||
|
{"files_written":["…/ticket_history/2026-08.sql","…/tickets/2026-08.sql"],"rows_written":0}
|
||||||
|
```
|
||||||
|
|
||||||
|
It **wrote both files and staged neither**. Second invocation (after a manual
|
||||||
|
`git add`) returned `{"files_written":null,"rows_written":0}`.
|
||||||
|
|
||||||
|
Hypothesis: `--stage` only issues the `git add` when it appends rows
|
||||||
|
(`rows_written > 0`). Because ticket mutations already **write through** to
|
||||||
|
`.pql/changelog/` synchronously, by the time the pre-commit hook runs there is
|
||||||
|
nothing left to append — `rows_written` is 0 — so the staging step is skipped even
|
||||||
|
though the file on disk is new/dirty. NOT YET VERIFIED; confirm against pql''s
|
||||||
|
`plan export --stage` implementation.
|
||||||
|
|
||||||
|
This also better explains the originally-reported symptom: `ticket_deps` /
|
||||||
|
`ticket_idmap` aren''t special-cased out, they just tend to be *new month files*
|
||||||
|
or already-written-through, hitting the same skip.
|
||||||
|
|
||||||
|
Contributing factor: new-month rollover. These were the first August files, so
|
||||||
|
they were untracked rather than modified — worth checking whether `--stage`
|
||||||
|
handles untracked paths differently from tracked-but-modified ones.
|
||||||
|
|
||||||
|
### The fix belongs in pql, not clide
|
||||||
|
|
||||||
|
clide''s hook has no logic to fix — it is a single delegating line installed by
|
||||||
|
`pql init`. The change is in pql''s `plan export --stage`: stage every file under
|
||||||
|
`.pql/changelog/` that is dirty or untracked, regardless of `rows_written`.
|
||||||
|
Track/land it in the pql repo; this ticket is the clide-side symptom record.
|
||||||
|
|
||||||
|
The ticket''s proposed workaround (`git add .pql/changelog/` on the whole
|
||||||
|
directory) is still correct and would cover untracked files too.
|
||||||
|
|
||||||
|
### Severity is higher than "medium"
|
||||||
|
|
||||||
|
This is a silent data-loss path, not a nuisance. A turn that only files or edits
|
||||||
|
tickets makes no other commit, so the hook is the sole persistence mechanism; when
|
||||||
|
it silently no-ops, the planning state never lands and a later branch switch drops
|
||||||
|
it. The failure is invisible unless someone reads the hook''s JSON on stderr.
|
||||||
|
Consider raising priority and/or making a failed stage loud rather than
|
||||||
|
`2>/dev/null || true`.', NULL, '2026-08-07 12:30:44', '2026-08-07 12:30:44.880', '2026-08-07 12:30:44.880', NULL, 'aaccee60badf01e93df53301dd52dc79', 2) ON CONFLICT(hash) DO NOTHING;
|
||||||
|
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGYS06SDJGZ4W3Z9V9HDEATW', 'priority', 'medium', 'high', NULL, '2026-08-07 12:30:59', '2026-08-07 12:30:59.962', '2026-08-07 12:30:59.962', NULL, '98d21d1e300343931ea7601b217a3b8e', 2) ON CONFLICT(hash) DO NOTHING;
|
||||||
|
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGYS06SDJGZ4W3Z9V9HDEATW', 'title', 'pre-commit changelog hook leaves ticket_deps/ticket_idmap unstaged', 'pre-commit hook stages no .pql/changelog files (pql plan export --stage)', NULL, '2026-08-07 12:30:59', '2026-08-07 12:30:59.967', '2026-08-07 12:30:59.967', NULL, '4f3d1bf15c90af6ba608067a90d78e77', 2) ON CONFLICT(hash) DO NOTHING;
|
||||||
|
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGYS06SDJGZ4W3Z9V9HDEATW', 'description', 'The pre-commit hook re-exports + stages .pql/changelog on commit but only catches the tickets + ticket_history tables — it leaves ticket_deps (blocker edges) and ticket_idmap (new T-NNN <-> record_id mappings) UNSTAGED. Seen repeatedly this session (D-103 re-sequencing blockers; T-495 id mapping), each needing a manual follow-up commit; otherwise the planning state silently doesn''t persist and a later branch switch drops it — exactly the failure the hook exists to prevent. Fix: stage ALL of .pql/changelog/ (git add .pql/changelog/), not just the tables the export rewrote. Repro: pql ticket block X --by Y + create a ticket, commit unrelated files, observe ticket_deps/ticket_idmap still modified afterward.
|
||||||
|
|
||||||
|
## Widened 2026-08-07 — broader than the title, and the root cause is different
|
||||||
|
|
||||||
|
### The scope is wrong: tickets + ticket_history are NOT immune
|
||||||
|
|
||||||
|
This ticket states the hook "only catches the tickets + ticket_history tables."
|
||||||
|
That is not the failure mode. On 2026-08-07 a ticket-only turn (appending Step-1
|
||||||
|
findings to T-454) left **`tickets/2026-08.sql` and `ticket_history/2026-08.sql`
|
||||||
|
untracked and unstaged** — the two tables assumed to work. The commit aborted
|
||||||
|
with "nothing added to commit but untracked files present" and needed an explicit
|
||||||
|
`git add` of both paths.
|
||||||
|
|
||||||
|
So no table is reliably staged. Retitle accordingly.
|
||||||
|
|
||||||
|
### Likely root cause: staging is gated on rows appended, not on file dirtiness
|
||||||
|
|
||||||
|
The pre-commit hook is a one-liner that delegates everything to pql:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# .pql/hooks/pre-commit
|
||||||
|
''/…/pql'' plan export --stage 2>/dev/null || true
|
||||||
|
```
|
||||||
|
|
||||||
|
Its output on the failing commit:
|
||||||
|
|
||||||
|
```
|
||||||
|
{"files_written":["…/ticket_history/2026-08.sql","…/tickets/2026-08.sql"],"rows_written":0}
|
||||||
|
```
|
||||||
|
|
||||||
|
It **wrote both files and staged neither**. Second invocation (after a manual
|
||||||
|
`git add`) returned `{"files_written":null,"rows_written":0}`.
|
||||||
|
|
||||||
|
Hypothesis: `--stage` only issues the `git add` when it appends rows
|
||||||
|
(`rows_written > 0`). Because ticket mutations already **write through** to
|
||||||
|
`.pql/changelog/` synchronously, by the time the pre-commit hook runs there is
|
||||||
|
nothing left to append — `rows_written` is 0 — so the staging step is skipped even
|
||||||
|
though the file on disk is new/dirty. NOT YET VERIFIED; confirm against pql''s
|
||||||
|
`plan export --stage` implementation.
|
||||||
|
|
||||||
|
This also better explains the originally-reported symptom: `ticket_deps` /
|
||||||
|
`ticket_idmap` aren''t special-cased out, they just tend to be *new month files*
|
||||||
|
or already-written-through, hitting the same skip.
|
||||||
|
|
||||||
|
Contributing factor: new-month rollover. These were the first August files, so
|
||||||
|
they were untracked rather than modified — worth checking whether `--stage`
|
||||||
|
handles untracked paths differently from tracked-but-modified ones.
|
||||||
|
|
||||||
|
### The fix belongs in pql, not clide
|
||||||
|
|
||||||
|
clide''s hook has no logic to fix — it is a single delegating line installed by
|
||||||
|
`pql init`. The change is in pql''s `plan export --stage`: stage every file under
|
||||||
|
`.pql/changelog/` that is dirty or untracked, regardless of `rows_written`.
|
||||||
|
Track/land it in the pql repo; this ticket is the clide-side symptom record.
|
||||||
|
|
||||||
|
The ticket''s proposed workaround (`git add .pql/changelog/` on the whole
|
||||||
|
directory) is still correct and would cover untracked files too.
|
||||||
|
|
||||||
|
### Severity is higher than "medium"
|
||||||
|
|
||||||
|
This is a silent data-loss path, not a nuisance. A turn that only files or edits
|
||||||
|
tickets makes no other commit, so the hook is the sole persistence mechanism; when
|
||||||
|
it silently no-ops, the planning state never lands and a later branch switch drops
|
||||||
|
it. The failure is invisible unless someone reads the hook''s JSON on stderr.
|
||||||
|
Consider raising priority and/or making a failed stage loud rather than
|
||||||
|
`2>/dev/null || true`.', 'The pre-commit hook re-exports + stages .pql/changelog on commit but only catches the tickets + ticket_history tables — it leaves ticket_deps (blocker edges) and ticket_idmap (new T-NNN <-> record_id mappings) UNSTAGED. Seen repeatedly this session (D-103 re-sequencing blockers; T-495 id mapping), each needing a manual follow-up commit; otherwise the planning state silently doesn''t persist and a later branch switch drops it — exactly the failure the hook exists to prevent. Fix: stage ALL of .pql/changelog/ (git add .pql/changelog/), not just the tables the export rewrote. Repro: pql ticket block X --by Y + create a ticket, commit unrelated files, observe ticket_deps/ticket_idmap still modified afterward.
|
||||||
|
|
||||||
|
## Widened 2026-08-07 — broader than the title, and the root cause is different
|
||||||
|
|
||||||
|
### The scope is wrong: tickets + ticket_history are NOT immune
|
||||||
|
|
||||||
|
This ticket states the hook "only catches the tickets + ticket_history tables."
|
||||||
|
That is not the failure mode. On 2026-08-07 a ticket-only turn (appending Step-1
|
||||||
|
findings to T-454) left **`tickets/2026-08.sql` and `ticket_history/2026-08.sql`
|
||||||
|
untracked and unstaged** — the two tables assumed to work. The commit aborted
|
||||||
|
with "nothing added to commit but untracked files present" and needed an explicit
|
||||||
|
`git add` of both paths.
|
||||||
|
|
||||||
|
So no table is reliably staged. Retitle accordingly.
|
||||||
|
|
||||||
|
### Likely root cause: staging is gated on rows appended, not on file dirtiness
|
||||||
|
|
||||||
|
The pre-commit hook is a one-liner that delegates everything to pql:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# .pql/hooks/pre-commit
|
||||||
|
''/…/pql'' plan export --stage 2>/dev/null || true
|
||||||
|
```
|
||||||
|
|
||||||
|
Its output on the failing commit:
|
||||||
|
|
||||||
|
```
|
||||||
|
{"files_written":["…/ticket_history/2026-08.sql","…/tickets/2026-08.sql"],"rows_written":0}
|
||||||
|
```
|
||||||
|
|
||||||
|
It **wrote both files and staged neither**. Second invocation (after a manual
|
||||||
|
`git add`) returned `{"files_written":null,"rows_written":0}`.
|
||||||
|
|
||||||
|
Hypothesis: `--stage` only issues the `git add` when it appends rows
|
||||||
|
(`rows_written > 0`). Because ticket mutations already **write through** to
|
||||||
|
`.pql/changelog/` synchronously, by the time the pre-commit hook runs there is
|
||||||
|
nothing left to append — `rows_written` is 0 — so the staging step is skipped even
|
||||||
|
though the file on disk is new/dirty. NOT YET VERIFIED; confirm against pql''s
|
||||||
|
`plan export --stage` implementation.
|
||||||
|
|
||||||
|
This also better explains the originally-reported symptom: `ticket_deps` /
|
||||||
|
`ticket_idmap` aren''t special-cased out, they just tend to be *new month files*
|
||||||
|
or already-written-through, hitting the same skip.
|
||||||
|
|
||||||
|
Contributing factor: new-month rollover. These were the first August files, so
|
||||||
|
they were untracked rather than modified — worth checking whether `--stage`
|
||||||
|
handles untracked paths differently from tracked-but-modified ones.
|
||||||
|
|
||||||
|
### The fix belongs in pql, not clide
|
||||||
|
|
||||||
|
clide''s hook has no logic to fix — it is a single delegating line installed by
|
||||||
|
`pql init`. The change is in pql''s `plan export --stage`: stage every file under
|
||||||
|
`.pql/changelog/` that is dirty or untracked, regardless of `rows_written`.
|
||||||
|
Track/land it in the pql repo; this ticket is the clide-side symptom record.
|
||||||
|
|
||||||
|
The ticket''s proposed workaround (`git add .pql/changelog/` on the whole
|
||||||
|
directory) is still correct and would cover untracked files too.
|
||||||
|
|
||||||
|
### Severity is higher than "medium"
|
||||||
|
|
||||||
|
This is a silent data-loss path, not a nuisance. A turn that only files or edits
|
||||||
|
tickets makes no other commit, so the hook is the sole persistence mechanism; when
|
||||||
|
it silently no-ops, the planning state never lands and a later branch switch drops
|
||||||
|
it. The failure is invisible unless someone reads the hook''s JSON on stderr.
|
||||||
|
Consider raising priority and/or making a failed stage loud rather than
|
||||||
|
`2>/dev/null || true`.
|
||||||
|
|
||||||
|
### Correction (same session): not an untracked-file issue — `--stage` never stages
|
||||||
|
|
||||||
|
The "new-month rollover / untracked path" contributing factor above is **disproved**.
|
||||||
|
Tested directly: with `tickets/2026-08.sql` and `ticket_history/2026-08.sql` already
|
||||||
|
tracked and merely *modified*, a bare `git commit` still aborted with "no changes
|
||||||
|
added to commit". Hook output was identical:
|
||||||
|
|
||||||
|
```
|
||||||
|
{"files_written":["…/ticket_history/2026-08.sql","…/tickets/2026-08.sql"],"rows_written":0}
|
||||||
|
```
|
||||||
|
|
||||||
|
Tracked-modified and untracked-new both fail. The only common factor is
|
||||||
|
`rows_written: 0`.
|
||||||
|
|
||||||
|
**Escalates the diagnosis:** this is not intermittent and not table-specific.
|
||||||
|
Because ticket mutations write through to `.pql/changelog/` synchronously, the
|
||||||
|
pre-commit export always finds zero rows left to append, so `--stage` skips its
|
||||||
|
`git add` on *every* commit. In this repo the hook''s staging step is effectively
|
||||||
|
dead — it has likely never worked, and every ticket change that landed did so
|
||||||
|
because some other file in the commit was staged by hand, or because someone
|
||||||
|
noticed and re-added.
|
||||||
|
|
||||||
|
That reframes the earlier `ticket_deps` / `ticket_idmap` reports: those tables
|
||||||
|
weren''t being singled out, they were just the cases where nothing else in the
|
||||||
|
commit masked the failure.
|
||||||
|
|
||||||
|
**Fix (pql):** `plan export --stage` must stage on file state, not on
|
||||||
|
`rows_written` — `git add` every dirty-or-untracked path under `.pql/changelog/`
|
||||||
|
whenever the directory differs from the index, including when the export was a
|
||||||
|
no-op. Consider also dropping the hook''s `2>/dev/null || true` so a staging
|
||||||
|
failure is visible instead of silent.', NULL, '2026-08-07 12:31:41', '2026-08-07 12:31:41.109', '2026-08-07 12:31:41.109', NULL, '52366e812f9b77586b07f322791e4fd3', 2) ON CONFLICT(hash) DO NOTHING;
|
||||||
@@ -1,173 +1,173 @@
|
|||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM67ZXPWX71ND4C699C', 'T-43', '2026-04-22 22:01:13', '2026-05-07 19:04:55', NULL, '069521bcf068ff6889cee5251511446c', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM67ZXPWX71ND4C699C', 'T-43', '2026-04-22 22:01:13', '2026-05-07 19:04:55', NULL, '069521bcf068ff6889cee5251511446c', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7SS2V5Z1M1XJGQX0M', 'T-86', '2026-05-06 13:28:58', '2026-05-07 19:04:55', NULL, '07e51e80b6df55240c465d17a9430700', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7SS2V5Z1M1XJGQX0M', 'T-86', '2026-05-06 13:28:58', '2026-05-07 19:04:55', NULL, '07e51e80b6df55240c465d17a9430700', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7P6Q0DG4RG4CBHFJG', 'T-67', '2026-04-24 06:34:16', '2026-05-07 19:04:55', NULL, '0b64bd846488ccf4fce74a6e14629edb', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7P6Q0DG4RG4CBHFJG', 'T-67', '2026-04-24 06:34:16', '2026-05-07 19:04:55', NULL, '0b64bd846488ccf4fce74a6e14629edb', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM460GRBMZMV8E5339M', 'T-77', '2026-05-05 12:58:59', '2026-05-07 19:04:55', NULL, '0cdd07e0992ab8eb76d6945ae1079855', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM460GRBMZMV8E5339M', 'T-77', '2026-05-05 12:58:59', '2026-05-07 19:04:55', NULL, '0cdd07e0992ab8eb76d6945ae1079855', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM79D19C0ZTXAVPKCCG', 'T-12', '2026-04-22 11:47:03', '2026-05-07 19:04:55', NULL, '10055ea4ae6c926286eb81eb35b8ef8f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM79D19C0ZTXAVPKCCG', 'T-12', '2026-04-22 11:47:03', '2026-05-07 19:04:55', NULL, '10055ea4ae6c926286eb81eb35b8ef8f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM427FX3GTR3VNNKM40', 'T-63', '2026-04-24 06:34:16', '2026-05-07 19:04:55', NULL, '178d61b166cf7e8f17efc83cdf60c062', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM427FX3GTR3VNNKM40', 'T-63', '2026-04-24 06:34:16', '2026-05-07 19:04:55', NULL, '178d61b166cf7e8f17efc83cdf60c062', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7DV4ZS010XWZJ9A84', 'T-6', '2026-04-22 11:45:41', '2026-05-07 19:04:55', NULL, '17e7bcab28adfbab47be2ad9aa4e4c56', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7DV4ZS010XWZJ9A84', 'T-6', '2026-04-22 11:45:41', '2026-05-07 19:04:55', NULL, '17e7bcab28adfbab47be2ad9aa4e4c56', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4W194B2421P2SF83R', 'T-25', '2026-04-22 20:14:24', '2026-05-07 19:04:55', NULL, '1b888a483ec795737d7a1cf71fdbd699', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4W194B2421P2SF83R', 'T-25', '2026-04-22 20:14:24', '2026-05-07 19:04:55', NULL, '1b888a483ec795737d7a1cf71fdbd699', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM77477EN2R5872G95M', 'T-93', '2026-05-07 06:33:47', '2026-05-07 19:04:55', NULL, '1f5f4e360943d2a903cdd7c819bfeaa3', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM77477EN2R5872G95M', 'T-93', '2026-05-07 06:33:47', '2026-05-07 19:04:55', NULL, '1f5f4e360943d2a903cdd7c819bfeaa3', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7D8AG5AY1CW58HCB4', 'T-58', '2026-04-23 20:32:06', '2026-05-07 19:04:55', NULL, '253f8fb1458c5394eea856c885f94fff', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7D8AG5AY1CW58HCB4', 'T-58', '2026-04-23 20:32:06', '2026-05-07 19:04:55', NULL, '253f8fb1458c5394eea856c885f94fff', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4M63G18VAQFG6R3XW', 'T-28', '2026-04-22 20:14:52', '2026-05-07 19:04:55', NULL, '280276cb372707c0fcdbc7de5c68f568', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4M63G18VAQFG6R3XW', 'T-28', '2026-04-22 20:14:52', '2026-05-07 19:04:55', NULL, '280276cb372707c0fcdbc7de5c68f568', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7CEP425DNV3W7RFPM', 'T-72', '2026-05-05 12:53:05', '2026-05-07 19:04:55', NULL, '2c7cd24dee2e7d21a31f476af233284d', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7CEP425DNV3W7RFPM', 'T-72', '2026-05-05 12:53:05', '2026-05-07 19:04:55', NULL, '2c7cd24dee2e7d21a31f476af233284d', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4XZA5399D2EHYCVFC', 'T-5', '2026-04-22 11:45:41', '2026-05-07 19:04:55', NULL, '31b2ad13bb8bcc41e4d21825a232f086', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4XZA5399D2EHYCVFC', 'T-5', '2026-04-22 11:45:41', '2026-05-07 19:04:55', NULL, '31b2ad13bb8bcc41e4d21825a232f086', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM79CNBXJ2S3CFQR7VM', 'T-81', '2026-05-05 12:58:59', '2026-05-07 19:04:55', NULL, '32698f648acf611d10fc719f6be28bad', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM79CNBXJ2S3CFQR7VM', 'T-81', '2026-05-05 12:58:59', '2026-05-07 19:04:55', NULL, '32698f648acf611d10fc719f6be28bad', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM76XDA3SZMPWR8WQSC', 'T-62', '2026-04-24 06:34:16', '2026-05-07 19:04:55', NULL, '3439d016919d87e8b4860735a23de1a8', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM76XDA3SZMPWR8WQSC', 'T-62', '2026-04-24 06:34:16', '2026-05-07 19:04:55', NULL, '3439d016919d87e8b4860735a23de1a8', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5GSR5WPC2T7CJM8XW', 'T-4', '2026-04-22 11:45:41', '2026-05-07 19:04:55', NULL, '407e3921ca9e6d5d13e11b7f577ad591', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5GSR5WPC2T7CJM8XW', 'T-4', '2026-04-22 11:45:41', '2026-05-07 19:04:55', NULL, '407e3921ca9e6d5d13e11b7f577ad591', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4PMYC2E1X99HX4MDM', 'T-84', '2026-05-06 10:16:02', '2026-05-07 19:04:55', NULL, '40ce052d36bd0270aa01f9e25c1a944a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4PMYC2E1X99HX4MDM', 'T-84', '2026-05-06 10:16:02', '2026-05-07 19:04:55', NULL, '40ce052d36bd0270aa01f9e25c1a944a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5A8DYZ3BCJN1DEY7C', 'T-71', '2026-05-05 12:53:01', '2026-05-07 19:04:55', NULL, '43cfd9109375b0fb6a8f176a0df764a5', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5A8DYZ3BCJN1DEY7C', 'T-71', '2026-05-05 12:53:01', '2026-05-07 19:04:55', NULL, '43cfd9109375b0fb6a8f176a0df764a5', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM48MDE8ZZ82VWNY994', 'T-27', '2026-04-22 20:14:45', '2026-05-07 19:04:55', NULL, '440474d801f1b9bd05e8fbb4254c3817', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM48MDE8ZZ82VWNY994', 'T-27', '2026-04-22 20:14:45', '2026-05-07 19:04:55', NULL, '440474d801f1b9bd05e8fbb4254c3817', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6M1VZ8Z2SZ94F0EQR', 'T-3', '2026-04-22 11:45:41', '2026-05-07 19:04:55', NULL, '44d2e24e49ca8555a6b3327f7e954ede', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6M1VZ8Z2SZ94F0EQR', 'T-3', '2026-04-22 11:45:41', '2026-05-07 19:04:55', NULL, '44d2e24e49ca8555a6b3327f7e954ede', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7AVABFH067XGTTCVM', 'T-76', '2026-05-05 12:58:59', '2026-05-07 19:04:55', NULL, '4a3e92a591238f629d18f9b10087c7f6', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7AVABFH067XGTTCVM', 'T-76', '2026-05-05 12:58:59', '2026-05-07 19:04:55', NULL, '4a3e92a591238f629d18f9b10087c7f6', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5WXV1RKPDK810C3FR', 'T-31', '2026-04-22 20:33:56', '2026-05-07 19:04:55', NULL, '4c423ea86e8173f7fa6edddea9adbadb', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5WXV1RKPDK810C3FR', 'T-31', '2026-04-22 20:33:56', '2026-05-07 19:04:55', NULL, '4c423ea86e8173f7fa6edddea9adbadb', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM62E3MNW8TBTKSR9GM', 'T-1', '2026-04-22 09:41:51', '2026-05-07 19:04:55', NULL, '55239329122e1f84e9aeac9cee14a21a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM62E3MNW8TBTKSR9GM', 'T-1', '2026-04-22 09:41:51', '2026-05-07 19:04:55', NULL, '55239329122e1f84e9aeac9cee14a21a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4KH7VR0BMZV5SSTXC', 'T-37', '2026-04-22 21:03:40', '2026-05-07 19:04:55', NULL, '55c80e1ce022b96aab6e97e31579c302', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4KH7VR0BMZV5SSTXC', 'T-37', '2026-04-22 21:03:40', '2026-05-07 19:04:55', NULL, '55c80e1ce022b96aab6e97e31579c302', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM42RQZVEWTF9CJSRF8', 'T-85', '2026-05-06 13:28:58', '2026-05-07 19:04:55', NULL, '6133918ee124e5502286fa0de06b5bd9', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM42RQZVEWTF9CJSRF8', 'T-85', '2026-05-06 13:28:58', '2026-05-07 19:04:55', NULL, '6133918ee124e5502286fa0de06b5bd9', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7QREFG3SBG2QPYY7R', 'T-59', '2026-04-23 20:32:06', '2026-05-07 19:04:55', NULL, '64c389eab795606b9d8b5b65877a67bc', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7QREFG3SBG2QPYY7R', 'T-59', '2026-04-23 20:32:06', '2026-05-07 19:04:55', NULL, '64c389eab795606b9d8b5b65877a67bc', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5JH7WV2RH5DGEA2AC', 'T-19', '2026-04-22 14:08:40', '2026-05-07 19:04:55', NULL, '65ba2e99100be29287532b3390054401', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5JH7WV2RH5DGEA2AC', 'T-19', '2026-04-22 14:08:40', '2026-05-07 19:04:55', NULL, '65ba2e99100be29287532b3390054401', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5YG22EV7BFTX5RTPR', 'T-26', '2026-04-22 20:14:33', '2026-05-07 19:04:55', NULL, '685c38f471288372eab298a106a06d66', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5YG22EV7BFTX5RTPR', 'T-26', '2026-04-22 20:14:33', '2026-05-07 19:04:55', NULL, '685c38f471288372eab298a106a06d66', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6T6580D8ABDVTMNZW', 'T-8', '2026-04-22 11:45:41', '2026-05-07 19:04:55', NULL, '6aa0a08f23546d11b37f80d54920c3be', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6T6580D8ABDVTMNZW', 'T-8', '2026-04-22 11:45:41', '2026-05-07 19:04:55', NULL, '6aa0a08f23546d11b37f80d54920c3be', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4VVHNKNXPYD4XWRYW', 'T-30', '2026-04-22 20:33:53', '2026-05-07 19:04:55', NULL, '6d929d2dcc64310a43b21be1a8314258', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4VVHNKNXPYD4XWRYW', 'T-30', '2026-04-22 20:33:53', '2026-05-07 19:04:55', NULL, '6d929d2dcc64310a43b21be1a8314258', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4TQEYESK545T8F164', 'T-57', '2026-04-23 20:32:06', '2026-05-07 19:04:55', NULL, '6ff368c440149011af6cc3e2bdfe243f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4TQEYESK545T8F164', 'T-57', '2026-04-23 20:32:06', '2026-05-07 19:04:55', NULL, '6ff368c440149011af6cc3e2bdfe243f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM79H4MPEWW2TWQ89D0', 'T-46', '2026-04-23 20:27:58', '2026-05-07 19:04:55', NULL, '71f030d09b588292801ae8853accd90c', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM79H4MPEWW2TWQ89D0', 'T-46', '2026-04-23 20:27:58', '2026-05-07 19:04:55', NULL, '71f030d09b588292801ae8853accd90c', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM70QNVQY1MQGP3A33G', 'T-78', '2026-05-05 12:58:59', '2026-05-07 19:04:55', NULL, '73ecd48d2d9f1cdf8e1bf6e88a8dc812', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM70QNVQY1MQGP3A33G', 'T-78', '2026-05-05 12:58:59', '2026-05-07 19:04:55', NULL, '73ecd48d2d9f1cdf8e1bf6e88a8dc812', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM52JT96V5067SM0DMR', 'T-87', '2026-05-06 13:46:07', '2026-05-07 19:04:55', NULL, '740c1dcab17dbdc339750aa8e32a1281', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM52JT96V5067SM0DMR', 'T-87', '2026-05-06 13:46:07', '2026-05-07 19:04:55', NULL, '740c1dcab17dbdc339750aa8e32a1281', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4QKBQY7FPCNX6N28R', 'T-45', '2026-04-23 20:27:28', '2026-05-07 19:04:55', NULL, '7c312190b902337039b21f4743be8908', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4QKBQY7FPCNX6N28R', 'T-45', '2026-04-23 20:27:28', '2026-05-07 19:04:55', NULL, '7c312190b902337039b21f4743be8908', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5Q6AWSTKGT0P64TRR', 'T-39', '2026-04-22 21:03:40', '2026-05-07 19:04:55', NULL, '825042c21d032181c1fe6d55a29a94f9', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5Q6AWSTKGT0P64TRR', 'T-39', '2026-04-22 21:03:40', '2026-05-07 19:04:55', NULL, '825042c21d032181c1fe6d55a29a94f9', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM59BAJSJ1JESDTPNER', 'T-15', '2026-04-22 11:47:18', '2026-05-07 19:04:55', NULL, '836e6112c6e1dff23772619499fad245', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM59BAJSJ1JESDTPNER', 'T-15', '2026-04-22 11:47:18', '2026-05-07 19:04:55', NULL, '836e6112c6e1dff23772619499fad245', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7TW8EJNJ2VP306A20', 'T-14', '2026-04-22 11:47:18', '2026-05-07 19:04:55', NULL, '8496d923db0e1fa76e7b787a273e974e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7TW8EJNJ2VP306A20', 'T-14', '2026-04-22 11:47:18', '2026-05-07 19:04:55', NULL, '8496d923db0e1fa76e7b787a273e974e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5QHMB46NSHHPVQRF0', 'T-24', '2026-04-22 14:08:40', '2026-05-07 19:04:55', NULL, '8a892f3717f8da2c93f67d3170af014f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5QHMB46NSHHPVQRF0', 'T-24', '2026-04-22 14:08:40', '2026-05-07 19:04:55', NULL, '8a892f3717f8da2c93f67d3170af014f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5AACHWPFWZDCJ3CPW', 'T-73', '2026-05-05 12:53:21', '2026-05-07 19:04:55', NULL, '8e532488915724b80881c7b2dc227de9', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5AACHWPFWZDCJ3CPW', 'T-73', '2026-05-05 12:53:21', '2026-05-07 19:04:55', NULL, '8e532488915724b80881c7b2dc227de9', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6P00AT6KGVZ1EF60C', 'T-18', '2026-04-22 13:26:29', '2026-05-07 19:04:55', NULL, '900d00f28a29207a464017a0bd750f33', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6P00AT6KGVZ1EF60C', 'T-18', '2026-04-22 13:26:29', '2026-05-07 19:04:55', NULL, '900d00f28a29207a464017a0bd750f33', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM734YZ060Q63H40EYG', 'T-80', '2026-05-05 12:58:59', '2026-05-07 19:04:55', NULL, '90da3a2c5bd03b314d661362a3919506', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM734YZ060Q63H40EYG', 'T-80', '2026-05-05 12:58:59', '2026-05-07 19:04:55', NULL, '90da3a2c5bd03b314d661362a3919506', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6JXWYYQ6MT6N8STYM', 'T-38', '2026-04-22 21:03:40', '2026-05-07 19:04:55', NULL, '91c3ef42d94e16789915ee6366f7015d', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6JXWYYQ6MT6N8STYM', 'T-38', '2026-04-22 21:03:40', '2026-05-07 19:04:55', NULL, '91c3ef42d94e16789915ee6366f7015d', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM75XRV8AQG2HEQZEJ0', 'T-16', '2026-04-22 11:47:18', '2026-05-07 19:04:55', NULL, '98bf61f1693e8b8877c2cc03c9fb120d', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM75XRV8AQG2HEQZEJ0', 'T-16', '2026-04-22 11:47:18', '2026-05-07 19:04:55', NULL, '98bf61f1693e8b8877c2cc03c9fb120d', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM67JSC5RKS6M9182KG', 'T-41', '2026-04-22 21:03:40', '2026-05-07 19:04:55', NULL, '9ab8f6ffa933c87dd3153eaea452e902', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM67JSC5RKS6M9182KG', 'T-41', '2026-04-22 21:03:40', '2026-05-07 19:04:55', NULL, '9ab8f6ffa933c87dd3153eaea452e902', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM66FTCTWHH9AQTNFKR', 'T-55', '2026-04-23 20:32:06', '2026-05-07 19:04:55', NULL, 'a7b7dc2af0426c8bcbfea6a3023a0aff', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM66FTCTWHH9AQTNFKR', 'T-55', '2026-04-23 20:32:06', '2026-05-07 19:04:55', NULL, 'a7b7dc2af0426c8bcbfea6a3023a0aff', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7YHYTWJGWPFJNHEAR', 'T-10', '2026-04-22 11:47:02', '2026-05-07 19:04:55', NULL, 'a8fa7598a624ad83878db046ffa8986f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7YHYTWJGWPFJNHEAR', 'T-10', '2026-04-22 11:47:02', '2026-05-07 19:04:55', NULL, 'a8fa7598a624ad83878db046ffa8986f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6TS48DVFDVJNZ5WGC', 'T-11', '2026-04-22 11:47:02', '2026-05-07 19:04:55', NULL, 'af42494291be5910520becc10285e157', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6TS48DVFDVJNZ5WGC', 'T-11', '2026-04-22 11:47:02', '2026-05-07 19:04:55', NULL, 'af42494291be5910520becc10285e157', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4R0WRHSJV1MVCW31M', 'T-9', '2026-04-22 11:47:02', '2026-05-07 19:04:55', NULL, 'b8d2fca6e4b3882e4cd1ec486924265b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4R0WRHSJV1MVCW31M', 'T-9', '2026-04-22 11:47:02', '2026-05-07 19:04:55', NULL, 'b8d2fca6e4b3882e4cd1ec486924265b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4005W4QV0ZPBMQ02C', 'T-35', '2026-04-22 20:34:06', '2026-05-07 19:04:55', NULL, 'bbbe9cce785ce60416cba671cea2985a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4005W4QV0ZPBMQ02C', 'T-35', '2026-04-22 20:34:06', '2026-05-07 19:04:55', NULL, 'bbbe9cce785ce60416cba671cea2985a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM50DVPFP4WY74RQBB8', 'T-61', '2026-04-24 06:34:16', '2026-05-07 19:04:55', NULL, 'bbf53c20ed761296c7bd54d418b67218', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM50DVPFP4WY74RQBB8', 'T-61', '2026-04-24 06:34:16', '2026-05-07 19:04:55', NULL, 'bbf53c20ed761296c7bd54d418b67218', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM50X0DX8XTVZEA5GN8', 'T-60', '2026-04-23 20:32:06', '2026-05-07 19:04:55', NULL, 'bc1502a8c8fe4e44c004f56e9e15b03e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM50X0DX8XTVZEA5GN8', 'T-60', '2026-04-23 20:32:06', '2026-05-07 19:04:55', NULL, 'bc1502a8c8fe4e44c004f56e9e15b03e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6PMW57C70KBJVAV10', 'T-22', '2026-04-22 14:08:40', '2026-05-07 19:04:55', NULL, 'be0ae61f02897da33e8a9b2d6d1b002e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6PMW57C70KBJVAV10', 'T-22', '2026-04-22 14:08:40', '2026-05-07 19:04:55', NULL, 'be0ae61f02897da33e8a9b2d6d1b002e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6GHHRANK5532VJVJR', 'T-34', '2026-04-22 20:34:03', '2026-05-07 19:04:55', NULL, 'c042cabf5814a596e1582a8a85138543', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6GHHRANK5532VJVJR', 'T-34', '2026-04-22 20:34:03', '2026-05-07 19:04:55', NULL, 'c042cabf5814a596e1582a8a85138543', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM606BMYDDGRSJBVPG8', 'T-70', '2026-05-05 12:52:56', '2026-05-07 19:04:55', NULL, 'c04d59ecdcc1ade801ed7f0866a3f00c', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM606BMYDDGRSJBVPG8', 'T-70', '2026-05-05 12:52:56', '2026-05-07 19:04:55', NULL, 'c04d59ecdcc1ade801ed7f0866a3f00c', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM74S58G8XZV1766VD0', 'T-90', '2026-05-06 20:38:14', '2026-05-07 19:04:55', NULL, 'c36ec6ce6ac423fa9983758304139d2b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM74S58G8XZV1766VD0', 'T-90', '2026-05-06 20:38:14', '2026-05-07 19:04:55', NULL, 'c36ec6ce6ac423fa9983758304139d2b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7CEKQCMZAV751402G', 'T-47', '2026-04-23 20:28:43', '2026-05-07 19:04:55', NULL, 'c5abd99aac954b783b84f3b77d003691', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7CEKQCMZAV751402G', 'T-47', '2026-04-23 20:28:43', '2026-05-07 19:04:55', NULL, 'c5abd99aac954b783b84f3b77d003691', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5EP8B65T0AR52TQFW', 'T-92', '2026-05-07 05:51:48', '2026-05-07 19:04:55', NULL, 'c62020a1cf82eb7ed6bb5635d5f8f0fa', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5EP8B65T0AR52TQFW', 'T-92', '2026-05-07 05:51:48', '2026-05-07 19:04:55', NULL, 'c62020a1cf82eb7ed6bb5635d5f8f0fa', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4QHBTA4VE6TWQT43R', 'T-13', '2026-04-22 11:47:18', '2026-05-07 19:04:55', NULL, 'd08af226653f0822b332b640dfcedde5', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4QHBTA4VE6TWQT43R', 'T-13', '2026-04-22 11:47:18', '2026-05-07 19:04:55', NULL, 'd08af226653f0822b332b640dfcedde5', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6KX7HEQJ65HZ566DG', 'T-2', '2026-04-22 11:45:26', '2026-05-07 19:04:55', NULL, 'd1b1abb9046e230f581009daf61e7bfd', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6KX7HEQJ65HZ566DG', 'T-2', '2026-04-22 11:45:26', '2026-05-07 19:04:55', NULL, 'd1b1abb9046e230f581009daf61e7bfd', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7Y0DFP66HSP073XHC', 'T-88', '2026-05-06 14:34:35', '2026-05-07 19:04:55', NULL, 'd1ea1e789ff487787076d0ca66670e35', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7Y0DFP66HSP073XHC', 'T-88', '2026-05-06 14:34:35', '2026-05-07 19:04:55', NULL, 'd1ea1e789ff487787076d0ca66670e35', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5JZ2AKN74FKMK3MR8', 'T-69', '2026-05-05 12:52:52', '2026-05-07 19:04:55', NULL, 'd2622779cfbab03758ed02949f12fa72', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5JZ2AKN74FKMK3MR8', 'T-69', '2026-05-05 12:52:52', '2026-05-07 19:04:55', NULL, 'd2622779cfbab03758ed02949f12fa72', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7MKCHC37G69SJGQ04', 'T-32', '2026-04-22 20:33:58', '2026-05-07 19:04:55', NULL, 'd4125c549e70d4f4d37bb43a4f3ccbd1', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7MKCHC37G69SJGQ04', 'T-32', '2026-04-22 20:33:58', '2026-05-07 19:04:55', NULL, 'd4125c549e70d4f4d37bb43a4f3ccbd1', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5NS39QCDHNVVVT1R4', 'T-17', '2026-04-22 13:26:29', '2026-05-07 19:04:55', NULL, 'd732affde22ee738f13bacb127c094e7', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5NS39QCDHNVVVT1R4', 'T-17', '2026-04-22 13:26:29', '2026-05-07 19:04:55', NULL, 'd732affde22ee738f13bacb127c094e7', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5X2K66A0MQY2VZ7H4', 'T-83', '2026-05-06 09:17:39', '2026-05-07 19:04:55', NULL, 'da553a2c61adb1795c0ab33867dc6ba3', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5X2K66A0MQY2VZ7H4', 'T-83', '2026-05-06 09:17:39', '2026-05-07 19:04:55', NULL, 'da553a2c61adb1795c0ab33867dc6ba3', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4Q4XW93E3WA1SD9KW', 'T-75', '2026-05-05 12:58:59', '2026-05-07 19:04:55', NULL, 'db0b7c934e54d06fcf33aaf168a723e4', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4Q4XW93E3WA1SD9KW', 'T-75', '2026-05-05 12:58:59', '2026-05-07 19:04:55', NULL, 'db0b7c934e54d06fcf33aaf168a723e4', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6YBQP75NQQ4Y9DN9C', 'T-68', '2026-05-05 12:52:48', '2026-05-07 19:04:55', NULL, 'e14345ea70ff466ed3d9b8de161ea556', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6YBQP75NQQ4Y9DN9C', 'T-68', '2026-05-05 12:52:48', '2026-05-07 19:04:55', NULL, 'e14345ea70ff466ed3d9b8de161ea556', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6VMWWSP4BV8Q11W0M', 'T-20', '2026-04-22 14:08:40', '2026-05-07 19:04:55', NULL, 'ebf54efaf812fb838959a80b4cdcc527', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6VMWWSP4BV8Q11W0M', 'T-20', '2026-04-22 14:08:40', '2026-05-07 19:04:55', NULL, 'ebf54efaf812fb838959a80b4cdcc527', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM699HAWC76SHRA7AM4', 'T-21', '2026-04-22 14:08:40', '2026-05-07 19:04:55', NULL, 'f217b0ca72240fbbe463d296f250f3b6', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM699HAWC76SHRA7AM4', 'T-21', '2026-04-22 14:08:40', '2026-05-07 19:04:55', NULL, 'f217b0ca72240fbbe463d296f250f3b6', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM64DC28XV20JJ8KW00', 'T-33', '2026-04-22 20:34:01', '2026-05-07 19:04:55', NULL, 'f7924a89ac74721c9145a511b7a1b4e9', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM64DC28XV20JJ8KW00', 'T-33', '2026-04-22 20:34:01', '2026-05-07 19:04:55', NULL, 'f7924a89ac74721c9145a511b7a1b4e9', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM454GCK8ENRKRA44NW', 'T-49', '2026-04-23 20:31:35', '2026-05-07 19:04:55', NULL, 'f9fb75eb241d8edd62688d7ac3fdd25a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM454GCK8ENRKRA44NW', 'T-49', '2026-04-23 20:31:35', '2026-05-07 19:04:55', NULL, 'f9fb75eb241d8edd62688d7ac3fdd25a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM57AEVK5E0GWVPGAY8', 'T-79', '2026-05-05 12:58:59', '2026-05-07 19:04:55', NULL, 'fe4c71ca925995617dcd4409caaae9d0', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM57AEVK5E0GWVPGAY8', 'T-79', '2026-05-05 12:58:59', '2026-05-07 19:04:55', NULL, 'fe4c71ca925995617dcd4409caaae9d0', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6RDM2EKZX132GPV7M', 'T-40', '2026-04-22 21:03:40', '2026-05-07 19:04:55', NULL, 'fe57a623da7c3fda11455f1d78ba7f4c', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6RDM2EKZX132GPV7M', 'T-40', '2026-04-22 21:03:40', '2026-05-07 19:04:55', NULL, 'fe57a623da7c3fda11455f1d78ba7f4c', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7162Z26FDWXG35VH0', 'T-7', '2026-04-22 11:45:41', '2026-05-07 19:04:55', NULL, 'ffa3d6a93f30550da97a3357a0b40c3c', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7162Z26FDWXG35VH0', 'T-7', '2026-04-22 11:45:41', '2026-05-07 19:04:55', NULL, 'ffa3d6a93f30550da97a3357a0b40c3c', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM48X0763Z9DZSM0HFR', 'T-94', '2026-05-07 19:08:29', '2026-05-07 19:08:52', NULL, '8087c73fd647b2156a0275ec7ec2ffcd', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM48X0763Z9DZSM0HFR', 'T-94', '2026-05-07 19:08:29', '2026-05-07 19:08:52', NULL, '8087c73fd647b2156a0275ec7ec2ffcd', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5WCDTR41VN9P1EGMC', 'T-96', '2026-05-17 17:16:01', '2026-05-17 18:11:18', NULL, 'c44d6bedd77f53875b4fb7f92e8c9895', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5WCDTR41VN9P1EGMC', 'T-96', '2026-05-17 17:16:01', '2026-05-17 18:11:18', NULL, 'c44d6bedd77f53875b4fb7f92e8c9895', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7F3V130BQXQH6HDVC', 'T-98', '2026-05-17 18:47:13', '2026-05-17 18:55:57', NULL, 'b2543702670de76b92f98bcb3690901e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7F3V130BQXQH6HDVC', 'T-98', '2026-05-17 18:47:13', '2026-05-17 18:55:57', NULL, 'b2543702670de76b92f98bcb3690901e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7NRKR9J1QTDSP9650', 'T-101', '2026-05-17 18:47:29', '2026-05-17 19:01:39', NULL, '8acbd73697594b2f0686c7e1f01f0b8e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7NRKR9J1QTDSP9650', 'T-101', '2026-05-17 18:47:29', '2026-05-17 19:01:39', NULL, '8acbd73697594b2f0686c7e1f01f0b8e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4QNZM15V1ZK32YS6G', 'T-102', '2026-05-17 18:47:33', '2026-05-17 19:01:39', NULL, 'c77e3fe23ababa8854065860aaaf7645', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4QNZM15V1ZK32YS6G', 'T-102', '2026-05-17 18:47:33', '2026-05-17 19:01:39', NULL, 'c77e3fe23ababa8854065860aaaf7645', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM493QAZNJTJQHYFGCC', 'T-103', '2026-05-17 18:47:39', '2026-05-17 19:18:43', NULL, '34fae6a3452e2f3a6fc76605fb82cd85', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM493QAZNJTJQHYFGCC', 'T-103', '2026-05-17 18:47:39', '2026-05-17 19:18:43', NULL, '34fae6a3452e2f3a6fc76605fb82cd85', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6MP9JD93ZE0CDGFFW', 'T-106', '2026-05-17 18:47:51', '2026-05-17 19:18:43', NULL, '52a5c071f2c90428eba13aaa8f785831', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6MP9JD93ZE0CDGFFW', 'T-106', '2026-05-17 18:47:51', '2026-05-17 19:18:43', NULL, '52a5c071f2c90428eba13aaa8f785831', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7WW3008NZRJWJ88HG', 'T-113', '2026-05-17 18:48:24', '2026-05-17 19:18:43', NULL, 'fabd5c2006ae0e13714b1aa12ecd2e41', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7WW3008NZRJWJ88HG', 'T-113', '2026-05-17 18:48:24', '2026-05-17 19:18:43', NULL, 'fabd5c2006ae0e13714b1aa12ecd2e41', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6MWAKNB2NE3ZZ0XKW', 'T-110', '2026-05-17 18:48:09', '2026-05-17 19:39:12', NULL, '22d75188f931b18801e8e9015e9863a5', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6MWAKNB2NE3ZZ0XKW', 'T-110', '2026-05-17 18:48:09', '2026-05-17 19:39:12', NULL, '22d75188f931b18801e8e9015e9863a5', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM60QRRNEEWG84VWKXC', 'T-66', '2026-04-24 06:34:16', '2026-05-17 19:39:37', NULL, '8b24910aba2e49638668b03f64006a5a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM60QRRNEEWG84VWKXC', 'T-66', '2026-04-24 06:34:16', '2026-05-17 19:39:37', NULL, '8b24910aba2e49638668b03f64006a5a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM42M9RK4399B4F4WSG', 'T-64', '2026-04-24 06:34:16', '2026-05-17 19:39:37', NULL, '9d3e8f627b3095e1db58e047618be710', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM42M9RK4399B4F4WSG', 'T-64', '2026-04-24 06:34:16', '2026-05-17 19:39:37', NULL, '9d3e8f627b3095e1db58e047618be710', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM65SSVGN5M36T4QNDC', 'T-117', '2026-05-17 19:28:28', '2026-05-17 19:39:40', NULL, '852007cdda3b405757c088e160798b40', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM65SSVGN5M36T4QNDC', 'T-117', '2026-05-17 19:28:28', '2026-05-17 19:39:40', NULL, '852007cdda3b405757c088e160798b40', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4CWANNSKNF2X5JEJ4', 'T-100', '2026-05-17 18:47:23', '2026-05-17 19:47:50', NULL, '3edd0e73ac89116392d4aab4e8180c6a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4CWANNSKNF2X5JEJ4', 'T-100', '2026-05-17 18:47:23', '2026-05-17 19:47:50', NULL, '3edd0e73ac89116392d4aab4e8180c6a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM63H3CXCKB13E3RNHW', 'T-105', '2026-05-17 18:47:47', '2026-05-17 19:56:28', NULL, '0f673c39dc8c450947f34c86e743f8cc', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM63H3CXCKB13E3RNHW', 'T-105', '2026-05-17 18:47:47', '2026-05-17 19:56:28', NULL, '0f673c39dc8c450947f34c86e743f8cc', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM40PV7G53JMHHNYPYG', 'T-108', '2026-05-17 18:47:59', '2026-05-17 20:05:38', NULL, 'f023344206a267eefd5d2c453d3483c9', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM40PV7G53JMHHNYPYG', 'T-108', '2026-05-17 18:47:59', '2026-05-17 20:05:38', NULL, 'f023344206a267eefd5d2c453d3483c9', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4ZNR15BSANVX07N1R', 'T-112', '2026-05-17 18:48:20', '2026-05-17 20:11:16', NULL, '874a9bbe234acb55dfc20d72a2c5a361', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4ZNR15BSANVX07N1R', 'T-112', '2026-05-17 18:48:20', '2026-05-17 20:11:16', NULL, '874a9bbe234acb55dfc20d72a2c5a361', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4W20PVMHX1BBJ4TVW', 'T-118', '2026-05-17 20:51:47', '2026-05-17 20:53:41', NULL, 'b8fbc53c7092e7b29a869f0247cd0e38', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4W20PVMHX1BBJ4TVW', 'T-118', '2026-05-17 20:51:47', '2026-05-17 20:53:41', NULL, 'b8fbc53c7092e7b29a869f0247cd0e38', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7FG92QKNFJSCAP888', 'T-114', '2026-05-17 18:48:28', '2026-05-18 07:04:38', NULL, '2c16b22992624d00be14801c105350c9', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7FG92QKNFJSCAP888', 'T-114', '2026-05-17 18:48:28', '2026-05-18 07:04:38', NULL, '2c16b22992624d00be14801c105350c9', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7Y9KHNVRZ41VYW1YM', 'T-111', '2026-05-17 18:48:14', '2026-05-18 07:43:45', NULL, '1c12b7ea3d82ff2bc1e5680690ee0746', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7Y9KHNVRZ41VYW1YM', 'T-111', '2026-05-17 18:48:14', '2026-05-18 07:43:45', NULL, '1c12b7ea3d82ff2bc1e5680690ee0746', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5W67PPRVA8SAJXHFG', 'T-104', '2026-05-17 18:47:42', '2026-05-18 07:53:10', NULL, 'ec883c703bad46f757d38057c71336d3', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5W67PPRVA8SAJXHFG', 'T-104', '2026-05-17 18:47:42', '2026-05-18 07:53:10', NULL, 'ec883c703bad46f757d38057c71336d3', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4TTAC53CQYWDQ91H0', 'T-109', '2026-05-17 18:48:03', '2026-05-18 08:07:23', NULL, 'ed187720e362af1ff3f8cae3fd0ac828', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4TTAC53CQYWDQ91H0', 'T-109', '2026-05-17 18:48:03', '2026-05-18 08:07:23', NULL, 'ed187720e362af1ff3f8cae3fd0ac828', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM45DS16DX0NKMN9Q3G', 'T-121', '2026-05-18 08:07:23', '2026-05-18 08:22:19', NULL, 'ec1cbea6674c6fb5d365510587c082ec', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM45DS16DX0NKMN9Q3G', 'T-121', '2026-05-18 08:07:23', '2026-05-18 08:22:19', NULL, 'ec1cbea6674c6fb5d365510587c082ec', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM614M7ES54V3SETAQM', 'T-115', '2026-05-17 19:10:21', '2026-05-18 09:30:59', NULL, '640c8f8e5a67cdb44eaabd65bf21fc04', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM614M7ES54V3SETAQM', 'T-115', '2026-05-17 19:10:21', '2026-05-18 09:30:59', NULL, '640c8f8e5a67cdb44eaabd65bf21fc04', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4RJ9K19P5AX14RHRR', 'T-123', '2026-05-18 10:29:02', '2026-05-18 10:29:02', NULL, '255468e265f300a234e8456d3a0abf51', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4RJ9K19P5AX14RHRR', 'T-123', '2026-05-18 10:29:02', '2026-05-18 10:29:02', NULL, '255468e265f300a234e8456d3a0abf51', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7FXS713CKYDZ284NC', 'T-107', '2026-05-17 18:47:55', '2026-05-18 10:30:30', NULL, '4bc77250919cd4cef2fb1bfd3438a7c6', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7FXS713CKYDZ284NC', 'T-107', '2026-05-17 18:47:55', '2026-05-18 10:30:30', NULL, '4bc77250919cd4cef2fb1bfd3438a7c6', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4H5C2Z6GCBCQ85QGR', 'T-116', '2026-05-17 19:14:31', '2026-05-18 11:22:46', NULL, '972bf9cfde6de9ff37cb5cb1dcc5a2dd', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4H5C2Z6GCBCQ85QGR', 'T-116', '2026-05-17 19:14:31', '2026-05-18 11:22:46', NULL, '972bf9cfde6de9ff37cb5cb1dcc5a2dd', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM53N56Z60B4SQ5VTRG', 'T-74', '2026-05-05 12:53:22', '2026-05-18 11:51:40', NULL, '7b71c20018634be865ab843900b93eff', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM53N56Z60B4SQ5VTRG', 'T-74', '2026-05-05 12:53:22', '2026-05-18 11:51:40', NULL, '7b71c20018634be865ab843900b93eff', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4AV8YXV4NYWS2ZQYW', 'T-124', '2026-05-18 11:58:47', '2026-05-18 12:51:08', NULL, 'b272f7b62db06897d71bcee86b0aef6e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4AV8YXV4NYWS2ZQYW', 'T-124', '2026-05-18 11:58:47', '2026-05-18 12:51:08', NULL, 'b272f7b62db06897d71bcee86b0aef6e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6KY9JVRKF22GGFMXR', 'T-125', '2026-05-18 11:58:52', '2026-05-18 15:51:09', NULL, '801eba2049b8dc046ab81f731d0caef1', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6KY9JVRKF22GGFMXR', 'T-125', '2026-05-18 11:58:52', '2026-05-18 15:51:09', NULL, '801eba2049b8dc046ab81f731d0caef1', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM78E2NAM4YK3A2AV6R', 'T-126', '2026-05-18 11:58:57', '2026-05-18 16:04:29', NULL, '6bc6a6b1f009225521ace82a6616244c', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM78E2NAM4YK3A2AV6R', 'T-126', '2026-05-18 11:58:57', '2026-05-18 16:04:29', NULL, '6bc6a6b1f009225521ace82a6616244c', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7J40S0A8Q8PC0PDY8', 'T-127', '2026-05-18 11:59:02', '2026-05-19 10:03:26', NULL, '0e2e8e90772e11cfad16ee7805a58f7e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7J40S0A8Q8PC0PDY8', 'T-127', '2026-05-18 11:59:02', '2026-05-19 10:03:26', NULL, '0e2e8e90772e11cfad16ee7805a58f7e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6KEY6593FMW8Y40VC', 'T-128', '2026-05-18 11:59:06', '2026-05-19 10:06:46', NULL, '9cf26209ff598d91824d59f791b34938', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6KEY6593FMW8Y40VC', 'T-128', '2026-05-18 11:59:06', '2026-05-19 10:06:46', NULL, '9cf26209ff598d91824d59f791b34938', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM40XWGSN99DBDQDHJR', 'T-129', '2026-05-18 11:59:11', '2026-05-19 12:19:51', NULL, '618bff52db127ed5655c78c4e09f3078', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM40XWGSN99DBDQDHJR', 'T-129', '2026-05-18 11:59:11', '2026-05-19 12:19:51', NULL, '618bff52db127ed5655c78c4e09f3078', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5MW2V3QCMWKMY4VQM', 'T-130', '2026-05-18 11:59:17', '2026-05-19 12:33:52', NULL, 'ab53ef037d31eb5a977cf6fe3280e126', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5MW2V3QCMWKMY4VQM', 'T-130', '2026-05-18 11:59:17', '2026-05-19 12:33:52', NULL, 'ab53ef037d31eb5a977cf6fe3280e126', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5ZSRZARG7SXCC71NM', 'T-131', '2026-05-18 11:59:23', '2026-05-19 13:14:41', NULL, '7339bc2840f028e45e798e8bd8c9c337', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5ZSRZARG7SXCC71NM', 'T-131', '2026-05-18 11:59:23', '2026-05-19 13:14:41', NULL, '7339bc2840f028e45e798e8bd8c9c337', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM76Q97D8R01CRTTA9R', 'T-99', '2026-05-17 18:47:18', '2026-05-19 13:14:41', NULL, 'ff7b3f5bbb802d081c305d32b3330163', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM76Q97D8R01CRTTA9R', 'T-99', '2026-05-17 18:47:18', '2026-05-19 13:14:41', NULL, 'ff7b3f5bbb802d081c305d32b3330163', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM54DENVAR46RXCCQQM', 'T-119', '2026-05-18 07:43:50', '2026-05-20 07:00:06', NULL, 'd2732a32ffbc29ddca7f9eacad2d5570', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM54DENVAR46RXCCQQM', 'T-119', '2026-05-18 07:43:50', '2026-05-20 07:00:06', NULL, 'd2732a32ffbc29ddca7f9eacad2d5570', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM47ARMYK2H24KJ0DAG', 'T-120', '2026-05-18 07:53:08', '2026-05-20 16:02:35', NULL, 'fdab02033af4c3f6df800ddf3bc78198', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM47ARMYK2H24KJ0DAG', 'T-120', '2026-05-18 07:53:08', '2026-05-20 16:02:35', NULL, 'fdab02033af4c3f6df800ddf3bc78198', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM56CF9W94FSFDSBKGW', 'T-97', '2026-05-17 18:47:08', '2026-05-20 16:02:46', NULL, '84c961d85f80b8ba21fc227f7d191948', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM56CF9W94FSFDSBKGW', 'T-97', '2026-05-17 18:47:08', '2026-05-20 16:02:46', NULL, '84c961d85f80b8ba21fc227f7d191948', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6TNXTJCQBH9VADC4M', 'T-89', '2026-05-06 20:36:42', '2026-05-22 13:37:46', NULL, '7197034866b3116490b8633fd18ff01f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6TNXTJCQBH9VADC4M', 'T-89', '2026-05-06 20:36:42', '2026-05-22 13:37:46', NULL, '7197034866b3116490b8633fd18ff01f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4HGK6KR0314P2M32M', 'T-91', '2026-05-06 20:49:47', '2026-05-22 13:37:46', NULL, 'c1d096207b720c77ac05b1950dce1bcd', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4HGK6KR0314P2M32M', 'T-91', '2026-05-06 20:49:47', '2026-05-22 13:37:46', NULL, 'c1d096207b720c77ac05b1950dce1bcd', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM54N0ZDJRS7G6MP1XC', 'T-136', '2026-05-22 15:59:34', '2026-05-22 17:37:23', NULL, '24eae70edc48f10e227710ee77e94fb6', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM54N0ZDJRS7G6MP1XC', 'T-136', '2026-05-22 15:59:34', '2026-05-22 17:37:23', NULL, '24eae70edc48f10e227710ee77e94fb6', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM54G017Y29APWJTCN0', 'T-133', '2026-05-22 15:50:06', '2026-05-22 17:37:23', NULL, 'a4886b596be68f26bcf01315f2eba159', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM54G017Y29APWJTCN0', 'T-133', '2026-05-22 15:50:06', '2026-05-22 17:37:23', NULL, 'a4886b596be68f26bcf01315f2eba159', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6SRMD12DMXCX6N7DM', 'T-135', '2026-05-22 15:59:34', '2026-05-22 17:37:23', NULL, 'e18b6b13a86b6202afb93b4bae32c824', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6SRMD12DMXCX6N7DM', 'T-135', '2026-05-22 15:59:34', '2026-05-22 17:37:23', NULL, 'e18b6b13a86b6202afb93b4bae32c824', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4EQAERS4J9X9RAETR', 'T-134', '2026-05-22 15:59:34', '2026-05-22 17:55:11', NULL, '99fdef2c143698cd8dee33e5903015f5', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4EQAERS4J9X9RAETR', 'T-134', '2026-05-22 15:59:34', '2026-05-22 17:55:11', NULL, '99fdef2c143698cd8dee33e5903015f5', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6E3X5WWRS09GCDGK8', 'T-137', '2026-05-22 15:59:34', '2026-05-22 18:14:32', NULL, '0ae6c36aab9db692afc7b9de9d83b70b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6E3X5WWRS09GCDGK8', 'T-137', '2026-05-22 15:59:34', '2026-05-22 18:14:32', NULL, '0ae6c36aab9db692afc7b9de9d83b70b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4V1PZ0EK6G60699EM', 'T-138', '2026-05-22 15:59:34', '2026-05-22 21:49:09', NULL, '006e8c34ed9058294d4144ed2fd853ba', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4V1PZ0EK6G60699EM', 'T-138', '2026-05-22 15:59:34', '2026-05-22 21:49:09', NULL, '006e8c34ed9058294d4144ed2fd853ba', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM427ZFSTWJ21EBK5FG', 'T-142', '2026-05-22 22:06:59', '2026-05-22 22:18:02', NULL, '93352b90d5b8532dca21609a5e6dee2c', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM427ZFSTWJ21EBK5FG', 'T-142', '2026-05-22 22:06:59', '2026-05-22 22:18:02', NULL, '93352b90d5b8532dca21609a5e6dee2c', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6YWAC8SSGQBK31T98', 'T-143', '2026-05-22 22:31:22', '2026-05-22 22:36:09', NULL, 'd585cc1215d301735c9e207e08193e6e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6YWAC8SSGQBK31T98', 'T-143', '2026-05-22 22:31:22', '2026-05-22 22:36:09', NULL, 'd585cc1215d301735c9e207e08193e6e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4BV0CXWCT04Z81EG0', 'T-144', '2026-05-22 22:40:42', '2026-05-22 22:43:45', NULL, 'b8e257b9abde9da0c38fc15cb7d4ee41', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4BV0CXWCT04Z81EG0', 'T-144', '2026-05-22 22:40:42', '2026-05-22 22:43:45', NULL, 'b8e257b9abde9da0c38fc15cb7d4ee41', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM653J6604KYDK6RT8R', 'T-139', '2026-05-22 15:59:34', '2026-05-22 23:16:28', NULL, 'e43a27d4464ce09179016a65dc702a57', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM653J6604KYDK6RT8R', 'T-139', '2026-05-22 15:59:34', '2026-05-22 23:16:28', NULL, 'e43a27d4464ce09179016a65dc702a57', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5AVSMKD15KBJYX48W', 'T-140', '2026-05-22 15:59:34', '2026-05-22 23:31:46', NULL, '2e962cad8956dff339a9c3028ff8c83a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5AVSMKD15KBJYX48W', 'T-140', '2026-05-22 15:59:34', '2026-05-22 23:31:46', NULL, '2e962cad8956dff339a9c3028ff8c83a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM558PCHET90BBSHGTC', 'T-146', '2026-05-23 06:19:51', '2026-05-23 06:30:47', NULL, 'd575cf325d7b347a88ca11f516b1b715', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM558PCHET90BBSHGTC', 'T-146', '2026-05-23 06:19:51', '2026-05-23 06:30:47', NULL, 'd575cf325d7b347a88ca11f516b1b715', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM47FEEMHPE8J5VVBKM', 'T-147', '2026-05-23 07:03:18', '2026-05-23 07:06:54', NULL, '2b5e6b5f67000bea0097ea86986124b6', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM47FEEMHPE8J5VVBKM', 'T-147', '2026-05-23 07:03:18', '2026-05-23 07:06:54', NULL, '2b5e6b5f67000bea0097ea86986124b6', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4GDS1R8H2TW12WX7G', 'T-149', '2026-05-23 07:14:36', '2026-05-23 07:27:32', NULL, '1ffa4dc9299a04293bfa473036ed8e08', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4GDS1R8H2TW12WX7G', 'T-149', '2026-05-23 07:14:36', '2026-05-23 07:27:32', NULL, '1ffa4dc9299a04293bfa473036ed8e08', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5KN50C7A723SEKZXG', 'T-145', '2026-05-23 06:07:59', '2026-05-23 08:43:19', NULL, 'e688de6397028cc53baef88f4af4db5c', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5KN50C7A723SEKZXG', 'T-145', '2026-05-23 06:07:59', '2026-05-23 08:43:19', NULL, 'e688de6397028cc53baef88f4af4db5c', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6F9XA7F2BX9P18BR4', 'T-150', '2026-05-23 09:04:40', '2026-05-23 09:33:03', NULL, '6103463406709c57456e06226486a739', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6F9XA7F2BX9P18BR4', 'T-150', '2026-05-23 09:04:40', '2026-05-23 09:33:03', NULL, '6103463406709c57456e06226486a739', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM77GWREHKA9K45P020', 'T-151', '2026-05-23 09:52:14', '2026-05-23 10:20:12', NULL, '1ee4e62532962562e7a57316eedf0d04', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM77GWREHKA9K45P020', 'T-151', '2026-05-23 09:52:14', '2026-05-23 10:20:12', NULL, '1ee4e62532962562e7a57316eedf0d04', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7BJS5E1JJGSJ9XHG0', 'T-153', '2026-05-23 09:52:27', '2026-05-23 10:35:56', NULL, '872e6c5e27120a76b24f7c033286071e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7BJS5E1JJGSJ9XHG0', 'T-153', '2026-05-23 09:52:27', '2026-05-23 10:35:56', NULL, '872e6c5e27120a76b24f7c033286071e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6YSQYCE096R2SFRXG', 'T-152', '2026-05-23 09:52:20', '2026-05-23 10:43:52', NULL, '9ba6f625fd14bb95a31902b699e821e6', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6YSQYCE096R2SFRXG', 'T-152', '2026-05-23 09:52:20', '2026-05-23 10:43:52', NULL, '9ba6f625fd14bb95a31902b699e821e6', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5B47G9GG22N9KBNEG', 'T-156', '2026-05-23 11:15:08', '2026-05-23 12:05:19', NULL, '35180e547e94880bbe7c9f73b8b28e2c', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5B47G9GG22N9KBNEG', 'T-156', '2026-05-23 11:15:08', '2026-05-23 12:05:19', NULL, '35180e547e94880bbe7c9f73b8b28e2c', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4XM8EY708NAM1JK00', 'T-154', '2026-05-23 09:52:32', '2026-05-23 14:50:17', NULL, '45a2e199fca3eb06e286f98d5c8c2228', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4XM8EY708NAM1JK00', 'T-154', '2026-05-23 09:52:32', '2026-05-23 14:50:17', NULL, '45a2e199fca3eb06e286f98d5c8c2228', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5R9Q3T7CBMTHM2GFR', 'T-155', '2026-05-23 11:06:50', '2026-05-23 14:50:17', NULL, '578a38cb9982309cac40cd0a214d7839', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5R9Q3T7CBMTHM2GFR', 'T-155', '2026-05-23 11:06:50', '2026-05-23 14:50:17', NULL, '578a38cb9982309cac40cd0a214d7839', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6CYT7NW4WE8ZP1TXR', 'T-148', '2026-05-23 07:03:18', '2026-05-23 15:05:29', NULL, 'edd29e766c59c65f2ca3c83700ed96f0', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6CYT7NW4WE8ZP1TXR', 'T-148', '2026-05-23 07:03:18', '2026-05-23 15:05:29', NULL, 'edd29e766c59c65f2ca3c83700ed96f0', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5V9RNW2BGT5GHRTRG', 'T-141', '2026-05-22 15:59:34', '2026-05-23 20:49:44', NULL, 'c95d953ec43d43dde07d94192342c3a9', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5V9RNW2BGT5GHRTRG', 'T-141', '2026-05-22 15:59:34', '2026-05-23 20:49:44', NULL, 'c95d953ec43d43dde07d94192342c3a9', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4QZ3JJF1704AV5JCW', 'T-157', '2026-05-23 20:48:31', '2026-05-23 20:57:07', NULL, '96ab8af2d5b2835a37c23b1af6c25be1', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4QZ3JJF1704AV5JCW', 'T-157', '2026-05-23 20:48:31', '2026-05-23 20:57:07', NULL, '96ab8af2d5b2835a37c23b1af6c25be1', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6KD2DKTGHC6CF1MJ4', 'T-159', '2026-05-24 08:53:13', '2026-05-24 08:54:30', NULL, '6d88f03a4c6268aefb7ab51411e6970f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6KD2DKTGHC6CF1MJ4', 'T-159', '2026-05-24 08:53:13', '2026-05-24 08:54:30', NULL, '6d88f03a4c6268aefb7ab51411e6970f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7SPRJZ519RZK1ZPAW', 'T-161', '2026-05-24 09:24:02', '2026-05-24 09:45:07', NULL, 'e5ad416566fa75f3caf1ccf085aa2506', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7SPRJZ519RZK1ZPAW', 'T-161', '2026-05-24 09:24:02', '2026-05-24 09:45:07', NULL, 'e5ad416566fa75f3caf1ccf085aa2506', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5932T486Z1F1M6X6W', 'T-173', '2026-05-24 16:45:40', '2026-05-24 17:10:07', NULL, '0d564a0dc8adc327e3f9460c254499fa', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5932T486Z1F1M6X6W', 'T-173', '2026-05-24 16:45:40', '2026-05-24 17:10:07', NULL, '0d564a0dc8adc327e3f9460c254499fa', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4AHSN3BXZFFWS0EPM', 'T-165', '2026-05-24 16:26:15', '2026-05-25 06:29:25', NULL, '879dcc70eadbc3d29a1e6f81ee0e86d4', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4AHSN3BXZFFWS0EPM', 'T-165', '2026-05-24 16:26:15', '2026-05-25 06:29:25', NULL, '879dcc70eadbc3d29a1e6f81ee0e86d4', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7KA37YDBJ89GJ27H4', 'T-166', '2026-05-24 16:26:23', '2026-05-25 06:31:08', NULL, '6a6a0ba97d6331ac3441060ec28197db', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7KA37YDBJ89GJ27H4', 'T-166', '2026-05-24 16:26:23', '2026-05-25 06:31:08', NULL, '6a6a0ba97d6331ac3441060ec28197db', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7K30Y9WAYZ3D330YR', 'T-175', '2026-05-25 07:11:09', '2026-05-25 07:25:02', NULL, '1d7a94fb62083c7c4390103f5bf29786', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7K30Y9WAYZ3D330YR', 'T-175', '2026-05-25 07:11:09', '2026-05-25 07:25:02', NULL, '1d7a94fb62083c7c4390103f5bf29786', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6RP0Q312AZJ8S1Y6R', 'T-177', '2026-05-25 07:11:22', '2026-05-25 07:25:02', NULL, '59a180929bd8894b53a761b2dda7b4f1', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6RP0Q312AZJ8S1Y6R', 'T-177', '2026-05-25 07:11:22', '2026-05-25 07:25:02', NULL, '59a180929bd8894b53a761b2dda7b4f1', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7AXEWDKD4VQNQCACM', 'T-176', '2026-05-25 07:11:16', '2026-05-25 07:27:57', NULL, '231d303368c603a6e01a6da02802fbc4', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7AXEWDKD4VQNQCACM', 'T-176', '2026-05-25 07:11:16', '2026-05-25 07:27:57', NULL, '231d303368c603a6e01a6da02802fbc4', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4VNVEAEYBX3S9Z8Q8', 'T-178', '2026-05-25 08:10:10', '2026-05-25 08:21:46', NULL, '3f7aae66c9e487bef74fd4d93b304d12', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4VNVEAEYBX3S9Z8Q8', 'T-178', '2026-05-25 08:10:10', '2026-05-25 08:21:46', NULL, '3f7aae66c9e487bef74fd4d93b304d12', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4DTGYPAB29MRDN000', 'T-179', '2026-05-25 08:10:18', '2026-05-25 08:26:21', NULL, '826c15b06fe0aaaf660e31042fe371bd', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4DTGYPAB29MRDN000', 'T-179', '2026-05-25 08:10:18', '2026-05-25 08:26:21', NULL, '826c15b06fe0aaaf660e31042fe371bd', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM48P8T23ZPR0BRK6PR', 'T-169', '2026-05-24 16:26:49', '2026-05-25 12:12:29', NULL, '99d40776974ced8e57efaa135df3ea9f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM48P8T23ZPR0BRK6PR', 'T-169', '2026-05-24 16:26:49', '2026-05-25 12:12:29', NULL, '99d40776974ced8e57efaa135df3ea9f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM654XV2TG4K0RVV1CW', 'T-170', '2026-05-24 16:27:01', '2026-05-25 19:38:16', NULL, 'd4a19feb40528dd6d22186c442c46890', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM654XV2TG4K0RVV1CW', 'T-170', '2026-05-24 16:27:01', '2026-05-25 19:38:16', NULL, 'd4a19feb40528dd6d22186c442c46890', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4R8YY69YAARCVE4AC', 'T-160', '2026-05-24 09:13:42', '2026-05-30 11:05:56', NULL, '87a62aa99c4c3e3be11c031c5667ff68', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4R8YY69YAARCVE4AC', 'T-160', '2026-05-24 09:13:42', '2026-05-30 11:05:56', NULL, '87a62aa99c4c3e3be11c031c5667ff68', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7G7MK8MP3BGQC36HG', 'T-167', '2026-05-24 16:26:30', '2026-05-30 11:05:56', NULL, 'a7343c529fc0c766f4d7c2a9530614fe', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7G7MK8MP3BGQC36HG', 'T-167', '2026-05-24 16:26:30', '2026-05-30 11:05:56', NULL, 'a7343c529fc0c766f4d7c2a9530614fe', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM78W48QX3JZP0QYAVW', 'T-168', '2026-05-24 16:26:39', '2026-05-30 11:44:28', NULL, '65bd7ae87632b0d65777a26af0bb31f2', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM78W48QX3JZP0QYAVW', 'T-168', '2026-05-24 16:26:39', '2026-05-30 11:44:28', NULL, '65bd7ae87632b0d65777a26af0bb31f2', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6FMAHXM1XAHHCQC60', 'T-171', '2026-05-24 16:27:09', '2026-05-30 21:11:26', NULL, '556df973d835841f7e8ae0c8cd9dd310', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6FMAHXM1XAHHCQC60', 'T-171', '2026-05-24 16:27:09', '2026-05-30 21:11:26', NULL, '556df973d835841f7e8ae0c8cd9dd310', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7ZB63YYNFXM9DQNRR', 'T-174', '2026-05-24 17:11:17', '2026-05-30 21:11:26', NULL, 'db290b95db28db6b5a90d880d8a36fdb', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7ZB63YYNFXM9DQNRR', 'T-174', '2026-05-24 17:11:17', '2026-05-30 21:11:26', NULL, 'db290b95db28db6b5a90d880d8a36fdb', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM71N3YMS82BAYD3M9R', 'T-172', '2026-05-24 16:27:16', '2026-05-30 21:34:56', NULL, '8fca1700a4bf028e071cf30e845ee8f1', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM71N3YMS82BAYD3M9R', 'T-172', '2026-05-24 16:27:16', '2026-05-30 21:34:56', NULL, '8fca1700a4bf028e071cf30e845ee8f1', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6V6TKRPA106D5SMMM', 'T-180', '2026-05-25 09:15:58', '2026-05-31 08:49:07', NULL, '412af567b67756da2e6b438c6a4bfd45', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6V6TKRPA106D5SMMM', 'T-180', '2026-05-25 09:15:58', '2026-05-31 08:49:07', NULL, '412af567b67756da2e6b438c6a4bfd45', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7WE0SD9N4HCP9BB64', 'T-183', '2026-05-25 09:26:40', '2026-05-31 09:30:11', NULL, 'f09d4e58d36e3049bbcf5d92df301530', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7WE0SD9N4HCP9BB64', 'T-183', '2026-05-25 09:26:40', '2026-05-31 09:30:11', NULL, 'f09d4e58d36e3049bbcf5d92df301530', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM55DZN2RFEVP6CG48G', 'T-184', '2026-05-30 11:42:53', '2026-05-31 10:17:09', NULL, '7f2e958614fa540d1087d3f1c84568df', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM55DZN2RFEVP6CG48G', 'T-184', '2026-05-30 11:42:53', '2026-05-31 10:17:09', NULL, '7f2e958614fa540d1087d3f1c84568df', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM52PRNJM86A1DZTQ1C', 'T-185', '2026-05-30 21:34:26', '2026-05-31 10:22:02', NULL, 'd7d14700bc8fb0164e6e2852b7a358cd', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM52PRNJM86A1DZTQ1C', 'T-185', '2026-05-30 21:34:26', '2026-05-31 10:22:02', NULL, 'd7d14700bc8fb0164e6e2852b7a358cd', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5HM3N07VB3RPFJCFM', 'T-164', '2026-05-24 16:26:05', '2026-05-31 10:22:03', NULL, '8bc4ad2dbf63176d9674cd014c6cce7b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5HM3N07VB3RPFJCFM', 'T-164', '2026-05-24 16:26:05', '2026-05-31 10:22:03', NULL, '8bc4ad2dbf63176d9674cd014c6cce7b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4TDSA2PDCV814E3YW', 'T-95', '2026-05-08 10:48:59', '2026-05-31 11:20:21', NULL, '628386f31fcfb4e96eac7b503ab2eb4b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4TDSA2PDCV814E3YW', 'T-95', '2026-05-08 10:48:59', '2026-05-31 11:20:21', NULL, '628386f31fcfb4e96eac7b503ab2eb4b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5316HVGDYD2W0DC50', 'T-162', '2026-05-24 09:29:07', '2026-05-31 14:17:22', NULL, '46d071266f94b404760832f3c2d88927', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5316HVGDYD2W0DC50', 'T-162', '2026-05-24 09:29:07', '2026-05-31 14:17:22', NULL, '46d071266f94b404760832f3c2d88927', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM514YJBF8AY8Q4N7Q4', 'T-188', '2026-05-31 11:38:28', '2026-05-31 14:17:22', NULL, '7328143d32f30fc412c22b5d76de92a9', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM514YJBF8AY8Q4N7Q4', 'T-188', '2026-05-31 11:38:28', '2026-05-31 14:17:22', NULL, '7328143d32f30fc412c22b5d76de92a9', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4GVWHMRTMQYRTRKD4', 'T-187', '2026-05-31 11:38:20', '2026-05-31 14:17:22', NULL, 'ce42be5c4b71e4c155b26e22506045f4', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4GVWHMRTMQYRTRKD4', 'T-187', '2026-05-31 11:38:20', '2026-05-31 14:17:22', NULL, 'ce42be5c4b71e4c155b26e22506045f4', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4DAQ2CEFESG9JGMZ8', 'T-192', '2026-05-31 12:08:42', '2026-05-31 14:46:39', NULL, '6bd69db546e3d3aadb77b5c289db817a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4DAQ2CEFESG9JGMZ8', 'T-192', '2026-05-31 12:08:42', '2026-05-31 14:46:39', NULL, '6bd69db546e3d3aadb77b5c289db817a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6S7FDAXQX32JNCSFG', 'T-186', '2026-05-31 11:37:34', '2026-05-31 16:40:19', NULL, 'eed0473280a7c582289f0fcaa6bf6dd5', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6S7FDAXQX32JNCSFG', 'T-186', '2026-05-31 11:37:34', '2026-05-31 16:40:19', NULL, 'eed0473280a7c582289f0fcaa6bf6dd5', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM709YPWECH1E66XXD4', 'T-193', '2026-05-31 16:12:42', '2026-05-31 17:26:25', NULL, 'ffbdde83a1cd6bbe9046f686705b2e15', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM709YPWECH1E66XXD4', 'T-193', '2026-05-31 16:12:42', '2026-05-31 17:26:25', NULL, 'ffbdde83a1cd6bbe9046f686705b2e15', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6YYG4X5R1GX97TJB4', 'T-52', '2026-04-23 20:32:06', '2026-05-31 18:54:02', NULL, '1e34fa00e15b0ada663e117c7493ca69', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6YYG4X5R1GX97TJB4', 'T-52', '2026-04-23 20:32:06', '2026-05-31 18:54:02', NULL, '1e34fa00e15b0ada663e117c7493ca69', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4QPGVP54EKJPCNQQM', 'T-51', '2026-04-23 20:32:06', '2026-05-31 18:54:02', NULL, 'cc6cf69d394f87a29c685b27ec13155e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4QPGVP54EKJPCNQQM', 'T-51', '2026-04-23 20:32:06', '2026-05-31 18:54:02', NULL, 'cc6cf69d394f87a29c685b27ec13155e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM452XPSG99PA60ZZ48', 'T-53', '2026-04-23 20:32:06', '2026-05-31 19:41:13', NULL, '22e98aa4226d3e9979abd7b7cdf7b68a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM452XPSG99PA60ZZ48', 'T-53', '2026-04-23 20:32:06', '2026-05-31 19:41:13', NULL, '22e98aa4226d3e9979abd7b7cdf7b68a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
|||||||
@@ -1,179 +1,340 @@
|
|||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7MFNNCC0MMY2TCNRM', 'T-194', '2026-06-01 06:49:25', '2026-06-01 06:49:47', NULL, 'c4ed6eb84383fb6052a61f94e37c98c9', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7MFNNCC0MMY2TCNRM', 'T-194', '2026-06-01 06:49:25', '2026-06-01 06:49:47', NULL, 'c4ed6eb84383fb6052a61f94e37c98c9', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4M2Z9YZ0SA81E5Q08', 'T-195', '2026-06-01 06:56:05', '2026-06-01 07:08:16', NULL, '6d199187494f2f942598092f9743285f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4M2Z9YZ0SA81E5Q08', 'T-195', '2026-06-01 06:56:05', '2026-06-01 07:08:16', NULL, '6d199187494f2f942598092f9743285f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6NTYAB8K6T50F8W00', 'T-196', '2026-06-01 08:58:10', '2026-06-01 10:45:14', NULL, '57fadff50bee964e4d821507d0e6e79b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6NTYAB8K6T50F8W00', 'T-196', '2026-06-01 08:58:10', '2026-06-01 10:45:14', NULL, '57fadff50bee964e4d821507d0e6e79b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6HQXNNF05GXWK7BWM', 'T-198', '2026-06-01 11:11:32', '2026-06-01 11:31:39', NULL, 'f203d6089bcb5f23d81e4c3cf67b3d33', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6HQXNNF05GXWK7BWM', 'T-198', '2026-06-01 11:11:32', '2026-06-01 11:31:39', NULL, 'f203d6089bcb5f23d81e4c3cf67b3d33', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM68APBCQTMGJAZ2B9C', 'T-199', '2026-06-01 11:38:32', '2026-06-01 12:35:04', NULL, '6fda1ce6b9f1ea55f001f1840fef1f7a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM68APBCQTMGJAZ2B9C', 'T-199', '2026-06-01 11:38:32', '2026-06-01 12:35:04', NULL, '6fda1ce6b9f1ea55f001f1840fef1f7a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4RAKSX59W1HJCZ1M8', 'T-200', '2026-06-01 14:04:00', '2026-06-01 14:04:24', NULL, 'b2c666f841d2546d0e6f150dec9e901b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4RAKSX59W1HJCZ1M8', 'T-200', '2026-06-01 14:04:00', '2026-06-01 14:04:24', NULL, 'b2c666f841d2546d0e6f150dec9e901b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM57GY6PTG78SD3961M', 'T-201', '2026-06-01 14:25:59', '2026-06-01 14:45:39', NULL, '289f9f811f27bad8b3f01acda2651b4b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM57GY6PTG78SD3961M', 'T-201', '2026-06-01 14:25:59', '2026-06-01 14:45:39', NULL, '289f9f811f27bad8b3f01acda2651b4b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7G8QBJ2PNQ0VREN24', 'T-197', '2026-06-01 08:58:19', '2026-06-01 16:36:38', NULL, 'a29f2ef4fa8bc86eceff40c324d613d0', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7G8QBJ2PNQ0VREN24', 'T-197', '2026-06-01 08:58:19', '2026-06-01 16:36:38', NULL, 'a29f2ef4fa8bc86eceff40c324d613d0', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5A3984KFPD4NKRG6M', 'T-202', '2026-06-01 16:48:31', '2026-06-01 16:48:56', NULL, '726f989a61da913e9f41f3353e453541', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5A3984KFPD4NKRG6M', 'T-202', '2026-06-01 16:48:31', '2026-06-01 16:48:56', NULL, '726f989a61da913e9f41f3353e453541', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM643F7Z648KNFPT7GR', 'T-203', '2026-06-01 16:48:31', '2026-06-01 16:48:56', NULL, '736af2dbfdf6cfbc8d2683c8e0feb063', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM643F7Z648KNFPT7GR', 'T-203', '2026-06-01 16:48:31', '2026-06-01 16:48:56', NULL, '736af2dbfdf6cfbc8d2683c8e0feb063', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM65R8CNFNE1MA5GGR0', 'T-204', '2026-06-01 18:48:19', '2026-06-01 18:51:08', NULL, '7685b5bd09a25bb7094a7458f292e81b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM65R8CNFNE1MA5GGR0', 'T-204', '2026-06-01 18:48:19', '2026-06-01 18:51:08', NULL, '7685b5bd09a25bb7094a7458f292e81b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6M83TTXHRXESFZY14', 'T-207', '2026-06-01 18:48:47', '2026-06-01 18:59:19', NULL, '0fd6c0e9537080a0b8ab85f351161542', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6M83TTXHRXESFZY14', 'T-207', '2026-06-01 18:48:47', '2026-06-01 18:59:19', NULL, '0fd6c0e9537080a0b8ab85f351161542', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4PH1J6ENYT4PJZRHG', 'T-205', '2026-06-01 18:48:27', '2026-06-01 19:12:01', NULL, 'e874c6bf6c97dae25404d6f1044f9c53', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4PH1J6ENYT4PJZRHG', 'T-205', '2026-06-01 18:48:27', '2026-06-01 19:12:01', NULL, 'e874c6bf6c97dae25404d6f1044f9c53', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5REFZXMY8ESWN0Z90', 'T-206', '2026-06-01 18:48:40', '2026-06-01 19:27:18', NULL, 'cdf5b34234372c3de0ef0c3caecabed2', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5REFZXMY8ESWN0Z90', 'T-206', '2026-06-01 18:48:40', '2026-06-01 19:27:18', NULL, 'cdf5b34234372c3de0ef0c3caecabed2', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4C2PSN2GVJY9JDSZG', 'T-210', '2026-06-02 18:13:52', '2026-06-03 09:00:37', NULL, '1281485b320f6c146f8af2519c0c02f3', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4C2PSN2GVJY9JDSZG', 'T-210', '2026-06-02 18:13:52', '2026-06-03 09:00:37', NULL, '1281485b320f6c146f8af2519c0c02f3', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM48QJV4N7J62436GC0', 'T-213', '2026-06-02 18:13:52', '2026-06-03 09:00:37', NULL, 'ac6cf78658e8a9ddfee7573e125377ed', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM48QJV4N7J62436GC0', 'T-213', '2026-06-02 18:13:52', '2026-06-03 09:00:37', NULL, 'ac6cf78658e8a9ddfee7573e125377ed', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7171NRB1T82TGP5RG', 'T-211', '2026-06-02 18:13:52', '2026-06-03 09:00:37', NULL, 'bf74e45672e065ef2aa21ce85c341bb0', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7171NRB1T82TGP5RG', 'T-211', '2026-06-02 18:13:52', '2026-06-03 09:00:37', NULL, 'bf74e45672e065ef2aa21ce85c341bb0', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM54WTNQDMYT0AVR4WM', 'T-224', '2026-06-02 18:13:52', '2026-06-03 09:05:50', NULL, '16525f2ae7035719b319a6f579d5e316', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM54WTNQDMYT0AVR4WM', 'T-224', '2026-06-02 18:13:52', '2026-06-03 09:05:50', NULL, '16525f2ae7035719b319a6f579d5e316', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4TP6KXTB1GHKBW1G4', 'T-215', '2026-06-02 18:13:52', '2026-06-03 09:18:28', NULL, '4fcb599f4b489ac8050770416737295d', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4TP6KXTB1GHKBW1G4', 'T-215', '2026-06-02 18:13:52', '2026-06-03 09:18:28', NULL, '4fcb599f4b489ac8050770416737295d', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7WYF8ESBSGAQF1S48', 'T-217', '2026-06-02 18:13:52', '2026-06-03 09:18:28', NULL, '682a13f3d6e396600a5d51d38e9508d7', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7WYF8ESBSGAQF1S48', 'T-217', '2026-06-02 18:13:52', '2026-06-03 09:18:28', NULL, '682a13f3d6e396600a5d51d38e9508d7', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM51CNEJP52P79RDVJW', 'T-216', '2026-06-02 18:13:52', '2026-06-03 09:18:28', NULL, 'e89cf8d8a6c65f6c47ef73aa0f1a8d7d', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM51CNEJP52P79RDVJW', 'T-216', '2026-06-02 18:13:52', '2026-06-03 09:18:28', NULL, 'e89cf8d8a6c65f6c47ef73aa0f1a8d7d', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM78J2H2S0R79SSSPW8', 'T-214', '2026-06-02 18:13:52', '2026-06-03 09:18:38', NULL, '32ca757e5489e190af0dae4297b200d7', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM78J2H2S0R79SSSPW8', 'T-214', '2026-06-02 18:13:52', '2026-06-03 09:18:38', NULL, '32ca757e5489e190af0dae4297b200d7', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7XZQJAK31WRVQ0HGW', 'T-228', '2026-06-03 09:49:35', '2026-06-03 10:02:02', NULL, 'ce3d4e957ec8cf656f8f022e518bf8d0', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7XZQJAK31WRVQ0HGW', 'T-228', '2026-06-03 09:49:35', '2026-06-03 10:02:02', NULL, 'ce3d4e957ec8cf656f8f022e518bf8d0', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7SA9TEX5CNMTG67MW', 'T-163', '2026-05-24 09:42:44', '2026-06-03 10:05:55', NULL, 'abed11805979ce7f3d996679ad7007a4', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7SA9TEX5CNMTG67MW', 'T-163', '2026-05-24 09:42:44', '2026-06-03 10:05:55', NULL, 'abed11805979ce7f3d996679ad7007a4', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5PFAYE4XH7WV6VDW8', 'T-227', '2026-06-03 09:48:23', '2026-06-03 10:09:26', NULL, '99368eee1c22ea3cf782b52159c04dc9', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5PFAYE4XH7WV6VDW8', 'T-227', '2026-06-03 09:48:23', '2026-06-03 10:09:26', NULL, '99368eee1c22ea3cf782b52159c04dc9', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM68T660K07YH3X5DH0', 'T-229', '2026-06-03 09:51:28', '2026-06-03 10:09:26', NULL, '9d77e30754feb77e0a64a4aa5d47f668', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM68T660K07YH3X5DH0', 'T-229', '2026-06-03 09:51:28', '2026-06-03 10:09:26', NULL, '9d77e30754feb77e0a64a4aa5d47f668', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6Y5SET5WGSS2W78F8', 'T-219', '2026-06-02 18:13:52', '2026-06-03 10:31:10', NULL, 'fae2d0c2950c6f4050c70e7c3c07a525', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6Y5SET5WGSS2W78F8', 'T-219', '2026-06-02 18:13:52', '2026-06-03 10:31:10', NULL, 'fae2d0c2950c6f4050c70e7c3c07a525', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6EGSD0SB7NYNSP1BM', 'T-220', '2026-06-02 18:13:52', '2026-06-03 10:59:25', NULL, '3c812d20f5da80c0b936cb59edd2704f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6EGSD0SB7NYNSP1BM', 'T-220', '2026-06-02 18:13:52', '2026-06-03 10:59:25', NULL, '3c812d20f5da80c0b936cb59edd2704f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM67ET3VQP90WRXVSMG', 'T-181', '2026-05-25 09:16:05', '2026-06-03 11:41:17', NULL, '045b971616418029b63a850050eef8a5', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM67ET3VQP90WRXVSMG', 'T-181', '2026-05-25 09:16:05', '2026-06-03 11:41:17', NULL, '045b971616418029b63a850050eef8a5', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM758PXMJH16PA3JHFW', 'T-221', '2026-06-02 18:13:52', '2026-06-03 11:50:02', NULL, '9e906306ef56b2c22724d0b72f14ce2d', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM758PXMJH16PA3JHFW', 'T-221', '2026-06-02 18:13:52', '2026-06-03 11:50:02', NULL, '9e906306ef56b2c22724d0b72f14ce2d', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7AMEYEBTF8YGJ4BVG', 'T-218', '2026-06-02 18:13:52', '2026-06-03 11:50:08', NULL, '9c2a9480a37df7681fe4388e27345573', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7AMEYEBTF8YGJ4BVG', 'T-218', '2026-06-02 18:13:52', '2026-06-03 11:50:08', NULL, '9c2a9480a37df7681fe4388e27345573', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6GJRWZVHZF24TPPS4', 'T-226', '2026-06-03 09:37:54', '2026-06-03 11:50:23', NULL, '6bf4765285f29d4c8fce8d71472bae0c', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6GJRWZVHZF24TPPS4', 'T-226', '2026-06-03 09:37:54', '2026-06-03 11:50:23', NULL, '6bf4765285f29d4c8fce8d71472bae0c', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM427BVZYN6MD7ZZX74', 'T-231', '2026-06-03 13:17:32', '2026-06-03 13:30:05', NULL, 'd6eb4f7458f0d1c72432b87a23aa60e3', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM427BVZYN6MD7ZZX74', 'T-231', '2026-06-03 13:17:32', '2026-06-03 13:30:05', NULL, 'd6eb4f7458f0d1c72432b87a23aa60e3', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5BJCK5YG3R0NEEF70', 'T-232', '2026-06-03 13:29:49', '2026-06-03 13:41:42', NULL, 'f255d56c3872bf6a210734e127a4a4bd', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5BJCK5YG3R0NEEF70', 'T-232', '2026-06-03 13:29:49', '2026-06-03 13:41:42', NULL, 'f255d56c3872bf6a210734e127a4a4bd', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5JR6QZDMKE167C4MR', 'T-82', '2026-05-06 08:30:15', '2026-06-03 14:56:07', NULL, 'd2669b112125f4f76041885296f5d315', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5JR6QZDMKE167C4MR', 'T-82', '2026-05-06 08:30:15', '2026-06-03 14:56:07', NULL, 'd2669b112125f4f76041885296f5d315', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM492DTRZJK9CGQPGDC', 'T-234', '2026-06-03 13:49:44', '2026-06-03 15:04:07', NULL, '92a7cabc855b76f429217cc65fcfa308', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM492DTRZJK9CGQPGDC', 'T-234', '2026-06-03 13:49:44', '2026-06-03 15:04:07', NULL, '92a7cabc855b76f429217cc65fcfa308', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5GH6VP8TZA95NMYK0', 'T-230', '2026-06-03 11:15:39', '2026-06-03 15:17:33', NULL, 'eec8da81c7180e8f301196514ba54e3b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5GH6VP8TZA95NMYK0', 'T-230', '2026-06-03 11:15:39', '2026-06-03 15:17:33', NULL, 'eec8da81c7180e8f301196514ba54e3b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM46ANXPW02XGD3D3NG', 'T-237', '2026-06-03 15:43:45', '2026-06-03 21:29:47', NULL, 'f9b1b279c9292d892ac07b7f4ea7cef8', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM46ANXPW02XGD3D3NG', 'T-237', '2026-06-03 15:43:45', '2026-06-03 21:29:47', NULL, 'f9b1b279c9292d892ac07b7f4ea7cef8', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4W624VD4JW1GHDHAR', 'T-182', '2026-05-25 09:26:31', '2026-06-04 12:00:09', NULL, '35ccb60111678fbc43644460a31f1d61', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4W624VD4JW1GHDHAR', 'T-182', '2026-05-25 09:26:31', '2026-06-04 12:00:09', NULL, '35ccb60111678fbc43644460a31f1d61', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM56FKPV4WSPWA0KMB4', 'T-189', '2026-05-31 11:38:36', '2026-06-04 12:00:09', NULL, '3759a2e27d13bddbcc19ed9a4fffef9a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM56FKPV4WSPWA0KMB4', 'T-189', '2026-05-31 11:38:36', '2026-06-04 12:00:09', NULL, '3759a2e27d13bddbcc19ed9a4fffef9a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5V7GHH42RHV04DPTR', 'T-65', '2026-04-24 06:34:16', '2026-06-04 12:00:09', NULL, '544a078f04d5c926a47cbfdacb4e3e2f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5V7GHH42RHV04DPTR', 'T-65', '2026-04-24 06:34:16', '2026-06-04 12:00:09', NULL, '544a078f04d5c926a47cbfdacb4e3e2f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5BWXW61EVYGMZD47G', 'T-191', '2026-05-31 11:58:19', '2026-06-04 12:00:09', NULL, 'd186513cc0783306b2c4e1b2e789dff7', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5BWXW61EVYGMZD47G', 'T-191', '2026-05-31 11:58:19', '2026-06-04 12:00:09', NULL, 'd186513cc0783306b2c4e1b2e789dff7', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5ABRPK2SPW8VY7RP4', 'T-190', '2026-05-31 11:38:42', '2026-06-04 12:00:09', NULL, 'fac1c8383ac95413e8885f8ee64b0d54', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5ABRPK2SPW8VY7RP4', 'T-190', '2026-05-31 11:38:42', '2026-06-04 12:00:09', NULL, 'fac1c8383ac95413e8885f8ee64b0d54', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM41S6RRTMTY9TYZA50', 'T-122', '2026-05-18 09:06:59', '2026-06-05 13:08:05', NULL, '600101f09173e61159a24ed44e34dd71', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM41S6RRTMTY9TYZA50', 'T-122', '2026-05-18 09:06:59', '2026-06-05 13:08:05', NULL, '600101f09173e61159a24ed44e34dd71', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM66TK8TQ1X5T9GK6V0', 'T-42', '2026-04-22 21:03:40', '2026-06-05 15:17:09', NULL, '223a9820685b3da2a6a6e19cf6ad036b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM66TK8TQ1X5T9GK6V0', 'T-42', '2026-04-22 21:03:40', '2026-06-05 15:17:09', NULL, '223a9820685b3da2a6a6e19cf6ad036b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5WT3BHB8JZY77G5AW', 'T-243', '2026-06-05 15:14:25', '2026-06-05 15:17:09', NULL, 'd82988ff85cd644376a13f49e406138f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5WT3BHB8JZY77G5AW', 'T-243', '2026-06-05 15:14:25', '2026-06-05 15:17:09', NULL, 'd82988ff85cd644376a13f49e406138f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4KPN4VK4EZP013NNG', 'T-244', '2026-06-05 15:21:10', '2026-06-05 15:24:35', NULL, 'f375c96bfd96b9cdd89db0cd046318f3', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4KPN4VK4EZP013NNG', 'T-244', '2026-06-05 15:21:10', '2026-06-05 15:24:35', NULL, 'f375c96bfd96b9cdd89db0cd046318f3', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5YYY4FVPX9KRVHCMC', 'T-50', '2026-04-23 20:31:48', '2026-06-05 21:12:23', NULL, '581605b67cbab29fdcddbac46154308a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5YYY4FVPX9KRVHCMC', 'T-50', '2026-04-23 20:31:48', '2026-06-05 21:12:23', NULL, '581605b67cbab29fdcddbac46154308a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM66DNEK5FS9C0T4J5R', 'T-245', '2026-06-05 21:20:00', '2026-06-05 21:24:52', NULL, '577902ab47810d0f848f48c8bf9b3196', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM66DNEK5FS9C0T4J5R', 'T-245', '2026-06-05 21:20:00', '2026-06-05 21:24:52', NULL, '577902ab47810d0f848f48c8bf9b3196', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6DH7C6GQN9WNKQNXR', 'T-246', '2026-06-05 21:28:44', '2026-06-05 21:29:50', NULL, '4ce06c5b0b8a09d452934ae8ba1e5c0b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6DH7C6GQN9WNKQNXR', 'T-246', '2026-06-05 21:28:44', '2026-06-05 21:29:50', NULL, '4ce06c5b0b8a09d452934ae8ba1e5c0b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6QCYT7JBF352YVJ48', 'T-247', '2026-06-05 21:28:48', '2026-06-05 21:30:04', NULL, 'c2fbcdc7eda67938f8d35f64a92782b4', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6QCYT7JBF352YVJ48', 'T-247', '2026-06-05 21:28:48', '2026-06-05 21:30:04', NULL, 'c2fbcdc7eda67938f8d35f64a92782b4', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5F4D2Q363QF7V40K8', 'T-239', '2026-06-03 21:41:58', '2026-06-06 06:44:40', NULL, '7312cd1c56d3c8d60625df7712a7deb4', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5F4D2Q363QF7V40K8', 'T-239', '2026-06-03 21:41:58', '2026-06-06 06:44:40', NULL, '7312cd1c56d3c8d60625df7712a7deb4', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5F2GC0ABFFVAH34EC', 'T-238', '2026-06-03 21:11:40', '2026-06-06 07:24:00', NULL, 'a724281049b28271d21c87776313dd72', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5F2GC0ABFFVAH34EC', 'T-238', '2026-06-03 21:11:40', '2026-06-06 07:24:00', NULL, 'a724281049b28271d21c87776313dd72', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7ZQNDVPAPFSD9KYS4', 'T-251', '2026-06-06 07:40:43', '2026-06-06 07:40:43', NULL, '9f010efd2f1b44840ff0af4d3723a4af', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7ZQNDVPAPFSD9KYS4', 'T-251', '2026-06-06 07:40:43', '2026-06-06 07:40:43', NULL, '9f010efd2f1b44840ff0af4d3723a4af', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4BVE5EYM92CWGSXA4', 'T-250', '2026-06-06 07:26:50', '2026-06-06 07:49:08', NULL, 'a8c1c3f7d308c4fe005fb998b7ec6730', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4BVE5EYM92CWGSXA4', 'T-250', '2026-06-06 07:26:50', '2026-06-06 07:49:08', NULL, 'a8c1c3f7d308c4fe005fb998b7ec6730', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7JXD3FKW91934D0W0', 'T-249', '2026-06-06 07:21:17', '2026-06-06 08:21:40', NULL, '9f43580f953cac1a27dab6e0ac2deece', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7JXD3FKW91934D0W0', 'T-249', '2026-06-06 07:21:17', '2026-06-06 08:21:40', NULL, '9f43580f953cac1a27dab6e0ac2deece', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM70TW38E78FFXDHYAC', 'T-248', '2026-06-06 07:21:17', '2026-06-06 08:31:25', NULL, '577fda356a95641dd39c28a716227d1a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM70TW38E78FFXDHYAC', 'T-248', '2026-06-06 07:21:17', '2026-06-06 08:31:25', NULL, '577fda356a95641dd39c28a716227d1a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5NEXC0P46NJHACNM0', 'T-233', '2026-06-03 13:29:59', '2026-06-06 09:20:02', NULL, '4cea7def08ae19b77ecfdd04b11f4b5a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5NEXC0P46NJHACNM0', 'T-233', '2026-06-03 13:29:59', '2026-06-06 09:20:02', NULL, '4cea7def08ae19b77ecfdd04b11f4b5a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM78Q3VYWSE830CTVB4', 'T-212', '2026-06-02 18:13:52', '2026-06-06 10:02:03', NULL, '75bc38afe04d24ff77c2b55d9b764fe1', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM78Q3VYWSE830CTVB4', 'T-212', '2026-06-02 18:13:52', '2026-06-06 10:02:03', NULL, '75bc38afe04d24ff77c2b55d9b764fe1', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4QYYKHPQ03H3QD61W', 'T-209', '2026-06-02 18:13:52', '2026-06-06 10:02:06', NULL, '4f782ec2f1fb76eea268247cf4cd75a0', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4QYYKHPQ03H3QD61W', 'T-209', '2026-06-02 18:13:52', '2026-06-06 10:02:06', NULL, '4f782ec2f1fb76eea268247cf4cd75a0', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4K2AAPK52Y8BEJ3YR', 'T-257', '2026-06-06 14:01:03', '2026-06-06 18:58:25', NULL, 'd79886881baf9d88ff31ec2970da2712', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4K2AAPK52Y8BEJ3YR', 'T-257', '2026-06-06 14:01:03', '2026-06-06 18:58:25', NULL, 'd79886881baf9d88ff31ec2970da2712', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5KYAV8TMH3Y3FPRSR', 'T-23', '2026-04-22 14:08:40', '2026-06-06 19:06:30', NULL, '9b456adde02b184d5d46652aac210af9', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5KYAV8TMH3Y3FPRSR', 'T-23', '2026-04-22 14:08:40', '2026-06-06 19:06:30', NULL, '9b456adde02b184d5d46652aac210af9', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM72ACQSDBJTKRBC58W', 'T-223', '2026-06-02 18:13:52', '2026-06-06 19:24:44', NULL, '7909a9620aa2a05d6a02b36f030f3641', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM72ACQSDBJTKRBC58W', 'T-223', '2026-06-02 18:13:52', '2026-06-06 19:24:44', NULL, '7909a9620aa2a05d6a02b36f030f3641', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM620F5ENRYNT9S0JDW', 'T-222', '2026-06-02 18:13:52', '2026-06-06 19:24:44', NULL, 'b58b0643ed78d32df526e765a076b2eb', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM620F5ENRYNT9S0JDW', 'T-222', '2026-06-02 18:13:52', '2026-06-06 19:24:44', NULL, 'b58b0643ed78d32df526e765a076b2eb', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5DYC7CRP8TMHADW8W', 'T-225', '2026-06-02 18:13:52', '2026-06-06 19:37:47', NULL, '6d2670282a9f66635c2fccaa20162209', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5DYC7CRP8TMHADW8W', 'T-225', '2026-06-02 18:13:52', '2026-06-06 19:37:47', NULL, '6d2670282a9f66635c2fccaa20162209', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7XMQ44AVCAARQZX14', 'T-208', '2026-06-02 18:13:52', '2026-06-06 19:53:07', NULL, '015f7fe6ec6e3b348a6157401742472b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7XMQ44AVCAARQZX14', 'T-208', '2026-06-02 18:13:52', '2026-06-06 19:53:07', NULL, '015f7fe6ec6e3b348a6157401742472b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6S7KHYPE9W7S1JHZ8', 'T-256', '2026-06-06 10:07:35', '2026-06-06 19:53:07', NULL, '2dbd4405f72911a87fd757c819b9f0c5', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6S7KHYPE9W7S1JHZ8', 'T-256', '2026-06-06 10:07:35', '2026-06-06 19:53:07', NULL, '2dbd4405f72911a87fd757c819b9f0c5', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6WZ7DKVDFAGQ4QDMG', 'T-258', '2026-06-06 20:55:49', '2026-06-06 20:55:49', NULL, '4bcfdcf889c4bf6ca3405fa7b4857520', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6WZ7DKVDFAGQ4QDMG', 'T-258', '2026-06-06 20:55:49', '2026-06-06 20:55:49', NULL, '4bcfdcf889c4bf6ca3405fa7b4857520', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7RQMN1GKEZ5JQKJT0', 'T-259', '2026-06-06 21:12:44', '2026-06-06 21:12:44', NULL, '9efbdb558a1358b67827a0814fa5c23e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7RQMN1GKEZ5JQKJT0', 'T-259', '2026-06-06 21:12:44', '2026-06-06 21:12:44', NULL, '9efbdb558a1358b67827a0814fa5c23e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5JK0RHMRAH47K8ND4', 'T-36', '2026-04-22 20:34:09', '2026-06-06 21:14:22', NULL, 'bab3e0865388263d61db6651c3e5a55d', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5JK0RHMRAH47K8ND4', 'T-36', '2026-04-22 20:34:09', '2026-06-06 21:14:22', NULL, 'bab3e0865388263d61db6651c3e5a55d', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6DSPH569T4458B8JC', 'T-260', '2026-06-06 21:46:42', '2026-06-06 21:46:42', NULL, 'e45747cbef04e469b21ef0b4f2a3122f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6DSPH569T4458B8JC', 'T-260', '2026-06-06 21:46:42', '2026-06-06 21:46:42', NULL, 'e45747cbef04e469b21ef0b4f2a3122f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7GJW4V3CXMMXXV988', 'T-261', '2026-06-07 08:03:10', '2026-06-07 08:03:10', NULL, '54c9a91b6b4408f05c85ab0afb7daf47', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7GJW4V3CXMMXXV988', 'T-261', '2026-06-07 08:03:10', '2026-06-07 08:03:10', NULL, '54c9a91b6b4408f05c85ab0afb7daf47', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7GCVGCH9RMGYHENCC', 'T-54', '2026-04-23 20:32:06', '2026-06-07 08:03:17', NULL, 'ed036c636484f9b724fe82dace896d49', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7GCVGCH9RMGYHENCC', 'T-54', '2026-04-23 20:32:06', '2026-06-07 08:03:17', NULL, 'ed036c636484f9b724fe82dace896d49', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4QW8VH454J8V3E174', 'T-252', '2026-06-06 08:28:43', '2026-06-07 08:32:36', NULL, 'cb647a08e949e13f6386fefbb99c8c6e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4QW8VH454J8V3E174', 'T-252', '2026-06-06 08:28:43', '2026-06-07 08:32:36', NULL, 'cb647a08e949e13f6386fefbb99c8c6e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM63WP564EZRERJHVCM', 'T-255', '2026-06-06 09:56:23', '2026-06-07 08:51:08', NULL, 'e2aa43fb1e6a1c9c28ebd1fe2ab6bd79', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM63WP564EZRERJHVCM', 'T-255', '2026-06-06 09:56:23', '2026-06-07 08:51:08', NULL, 'e2aa43fb1e6a1c9c28ebd1fe2ab6bd79', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM74JAV0MJMB4VQNTRG', 'T-268', '2026-06-07 09:35:03', '2026-06-07 09:36:59', NULL, '796bd5eff55061d92fe00b3c4b15d3ad', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM74JAV0MJMB4VQNTRG', 'T-268', '2026-06-07 09:35:03', '2026-06-07 09:36:59', NULL, '796bd5eff55061d92fe00b3c4b15d3ad', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6P9YQ5V7WS6RFJNHW', 'T-269', '2026-06-07 09:44:17', '2026-06-07 09:51:32', NULL, '6fc792db7c0d2ba8f8c73c1e1960faf6', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6P9YQ5V7WS6RFJNHW', 'T-269', '2026-06-07 09:44:17', '2026-06-07 09:51:32', NULL, '6fc792db7c0d2ba8f8c73c1e1960faf6', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4XBRZJ6DEHFWREWC0', 'T-271', '2026-06-07 10:42:32', '2026-06-07 10:42:32', NULL, 'a7a8244eab996f86026f60edd5969de6', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4XBRZJ6DEHFWREWC0', 'T-271', '2026-06-07 10:42:32', '2026-06-07 10:42:32', NULL, 'a7a8244eab996f86026f60edd5969de6', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM67PDXAFTPPW7B1WDR', 'T-272', '2026-06-07 10:42:38', '2026-06-07 10:42:38', NULL, 'd3fcdcc97810a9b5f6b0624a3507c952', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM67PDXAFTPPW7B1WDR', 'T-272', '2026-06-07 10:42:38', '2026-06-07 10:42:38', NULL, 'd3fcdcc97810a9b5f6b0624a3507c952', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM40JE9MZZWCXC91THG', 'T-270', '2026-06-07 10:23:13', '2026-06-07 10:43:18', NULL, '014c8442d8f19f6cc075ad8fc27ce9ed', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM40JE9MZZWCXC91THG', 'T-270', '2026-06-07 10:23:13', '2026-06-07 10:43:18', NULL, '014c8442d8f19f6cc075ad8fc27ce9ed', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM551VZ2NYV6PD0XQRC', 'T-48', '2026-04-23 20:30:09', '2026-06-07 15:40:06', NULL, '8389d1a6a5d2db863bda0f7405d9496a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM551VZ2NYV6PD0XQRC', 'T-48', '2026-04-23 20:30:09', '2026-06-07 15:40:06', NULL, '8389d1a6a5d2db863bda0f7405d9496a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM71P14PAF7K4QE61G0', 'T-262', '2026-06-07 08:10:42', '2026-06-07 17:41:11', NULL, '561c4e90d842e6ac1a22dcacd7a5e33f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM71P14PAF7K4QE61G0', 'T-262', '2026-06-07 08:10:42', '2026-06-07 17:41:11', NULL, '561c4e90d842e6ac1a22dcacd7a5e33f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5W6VN98RQM6S22X28', 'T-274', '2026-06-08 07:26:13', '2026-06-08 07:46:46', NULL, 'd9177bbb472fd16a13d4f23e0cd70344', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5W6VN98RQM6S22X28', 'T-274', '2026-06-08 07:26:13', '2026-06-08 07:46:46', NULL, 'd9177bbb472fd16a13d4f23e0cd70344', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5TWC00GW0P3X02HZW', 'T-276', '2026-06-08 07:46:23', '2026-06-08 07:53:32', NULL, '1b77c5f3a8d66247532ead2164b6b37f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5TWC00GW0P3X02HZW', 'T-276', '2026-06-08 07:46:23', '2026-06-08 07:53:32', NULL, '1b77c5f3a8d66247532ead2164b6b37f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM60PAS5RJ55CZGPM1G', 'T-277', '2026-06-08 08:32:30', '2026-06-08 08:34:47', NULL, '70e24eabce743397720db9d6029a3337', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM60PAS5RJ55CZGPM1G', 'T-277', '2026-06-08 08:32:30', '2026-06-08 08:34:47', NULL, '70e24eabce743397720db9d6029a3337', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7XXSERDHKR0EEH3N4', 'T-263', '2026-06-07 08:34:02', '2026-06-08 08:45:23', NULL, '1cb588e500a902d2b880f3004c5c33b4', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7XXSERDHKR0EEH3N4', 'T-263', '2026-06-07 08:34:02', '2026-06-08 08:45:23', NULL, '1cb588e500a902d2b880f3004c5c33b4', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM45HHRBCRMV2166Y6M', 'T-266', '2026-06-07 08:41:13', '2026-06-08 09:04:12', NULL, '9162b1edab8984a25660f0fdcebcd41d', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM45HHRBCRMV2166Y6M', 'T-266', '2026-06-07 08:41:13', '2026-06-08 09:04:12', NULL, '9162b1edab8984a25660f0fdcebcd41d', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5YYMMKFD5Z8WG9F60', 'T-264', '2026-06-07 08:40:25', '2026-06-08 09:25:50', NULL, '4b9c66ff7114ce85456f57f6d1c58d7b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5YYMMKFD5Z8WG9F60', 'T-264', '2026-06-07 08:40:25', '2026-06-08 09:25:50', NULL, '4b9c66ff7114ce85456f57f6d1c58d7b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4Q1Q97CHA0XNK2G4W', 'T-265', '2026-06-07 08:40:33', '2026-06-08 10:09:14', NULL, 'ff24fcb74089501588a4bfcfa62c9aad', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4Q1Q97CHA0XNK2G4W', 'T-265', '2026-06-07 08:40:33', '2026-06-08 10:09:14', NULL, 'ff24fcb74089501588a4bfcfa62c9aad', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7ZGZ9GQ5W1MKV00Y4', 'T-267', '2026-06-07 08:42:53', '2026-06-08 10:09:21', NULL, 'd860955c7a7030d4c1c2ea98e5447fdf', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7ZGZ9GQ5W1MKV00Y4', 'T-267', '2026-06-07 08:42:53', '2026-06-08 10:09:21', NULL, 'd860955c7a7030d4c1c2ea98e5447fdf', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM55CV3VDYS88VBJZ60', 'T-273', '2026-06-07 17:39:10', '2026-06-08 11:44:27', NULL, '02cd1eaf484bd3adef09a71a7408674e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM55CV3VDYS88VBJZ60', 'T-273', '2026-06-07 17:39:10', '2026-06-08 11:44:27', NULL, '02cd1eaf484bd3adef09a71a7408674e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM59DG2WADJ9A0JFD1W', 'T-281', '2026-06-08 11:46:11', '2026-06-08 11:49:36', NULL, '1d9df18227de229f12bda189c4081353', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM59DG2WADJ9A0JFD1W', 'T-281', '2026-06-08 11:46:11', '2026-06-08 11:49:36', NULL, '1d9df18227de229f12bda189c4081353', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6K1QRC911JMQ9C960', 'T-283', '2026-06-08 13:39:51', '2026-06-08 13:44:57', NULL, '56929fab7dc064046853959720d43b8b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6K1QRC911JMQ9C960', 'T-283', '2026-06-08 13:39:51', '2026-06-08 13:44:57', NULL, '56929fab7dc064046853959720d43b8b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6A6A56VFSVRRBKMP0', 'T-279', '2026-06-08 10:21:20', '2026-06-08 14:12:46', NULL, '1023e2106149f0366bf3896635ec44c4', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6A6A56VFSVRRBKMP0', 'T-279', '2026-06-08 10:21:20', '2026-06-08 14:12:46', NULL, '1023e2106149f0366bf3896635ec44c4', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4KFHAS1WZFGBJ6JN4', 'T-284', '2026-06-08 14:55:43', '2026-06-08 14:57:15', NULL, '75d5f69fd00e63d09e707ad1e8338853', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4KFHAS1WZFGBJ6JN4', 'T-284', '2026-06-08 14:55:43', '2026-06-08 14:57:15', NULL, '75d5f69fd00e63d09e707ad1e8338853', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6GZ55VD4SAZZ6XXP4', 'T-285', '2026-06-08 15:22:32', '2026-06-08 15:37:29', NULL, '994bf6438e27af887c2f3d247e76d576', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6GZ55VD4SAZZ6XXP4', 'T-285', '2026-06-08 15:22:32', '2026-06-08 15:37:29', NULL, '994bf6438e27af887c2f3d247e76d576', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7W2MWZ45YNK7TJGC4', 'T-282', '2026-06-08 13:39:15', '2026-06-08 15:42:01', NULL, '9d5f153703ebeae7f011f555f380ef6e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7W2MWZ45YNK7TJGC4', 'T-282', '2026-06-08 13:39:15', '2026-06-08 15:42:01', NULL, '9d5f153703ebeae7f011f555f380ef6e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5AAA9WW54JGP83HGW', 'T-275', '2026-06-08 07:28:34', '2026-06-08 16:52:13', NULL, '886bd74d7ec01145f8acb5c7d9397307', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5AAA9WW54JGP83HGW', 'T-275', '2026-06-08 07:28:34', '2026-06-08 16:52:13', NULL, '886bd74d7ec01145f8acb5c7d9397307', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6NNRR61E8P6GHXABG', 'T-289', '2026-06-08 20:16:22', '2026-06-08 20:16:22', NULL, '6c2022166a2139a665912c3fe6d4802e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6NNRR61E8P6GHXABG', 'T-289', '2026-06-08 20:16:22', '2026-06-08 20:16:22', NULL, '6c2022166a2139a665912c3fe6d4802e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4501EBPDFDH84RJ5G', 'T-288', '2026-06-08 17:52:51', '2026-06-09 06:19:01', NULL, '16b1c85fab4273ebe7c9cfb9b9800e3e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4501EBPDFDH84RJ5G', 'T-288', '2026-06-08 17:52:51', '2026-06-09 06:19:01', NULL, '16b1c85fab4273ebe7c9cfb9b9800e3e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5R93N5J6RNVTBRB28', 'T-286', '2026-06-08 16:30:27', '2026-06-09 06:19:36', NULL, '22c1b0f40e3e3344f0c624af618bdaff', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5R93N5J6RNVTBRB28', 'T-286', '2026-06-08 16:30:27', '2026-06-09 06:19:36', NULL, '22c1b0f40e3e3344f0c624af618bdaff', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM44CKN5QQGFKP1KWZC', 'T-290', '2026-06-09 07:15:14', '2026-06-09 07:15:14', NULL, '53ca5591666fa7c01d90174bf28ecf4b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM44CKN5QQGFKP1KWZC', 'T-290', '2026-06-09 07:15:14', '2026-06-09 07:15:14', NULL, '53ca5591666fa7c01d90174bf28ecf4b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM45BSF1B0R0JA1Z7FC', 'T-291', '2026-06-09 07:15:22', '2026-06-09 07:15:22', NULL, '79e9f769c9313f0bc63d5c8c8a1ee641', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM45BSF1B0R0JA1Z7FC', 'T-291', '2026-06-09 07:15:22', '2026-06-09 07:15:22', NULL, '79e9f769c9313f0bc63d5c8c8a1ee641', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5E41Q8TX8X55X4MZ0', 'T-29', '2026-04-22 20:17:26', '2026-06-09 10:46:41', NULL, '93ab2ce409ff22e37a756e41553c0a69', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5E41Q8TX8X55X4MZ0', 'T-29', '2026-04-22 20:17:26', '2026-06-09 10:46:41', NULL, '93ab2ce409ff22e37a756e41553c0a69', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM50BPNDT50PM24ZVA4', 'T-278', '2026-06-08 09:20:00', '2026-06-09 15:03:23', NULL, '0c340b4aeb41ddaa858ae18888207b2e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM50BPNDT50PM24ZVA4', 'T-278', '2026-06-08 09:20:00', '2026-06-09 15:03:23', NULL, '0c340b4aeb41ddaa858ae18888207b2e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4BD8PXDRHBF001200', 'T-292', '2026-06-09 14:57:32', '2026-06-09 15:09:05', NULL, 'b907503e714ddc775257c90330c25d2f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4BD8PXDRHBF001200', 'T-292', '2026-06-09 14:57:32', '2026-06-09 15:09:05', NULL, 'b907503e714ddc775257c90330c25d2f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5DM43Q9HX352STN3M', 'T-295', '2026-06-09 15:26:00', '2026-06-09 15:26:00', NULL, 'c93802bd37eb8dfe981c74cfde3f24c4', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5DM43Q9HX352STN3M', 'T-295', '2026-06-09 15:26:00', '2026-06-09 15:26:00', NULL, 'c93802bd37eb8dfe981c74cfde3f24c4', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM42WW0SY3XEXKE8PK8', 'T-293', '2026-06-09 15:12:15', '2026-06-09 15:36:15', NULL, '55da76c0ebfc56f44cb4096a2a17b9c6', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM42WW0SY3XEXKE8PK8', 'T-293', '2026-06-09 15:12:15', '2026-06-09 15:36:15', NULL, '55da76c0ebfc56f44cb4096a2a17b9c6', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4GN07FN8GAXZ20YAR', 'T-236', '2026-06-03 15:31:01', '2026-06-09 15:55:06', NULL, '18d3d9bc2bc268d007d27c4cc20fcea8', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4GN07FN8GAXZ20YAR', 'T-236', '2026-06-03 15:31:01', '2026-06-09 15:55:06', NULL, '18d3d9bc2bc268d007d27c4cc20fcea8', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM61SRVBDRFFN2S80T4', 'T-254', '2026-06-06 09:32:54', '2026-06-09 15:55:06', NULL, 'ae31cf118f94e93699eed5f0ac0eee7c', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM61SRVBDRFFN2S80T4', 'T-254', '2026-06-06 09:32:54', '2026-06-09 15:55:06', NULL, 'ae31cf118f94e93699eed5f0ac0eee7c', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM63TRGBFRWK9W2WA98', 'T-296', '2026-06-09 15:43:58', '2026-06-09 16:34:46', NULL, '405de86b123fc1aeccf6f444a36bbf36', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM63TRGBFRWK9W2WA98', 'T-296', '2026-06-09 15:43:58', '2026-06-09 16:34:46', NULL, '405de86b123fc1aeccf6f444a36bbf36', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM72SHY93S36VM9G6D8', 'T-294', '2026-06-09 15:18:22', '2026-06-09 16:34:46', NULL, 'baa483c978c2744aaf95035de3809048', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM72SHY93S36VM9G6D8', 'T-294', '2026-06-09 15:18:22', '2026-06-09 16:34:46', NULL, 'baa483c978c2744aaf95035de3809048', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6RXN6HW6XTEHKYQDG', 'T-297', '2026-06-09 16:01:09', '2026-06-09 16:34:46', NULL, 'f228757d5b5ed41b7cf90b6035e09dda', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6RXN6HW6XTEHKYQDG', 'T-297', '2026-06-09 16:01:09', '2026-06-09 16:34:46', NULL, 'f228757d5b5ed41b7cf90b6035e09dda', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7K1FN7KD8S5ZVX2VM', 'T-299', '2026-06-09 16:42:47', '2026-06-09 16:42:47', NULL, 'a2fdfc4298353c34568d42e71c2786e6', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7K1FN7KD8S5ZVX2VM', 'T-299', '2026-06-09 16:42:47', '2026-06-09 16:42:47', NULL, 'a2fdfc4298353c34568d42e71c2786e6', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM53HQD6YV754GKBA60', 'T-44', '2026-04-23 20:25:26', '2026-06-09 16:56:55', NULL, '75a46ae8c87aa5a9a27e513b4ea65e58', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM53HQD6YV754GKBA60', 'T-44', '2026-04-23 20:25:26', '2026-06-09 16:56:55', NULL, '75a46ae8c87aa5a9a27e513b4ea65e58', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM62FKQQD0B9B80PFY4', 'T-158', '2026-05-23 20:48:38', '2026-06-09 17:16:34', NULL, '1282d8b5cb009f639f7c7a14e69ef2b3', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM62FKQQD0B9B80PFY4', 'T-158', '2026-05-23 20:48:38', '2026-06-09 17:16:34', NULL, '1282d8b5cb009f639f7c7a14e69ef2b3', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7D5DMYF5X92Q55CBW', 'T-235', '2026-06-03 15:17:29', '2026-06-09 17:16:34', NULL, '1bccb4cf47ba2a1a72e4f65a214e2f78', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7D5DMYF5X92Q55CBW', 'T-235', '2026-06-03 15:17:29', '2026-06-09 17:16:34', NULL, '1bccb4cf47ba2a1a72e4f65a214e2f78', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7W0NPAEG3KWNFY9DR', 'T-132', '2026-05-22 15:45:15', '2026-06-09 17:23:25', NULL, 'cf1709ddff1d13a7b4adb0dc193b319b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7W0NPAEG3KWNFY9DR', 'T-132', '2026-05-22 15:45:15', '2026-06-09 17:23:25', NULL, 'cf1709ddff1d13a7b4adb0dc193b319b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7F2TBJJV1F2KP7XR8', 'T-300', '2026-06-09 20:02:41', '2026-06-09 20:03:08', NULL, '6f1c204fc4f81403ba50e9e7ecff7241', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7F2TBJJV1F2KP7XR8', 'T-300', '2026-06-09 20:02:41', '2026-06-09 20:03:08', NULL, '6f1c204fc4f81403ba50e9e7ecff7241', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6048VEGFDNEBHFMM4', 'T-301', '2026-06-09 20:04:29', '2026-06-09 20:04:54', NULL, '89490f3e4d3e09714b70f0e35c726038', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6048VEGFDNEBHFMM4', 'T-301', '2026-06-09 20:04:29', '2026-06-09 20:04:54', NULL, '89490f3e4d3e09714b70f0e35c726038', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4AE2GEF6BXSGKRMGC', 'T-242', '2026-06-05 10:17:47', '2026-06-09 20:07:30', NULL, 'c570cc4f2808f31192d947affb3392a0', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4AE2GEF6BXSGKRMGC', 'T-242', '2026-06-05 10:17:47', '2026-06-09 20:07:30', NULL, 'c570cc4f2808f31192d947affb3392a0', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM42VPM50VKAWXBCAM8', 'T-253', '2026-06-06 09:32:53', '2026-06-09 20:17:04', NULL, '47b9d1a167b65553a14ede7a5a53f851', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM42VPM50VKAWXBCAM8', 'T-253', '2026-06-06 09:32:53', '2026-06-09 20:17:04', NULL, '47b9d1a167b65553a14ede7a5a53f851', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7H8JWCP59WQVD0FW4', 'T-302', '2026-06-09 20:24:54', '2026-06-09 20:25:49', NULL, '8e04d93f6163a8f54965bc5988dae31c', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7H8JWCP59WQVD0FW4', 'T-302', '2026-06-09 20:24:54', '2026-06-09 20:25:49', NULL, '8e04d93f6163a8f54965bc5988dae31c', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5QJC039TMDF5JGMXC', 'T-240', '2026-06-05 09:38:46', '2026-06-09 20:27:17', NULL, '4879c042965effced12e608af5739659', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5QJC039TMDF5JGMXC', 'T-240', '2026-06-05 09:38:46', '2026-06-09 20:27:17', NULL, '4879c042965effced12e608af5739659', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM531VE0C6N36AT12SR', 'T-241', '2026-06-05 10:02:31', '2026-06-09 20:34:30', NULL, 'b7de744d4e5292306b1fa64bcc3ba1aa', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM531VE0C6N36AT12SR', 'T-241', '2026-06-05 10:02:31', '2026-06-09 20:34:30', NULL, 'b7de744d4e5292306b1fa64bcc3ba1aa', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4K1MTP2MHRKKNXBFM', 'T-303', '2026-06-09 20:41:22', '2026-06-09 20:41:22', NULL, '1adc6db2fcc64d6fd36ad0406939a8d7', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4K1MTP2MHRKKNXBFM', 'T-303', '2026-06-09 20:41:22', '2026-06-09 20:41:22', NULL, '1adc6db2fcc64d6fd36ad0406939a8d7', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4BRWWPB4R06Q31XV0', 'T-56', '2026-04-23 20:32:06', '2026-06-09 20:57:53', NULL, '5a394b49d98e119d21b637745798fd8b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4BRWWPB4R06Q31XV0', 'T-56', '2026-04-23 20:32:06', '2026-06-09 20:57:53', NULL, '5a394b49d98e119d21b637745798fd8b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6SK3D1QYACBPHHBZ0', 'T-287', '2026-06-08 17:12:49', '2026-06-09 21:21:08', NULL, '7d9537b53ade941ecd8a8efadd591c17', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6SK3D1QYACBPHHBZ0', 'T-287', '2026-06-08 17:12:49', '2026-06-09 21:21:08', NULL, '7d9537b53ade941ecd8a8efadd591c17', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4KS233FGZE9H7ABWR', 'T-304', '2026-06-09 21:22:28', '2026-06-09 21:22:44', NULL, '252c572a5954883d0e5e71406b092a7f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4KS233FGZE9H7ABWR', 'T-304', '2026-06-09 21:22:28', '2026-06-09 21:22:44', NULL, '252c572a5954883d0e5e71406b092a7f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM50S6WRD81V3Z0NH1M', 'T-298', '2026-06-09 16:06:41', '2026-06-09 21:36:05', NULL, 'f8666523eaf2642b918f6846e2801539', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM50S6WRD81V3Z0NH1M', 'T-298', '2026-06-09 16:06:41', '2026-06-09 21:36:05', NULL, 'f8666523eaf2642b918f6846e2801539', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5YNEQM1WY25BV7TD8', 'T-280', '2026-06-08 11:29:22', '2026-06-09 21:42:59', NULL, 'e9859dd425e0ac667ddbce721415572e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5YNEQM1WY25BV7TD8', 'T-280', '2026-06-08 11:29:22', '2026-06-09 21:42:59', NULL, 'e9859dd425e0ac667ddbce721415572e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB16FJ7KXGFHQXEG88MYRFTG', 'T-305', '2026-06-10 08:15:39', '2026-06-10 08:15:39', NULL, '288b0c9d74e98c2ac42ee25d3369f689', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB16FJ7KXGFHQXEG88MYRFTG', 'T-305', '2026-06-10 08:15:39', '2026-06-10 08:15:39', NULL, '288b0c9d74e98c2ac42ee25d3369f689', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB16YM1Y910T07Y1Y22MGTEM', 'T-306', '2026-06-10 08:17:42', '2026-06-10 08:17:42', NULL, 'af36af77224b697a61cb5447955605e5', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB16YM1Y910T07Y1Y22MGTEM', 'T-306', '2026-06-10 08:17:42', '2026-06-10 08:17:42', NULL, 'af36af77224b697a61cb5447955605e5', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB170DJA02EH2E8HMH7X7SS4', 'T-307', '2026-06-10 08:17:57', '2026-06-10 08:17:57', NULL, '882cca1753c2ede7bfe2aef142545b76', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB170DJA02EH2E8HMH7X7SS4', 'T-307', '2026-06-10 08:17:57', '2026-06-10 08:17:57', NULL, '882cca1753c2ede7bfe2aef142545b76', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB1Q1Y3CYJHD7W5F68VDB6T4', 'T-308', '2026-06-10 09:28:04', '2026-06-10 09:28:04', NULL, '5050ff0e69b24a93f5b7e96c8a9fa47e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB1Q1Y3CYJHD7W5F68VDB6T4', 'T-308', '2026-06-10 09:28:04', '2026-06-10 09:28:04', NULL, '5050ff0e69b24a93f5b7e96c8a9fa47e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB1S7613SYF0M9XQT5JNWM40', 'T-309', '2026-06-10 09:37:31', '2026-06-10 09:37:31', NULL, 'b4f48310ea6b0f49f83c46e3bc5b7ad8', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB1S7613SYF0M9XQT5JNWM40', 'T-309', '2026-06-10 09:37:31', '2026-06-10 09:37:31', NULL, 'b4f48310ea6b0f49f83c46e3bc5b7ad8', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB1SJKA7KRCQMZE41SPQG780', 'T-310', '2026-06-10 09:39:05', '2026-06-10 09:39:05', NULL, '9088122bf9d5e04ca8a7fee3bf031a53', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB1SJKA7KRCQMZE41SPQG780', 'T-310', '2026-06-10 09:39:05', '2026-06-10 09:39:05', NULL, '9088122bf9d5e04ca8a7fee3bf031a53', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB1XDWKQ594ET4GDYEFK5ZJ4', 'T-311', '2026-06-10 09:55:55', '2026-06-10 09:55:55', NULL, 'ed03464125d09ff5f23913e6247064e3', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB1XDWKQ594ET4GDYEFK5ZJ4', 'T-311', '2026-06-10 09:55:55', '2026-06-10 09:55:55', NULL, 'ed03464125d09ff5f23913e6247064e3', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB1ZFJK6J2GSV4SA69QF730C', 'T-312', '2026-06-10 10:04:53', '2026-06-10 10:04:53', NULL, 'dd22af12b333c13376b23aa5381ea2d7', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB1ZFJK6J2GSV4SA69QF730C', 'T-312', '2026-06-10 10:04:53', '2026-06-10 10:04:53', NULL, 'dd22af12b333c13376b23aa5381ea2d7', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB234WP4Y6Q16A0HFW8BSXMG', 'T-313', '2026-06-10 10:20:54', '2026-06-10 10:20:54', NULL, '9b7abb73ea56cfdad2039303a8935897', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB234WP4Y6Q16A0HFW8BSXMG', 'T-313', '2026-06-10 10:20:54', '2026-06-10 10:20:54', NULL, '9b7abb73ea56cfdad2039303a8935897', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB23Z52EVGQ4ZDAQ5BVAJ13R', 'T-314', '2026-06-10 10:24:29', '2026-06-10 10:24:29', NULL, 'f8b89421a13f620c2a0e76bd780db5a2', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB23Z52EVGQ4ZDAQ5BVAJ13R', 'T-314', '2026-06-10 10:24:29', '2026-06-10 10:24:29', NULL, 'f8b89421a13f620c2a0e76bd780db5a2', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2ACSDBDZARV3NNGYD9NYYR', 'T-315', '2026-06-10 10:52:34', '2026-06-10 10:52:34', NULL, 'd0521ab80265d66c99c803a8714e8f02', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2ACSDBDZARV3NNGYD9NYYR', 'T-315', '2026-06-10 10:52:34', '2026-06-10 10:52:34', NULL, 'd0521ab80265d66c99c803a8714e8f02', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2AD3HPR3HXSVASVZEX8PK0', 'T-316', '2026-06-10 10:52:36', '2026-06-10 10:52:36', NULL, '5beb005b263eb4c5bb10ffc6e2fc0100', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2AD3HPR3HXSVASVZEX8PK0', 'T-316', '2026-06-10 10:52:36', '2026-06-10 10:52:36', NULL, '5beb005b263eb4c5bb10ffc6e2fc0100', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2EDCBYRBDSV9V1PJ1KE3CM', 'T-317', '2026-06-10 11:10:07', '2026-06-10 11:10:07', NULL, '4d4a02ab95987e3ebb134a2f0173b4a1', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2EDCBYRBDSV9V1PJ1KE3CM', 'T-317', '2026-06-10 11:10:07', '2026-06-10 11:10:07', NULL, '4d4a02ab95987e3ebb134a2f0173b4a1', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2ERREMEEF26KKHGNZBWW64', 'T-318', '2026-06-10 11:11:40', '2026-06-10 11:11:40', NULL, '31820aadd1f19f9dd0cf931dae565abc', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2ERREMEEF26KKHGNZBWW64', 'T-318', '2026-06-10 11:11:40', '2026-06-10 11:11:40', NULL, '31820aadd1f19f9dd0cf931dae565abc', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2ESCR4V6V07CRH18FBCDN8', 'T-319', '2026-06-10 11:11:45', '2026-06-10 11:11:45', NULL, '12c5a57fb83444410cca98a802e9ba6f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2ESCR4V6V07CRH18FBCDN8', 'T-319', '2026-06-10 11:11:45', '2026-06-10 11:11:45', NULL, '12c5a57fb83444410cca98a802e9ba6f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2ETJQP0CT6X7W3CWZ6NS9G', 'T-320', '2026-06-10 11:11:55', '2026-06-10 11:11:55', NULL, '2266e362f144e4fd97403e1d1abe3eb4', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2ETJQP0CT6X7W3CWZ6NS9G', 'T-320', '2026-06-10 11:11:55', '2026-06-10 11:11:55', NULL, '2266e362f144e4fd97403e1d1abe3eb4', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2EV29HSK6EJ5VF50R87VC4', 'T-321', '2026-06-10 11:11:59', '2026-06-10 11:11:59', NULL, 'd48b6bd9f0c8289c95448dda6865d666', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2EV29HSK6EJ5VF50R87VC4', 'T-321', '2026-06-10 11:11:59', '2026-06-10 11:11:59', NULL, 'd48b6bd9f0c8289c95448dda6865d666', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2G1WD1839Z90AQ5C0BHNV4', 'T-322', '2026-06-10 11:17:17', '2026-06-10 11:17:17', NULL, 'f33b1db4b67a0521f02c5c49fcfa8e6f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2G1WD1839Z90AQ5C0BHNV4', 'T-322', '2026-06-10 11:17:17', '2026-06-10 11:17:17', NULL, 'f33b1db4b67a0521f02c5c49fcfa8e6f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2G2KHKT5CJYR0TK1WQGMD0', 'T-323', '2026-06-10 11:17:23', '2026-06-10 11:17:23', NULL, '0738a8da475a6d8d49132d1e4e753775', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2G2KHKT5CJYR0TK1WQGMD0', 'T-323', '2026-06-10 11:17:23', '2026-06-10 11:17:23', NULL, '0738a8da475a6d8d49132d1e4e753775', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2J2HWD66QAFDDRRWS5NM48', 'T-324', '2026-06-10 11:26:07', '2026-06-10 11:26:07', NULL, 'd8aa9ae4522d97b70331c42b8ab7a365', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2J2HWD66QAFDDRRWS5NM48', 'T-324', '2026-06-10 11:26:07', '2026-06-10 11:26:07', NULL, 'd8aa9ae4522d97b70331c42b8ab7a365', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2T11GCV1EV07DYD5BZENTM', 'T-325', '2026-06-10 12:00:52', '2026-06-10 12:00:52', NULL, '47b8f31d9337c5bbc6476d62c7f6ed4d', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2T11GCV1EV07DYD5BZENTM', 'T-325', '2026-06-10 12:00:52', '2026-06-10 12:00:52', NULL, '47b8f31d9337c5bbc6476d62c7f6ed4d', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2TY91VHK7TPKPMZ11EG3TM', 'T-326', '2026-06-10 12:04:51', '2026-06-10 12:04:51', NULL, '348dee79d9d3fe0a8b260c1f9c47a289', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2TY91VHK7TPKPMZ11EG3TM', 'T-326', '2026-06-10 12:04:51', '2026-06-10 12:04:51', NULL, '348dee79d9d3fe0a8b260c1f9c47a289', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2W4G9K8ZF782W7H2TM5XA8', 'T-327', '2026-06-10 12:10:04', '2026-06-10 12:10:04', NULL, '967aab6bc692754a5d3a192cb0008871', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2W4G9K8ZF782W7H2TM5XA8', 'T-327', '2026-06-10 12:10:04', '2026-06-10 12:10:04', NULL, '967aab6bc692754a5d3a192cb0008871', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB37JZSFZKWPK9PDFYJY2YC0', 'T-328', '2026-06-10 13:00:06', '2026-06-10 13:00:06', NULL, '553b6683bbcddfbbab39ee545a99c98c', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB37JZSFZKWPK9PDFYJY2YC0', 'T-328', '2026-06-10 13:00:06', '2026-06-10 13:00:06', NULL, '553b6683bbcddfbbab39ee545a99c98c', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DHCTP001YCHFP39XER0ZM', 'T-329', '2026-06-10 13:26:06', '2026-06-10 13:26:06', NULL, 'a7b63cf73534de82c953d3029251b5e4', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DHCTP001YCHFP39XER0ZM', 'T-329', '2026-06-10 13:26:06', '2026-06-10 13:26:06', NULL, 'a7b63cf73534de82c953d3029251b5e4', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DJZDDZ00BSA04B660RS7M', 'T-330', '2026-06-10 13:26:19', '2026-06-10 13:26:19', NULL, 'c7ef552dc6d7fc2a5e312b20939a2987', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DJZDDZ00BSA04B660RS7M', 'T-330', '2026-06-10 13:26:19', '2026-06-10 13:26:19', NULL, 'c7ef552dc6d7fc2a5e312b20939a2987', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DKQQJ583944DG8561VQ3G', 'T-331', '2026-06-10 13:26:25', '2026-06-10 13:26:25', NULL, '002e4d81284119aecab05d180a9a41cd', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DKQQJ583944DG8561VQ3G', 'T-331', '2026-06-10 13:26:25', '2026-06-10 13:26:25', NULL, '002e4d81284119aecab05d180a9a41cd', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DMF20SYFDT6WX2RFBQXKW', 'T-332', '2026-06-10 13:26:31', '2026-06-10 13:26:31', NULL, '38d661bbd4a937daf395f82074cf8d12', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DMF20SYFDT6WX2RFBQXKW', 'T-332', '2026-06-10 13:26:31', '2026-06-10 13:26:31', NULL, '38d661bbd4a937daf395f82074cf8d12', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DN94MBCTYJW17ZCYVSXE0', 'T-333', '2026-06-10 13:26:38', '2026-06-10 13:26:38', NULL, 'c710c528662f92c6b7416b7163c8e99f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DN94MBCTYJW17ZCYVSXE0', 'T-333', '2026-06-10 13:26:38', '2026-06-10 13:26:38', NULL, 'c710c528662f92c6b7416b7163c8e99f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DNQZKV20F7YG5PJH8V8SM', 'T-334', '2026-06-10 13:26:42', '2026-06-10 13:26:42', NULL, '7f774dc51ae344eddfd42c2149887d56', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DNQZKV20F7YG5PJH8V8SM', 'T-334', '2026-06-10 13:26:42', '2026-06-10 13:26:42', NULL, '7f774dc51ae344eddfd42c2149887d56', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DP48FS33CQGRDF7EB9GT0', 'T-335', '2026-06-10 13:26:45', '2026-06-10 13:26:45', NULL, '1cce32ce77997202bf74c69426c29ab9', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DP48FS33CQGRDF7EB9GT0', 'T-335', '2026-06-10 13:26:45', '2026-06-10 13:26:45', NULL, '1cce32ce77997202bf74c69426c29ab9', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DQEMTDHF8SV27AKAB8JHW', 'T-336', '2026-06-10 13:26:56', '2026-06-10 13:26:56', NULL, 'b988abcd2cef0dbd6adbc56502f676ca', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DQEMTDHF8SV27AKAB8JHW', 'T-336', '2026-06-10 13:26:56', '2026-06-10 13:26:56', NULL, 'b988abcd2cef0dbd6adbc56502f676ca', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DWCJSGZH9WYDNFWZBAYYR', 'T-337', '2026-06-10 13:27:36', '2026-06-10 13:27:36', NULL, '94b0ebd244a6794e0e4e5a868b38d67f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3DWCJSGZH9WYDNFWZBAYYR', 'T-337', '2026-06-10 13:27:36', '2026-06-10 13:27:36', NULL, '94b0ebd244a6794e0e4e5a868b38d67f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3JAXDKZMS0805MMEYB6820', 'T-338', '2026-06-10 13:47:04', '2026-06-10 13:47:04', NULL, 'be9b536d471a6008cc854092dfa6aaa4', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3JAXDKZMS0805MMEYB6820', 'T-338', '2026-06-10 13:47:04', '2026-06-10 13:47:04', NULL, 'be9b536d471a6008cc854092dfa6aaa4', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3JM0AXK1CTWD720RV1AVZ0', 'T-339', '2026-06-10 13:48:18', '2026-06-10 13:48:18', NULL, 'e76a2ce5d3149bb7ca0ec8a45f5c57a2', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3JM0AXK1CTWD720RV1AVZ0', 'T-339', '2026-06-10 13:48:18', '2026-06-10 13:48:18', NULL, 'e76a2ce5d3149bb7ca0ec8a45f5c57a2', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3KS499THAD899M0NWN7E3R', 'T-340', '2026-06-10 13:53:23', '2026-06-10 13:53:23', NULL, 'bdd164a73576f6ca5151c8a62640526f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB3KS499THAD899M0NWN7E3R', 'T-340', '2026-06-10 13:53:23', '2026-06-10 13:53:23', NULL, 'bdd164a73576f6ca5151c8a62640526f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB44SKPKTHFMV6WD28GZYPXM', 'T-341', '2026-06-10 15:07:43', '2026-06-10 15:07:43', NULL, '113520f8f3a640fa2f470200ea9f45d8', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB44SKPKTHFMV6WD28GZYPXM', 'T-341', '2026-06-10 15:07:43', '2026-06-10 15:07:43', NULL, '113520f8f3a640fa2f470200ea9f45d8', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB493JEW32CH0H3771TNHF7G', 'T-342', '2026-06-10 15:26:33', '2026-06-10 15:26:33', NULL, '13a646741953f113356c4bcda162c3c9', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB493JEW32CH0H3771TNHF7G', 'T-342', '2026-06-10 15:26:33', '2026-06-10 15:26:33', NULL, '13a646741953f113356c4bcda162c3c9', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB4FDREHRYRR7B9ER72KCQKC', 'T-343', '2026-06-10 15:54:09', '2026-06-10 15:54:09', NULL, 'e48d2b913bb03202409c6568d9bc11a5', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB4FDREHRYRR7B9ER72KCQKC', 'T-343', '2026-06-10 15:54:09', '2026-06-10 15:54:09', NULL, 'e48d2b913bb03202409c6568d9bc11a5', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB4J5E6W983P1S7BE0FDPSMM', 'T-344', '2026-06-10 16:06:08', '2026-06-10 16:06:08', NULL, '481e82dfab98c20cd37c77a3e0c16668', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB4J5E6W983P1S7BE0FDPSMM', 'T-344', '2026-06-10 16:06:08', '2026-06-10 16:06:08', NULL, '481e82dfab98c20cd37c77a3e0c16668', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB4RD1DDSYM4J7WYEGTXARB4', 'T-345', '2026-06-10 16:33:23', '2026-06-10 16:33:23', NULL, '9f26d5036c05057d4bd0fc53ddaddafd', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB4RD1DDSYM4J7WYEGTXARB4', 'T-345', '2026-06-10 16:33:23', '2026-06-10 16:33:23', NULL, '9f26d5036c05057d4bd0fc53ddaddafd', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB4VG3N3YJSV8G7M1HFSYW2W', 'T-346', '2026-06-10 16:46:54', '2026-06-10 16:46:54', NULL, 'a64940cb0b4ec4fb489eac27065dc447', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB4VG3N3YJSV8G7M1HFSYW2W', 'T-346', '2026-06-10 16:46:54', '2026-06-10 16:46:54', NULL, 'a64940cb0b4ec4fb489eac27065dc447', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB4XCM5KBXDDSCWJ37GPYG3R', 'T-347', '2026-06-10 16:55:10', '2026-06-10 16:55:10', NULL, '9d40226dbc6136072d2d5d0eda71f141', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB4XCM5KBXDDSCWJ37GPYG3R', 'T-347', '2026-06-10 16:55:10', '2026-06-10 16:55:10', NULL, '9d40226dbc6136072d2d5d0eda71f141', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB50YE6S6YWNP2ZSFWES9B2W', 'T-348', '2026-06-10 17:10:42', '2026-06-10 17:10:42', NULL, '8bb5ad92551f272417840869a0774668', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB50YE6S6YWNP2ZSFWES9B2W', 'T-348', '2026-06-10 17:10:42', '2026-06-10 17:10:42', NULL, '8bb5ad92551f272417840869a0774668', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB58X0TFJ02YTMVPD0D9Q838', 'T-349', '2026-06-10 17:45:28', '2026-06-10 17:45:28', NULL, '0b12f14fa83254ab113c870531628359', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB58X0TFJ02YTMVPD0D9Q838', 'T-349', '2026-06-10 17:45:28', '2026-06-10 17:45:28', NULL, '0b12f14fa83254ab113c870531628359', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB5CW7JPT6BR2RWMNYVCXJ50', 'T-350', '2026-06-10 18:02:50', '2026-06-10 18:02:50', NULL, 'a5c0c22d84621b14a5208317414d6026', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB5CW7JPT6BR2RWMNYVCXJ50', 'T-350', '2026-06-10 18:02:50', '2026-06-10 18:02:50', NULL, 'a5c0c22d84621b14a5208317414d6026', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB5HMYDXP62RKH3HP55T6AYG', 'T-351', '2026-06-10 18:23:41', '2026-06-10 18:23:41', NULL, '9d2da44c16c5aa38c0a36e4b00ef5f15', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB5HMYDXP62RKH3HP55T6AYG', 'T-351', '2026-06-10 18:23:41', '2026-06-10 18:23:41', NULL, '9d2da44c16c5aa38c0a36e4b00ef5f15', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB5M14B76B31654D959XM5AC', 'T-352', '2026-06-10 18:34:05', '2026-06-10 18:34:05', NULL, '3fe3e1d5fb7c0fbd084b45116575ad98', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash);
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB5M14B76B31654D959XM5AC', 'T-352', '2026-06-10 18:34:05', '2026-06-10 18:34:05', NULL, '3fe3e1d5fb7c0fbd084b45116575ad98', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBAWHM1SQ1686ZJ8JQCFQ1ZW', 'T-353', '2026-06-11 06:50:21', '2026-06-11 06:50:21', NULL, '53374633101d04f94981baaf4f2e0315', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBDSJYQFDNKP4KA1JAEDSS8W', 'T-354', '2026-06-11 13:36:51', '2026-06-11 13:36:51', NULL, '32bb5d359401599022a8771031d8a08a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBDSKGAHYHH2NPZK8B6EV4D4', 'T-355', '2026-06-11 13:36:55', '2026-06-11 13:36:55', NULL, '2eb6809e958613a924b35e080ab17609', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBDSM0PRGYR61R0NWYAT9VDC', 'T-356', '2026-06-11 13:37:00', '2026-06-11 13:37:00', NULL, 'bdb597080218a3e8783f6c5cf74c529a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBDSPECQ0FPKB9SYTD7KZSBM', 'T-357', '2026-06-11 13:37:19', '2026-06-11 13:37:19', NULL, '96cf88e036dc3a45487cdbffff26cdde', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBDSQ2GBSP0ZH4RHZG2PMR0R', 'T-358', '2026-06-11 13:37:25', '2026-06-11 13:37:25', NULL, '2a656aaec54bf50c34c7e28347b1fb29', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHBGHNEQTAEPGNJKN42C1E8', 'T-359', '2026-06-11 21:54:36', '2026-06-11 21:54:36', NULL, '1930fad7b18c79cf97d913d8372b77bd', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHBJ5T7HAQ9CA8XQMX43A2C', 'T-360', '2026-06-11 21:54:49', '2026-06-11 21:54:49', NULL, '1ffef3c00cdca28566ab67a11ec17e53', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHBKK2TZQK683J8FS0ZH5A4', 'T-361', '2026-06-11 21:55:01', '2026-06-11 21:55:01', NULL, '5f8bdede98496496bf031a40a09dee16', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHBN5F0F8SDF15P21DNKT1W', 'T-362', '2026-06-11 21:55:13', '2026-06-11 21:55:13', NULL, '610e74eb7b4ff9db3949ed01a0268380', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHBPQE4J4YBJX92812ZK6DR', 'T-363', '2026-06-11 21:55:26', '2026-06-11 21:55:26', NULL, '5daf7bcd9ccdc37f8aed531ef12d395f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHBR4636GSRJBWFJDAZ6ZA0', 'T-364', '2026-06-11 21:55:38', '2026-06-11 21:55:38', NULL, '025de46ba9e8d005fd8b1f74687cd8b6', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHBSG6356MZJ2DCCCSBMBGM', 'T-365', '2026-06-11 21:55:49', '2026-06-11 21:55:49', NULL, 'b366b41e4737a2761a01284fd7dd44e0', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHBV0465906BY3QFAY9F1YM', 'T-366', '2026-06-11 21:56:01', '2026-06-11 21:56:01', NULL, '8a75dc7dea83a0e643d1912bda46dd57', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHBWE2W1226T58CX37E50HC', 'T-367', '2026-06-11 21:56:13', '2026-06-11 21:56:13', NULL, '578b51eafd19044dc0e2720f6e55d633', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHBYTJ4E7ZBY6DWWNT1S16M', 'T-368', '2026-06-11 21:56:33', '2026-06-11 21:56:33', NULL, '0df409c83fe28af2d49a156118ed6ece', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHC0HYRZ86CWW0DDQJ5CAQM', 'T-369', '2026-06-11 21:56:47', '2026-06-11 21:56:47', NULL, '7f47ddc3e84f9fea915200992a5a0baf', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHC2NM7AYKENZ0ZD49HAX1W', 'T-370', '2026-06-11 21:57:04', '2026-06-11 21:57:04', NULL, '1908b7c0903c389ad5b743fb89ca32e0', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHC46SEHH8NQY481VMGK66R', 'T-371', '2026-06-11 21:57:17', '2026-06-11 21:57:17', NULL, '2095f10159561a5e81b2a9b990c79fa2', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHC5ZE4EZEGXK8YY8J86CM0', 'T-372', '2026-06-11 21:57:31', '2026-06-11 21:57:31', NULL, '9d22f370e726af56d47d6c8acd93bc87', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHC7KDFW07S8WTCC3MD71J0', 'T-373', '2026-06-11 21:57:44', '2026-06-11 21:57:44', NULL, '231c399183a83e569c0645e1d149625f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHC90B72A270CAKA7AP1ZX8', 'T-374', '2026-06-11 21:57:56', '2026-06-11 21:57:56', NULL, '9832ac0b3e0bebd85f3271a5ea96d4ed', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHCAFKK334YNJXZJQG4J6AW', 'T-375', '2026-06-11 21:58:08', '2026-06-11 21:58:08', NULL, 'de3569d098b5c4cf6a3d49ee3d33d1c9', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHCC6AR37VTF4SY8DR99JHC', 'T-376', '2026-06-11 21:58:22', '2026-06-11 21:58:22', NULL, 'fe23c94d8971d21963a2b2e2739e05a3', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHCEC25337J2AXXQNST56Y4', 'T-377', '2026-06-11 21:58:40', '2026-06-11 21:58:40', NULL, '1585df7f3826ddbcef8a030ffd1e0890', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHCG84F4SPFW111CC4K26A8', 'T-378', '2026-06-11 21:58:55', '2026-06-11 21:58:55', NULL, 'c6b0d9d124401f1d2bdc403567cbfdf8', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHCJEYHC91PMVNVWVHBR2RG', 'T-379', '2026-06-11 21:59:13', '2026-06-11 21:59:13', NULL, '0d9aed402c9840ef6fb75edfcfcbc3f4', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHCM1RBAF72SCZBKRTXJSYC', 'T-380', '2026-06-11 21:59:26', '2026-06-11 21:59:26', NULL, '1a0d767f30c9bc0e9c96f39d468ca67b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHCP03EJ9CDBGZGRPD19N8W', 'T-381', '2026-06-11 21:59:42', '2026-06-11 21:59:42', NULL, 'cfac236e079164f9588d936f5101c71c', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHCQHZQ0NKY1VRWWPSNZT84', 'T-382', '2026-06-11 21:59:55', '2026-06-11 21:59:55', NULL, 'b54be44ec4cfbbc649324471a5e2141f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHCST6CQ449VJGAP6C5KZ5W', 'T-383', '2026-06-11 22:00:14', '2026-06-11 22:00:14', NULL, '0e18de4e94e4fcf36fc40de763522cbd', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHCVPGCKEGDC54KKQ120SRM', 'T-384', '2026-06-11 22:00:29', '2026-06-11 22:00:29', NULL, '57d7b6a6c05791acadd1cebe611c8991', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHCXFF5V1RT6QJETS2K4C0G', 'T-385', '2026-06-11 22:00:44', '2026-06-11 22:00:44', NULL, 'ebda2dd9c7dfe92bab2260dc34212ac4', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHD098CV2N73823KX4Z99P4', 'T-386', '2026-06-11 22:01:07', '2026-06-11 22:01:07', NULL, 'de90501f2d4be80231651d25d04f4649', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHD2FWTDFYA00W4QXTE41M0', 'T-387', '2026-06-11 22:01:25', '2026-06-11 22:01:25', NULL, '8a247364a872c223b37682c6496d3920', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHD4QYHYRTK0SGRZCBSHSQ0', 'T-388', '2026-06-11 22:01:43', '2026-06-11 22:01:43', NULL, 'cc238ee850d4d0ed90d05b9a42c8d506', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHD6FQMXMQQQ877KMNCK6QC', 'T-389', '2026-06-11 22:01:57', '2026-06-11 22:01:57', NULL, 'bb0657e304f4ad1445d756ef7170c62d', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHD8F2NBEFZNPKSJ9W253J0', 'T-390', '2026-06-11 22:02:14', '2026-06-11 22:02:14', NULL, '35453f0d8c7e0fb89c243481f870de03', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHDAK04ZA0PBT69ZWNBXPSR', 'T-391', '2026-06-11 22:02:31', '2026-06-11 22:02:31', NULL, '0647245b4da95532bb3abd6f20cd87de', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHDC7B2MFQZVR1K9E30FXDR', 'T-392', '2026-06-11 22:02:44', '2026-06-11 22:02:44', NULL, 'a1612ff75df3d134b8e05c716d24ebfe', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHDE5A3965GNRFS5WPZW878', 'T-393', '2026-06-11 22:03:00', '2026-06-11 22:03:00', NULL, 'f8f29fb8b31cc8afdd8af989c3f711f1', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHDGPXQN31NNRPJ00PFRAG4', 'T-394', '2026-06-11 22:03:21', '2026-06-11 22:03:21', NULL, 'f9cee5dc96cedfabc3eaaf7352e732c8', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBHDH8TE9MJBXZ4GQ5YT10JM', 'T-395', '2026-06-11 22:03:26', '2026-06-11 22:03:26', NULL, '382a5742e32da0f38c1e143715a0b656', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBJAXQHCKHS8ZSDZNM9NH7QM', 'T-396', '2026-06-12 00:11:50', '2026-06-12 00:11:50', NULL, '20577481e56f82bb0df9e56a266303c9', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBJM6XXQZ3EMGRC13XRYVBEM', 'T-397', '2026-06-12 00:52:25', '2026-06-12 00:52:25', NULL, 'bf89e25b384be60faa65e9eb1ec2fab9', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBKMV7Y13PAYKZC0WB4FQXKC', 'T-398', '2026-06-12 03:15:00', '2026-06-12 03:15:00', NULL, 'd0ed46ee279c148f1d76683e86e0d4aa', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBKMXSVCE98K1H76N00TYCQR', 'T-399', '2026-06-12 03:15:21', '2026-06-12 03:15:21', NULL, 'eacf3522aeb2bccbaf006c9703b9794d', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBKN09R21H3AWR2Q2ZTSGNSW', 'T-400', '2026-06-12 03:15:41', '2026-06-12 03:15:41', NULL, 'a7971f428145d04ae82d4cd89f3eeb9d', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBKN2MP35NPPK1BRDYY2M428', 'T-401', '2026-06-12 03:16:00', '2026-06-12 03:16:00', NULL, '29980034db5fe381473b156ece7d8a1a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBKN4QVFVE51MY2N0CWCVXHM', 'T-402', '2026-06-12 03:16:18', '2026-06-12 03:16:18', NULL, 'c65717bf20ea6886ef7a86f5cb4b2929', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBKP67X1Y1FEE9T5R0E5DA9C', 'T-403', '2026-06-12 03:20:52', '2026-06-12 03:20:52', NULL, '372a686b214820b5d093b11b9f3d57a5', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBKP8KFAF526ZNXBQS98DPPG', 'T-404', '2026-06-12 03:21:11', '2026-06-12 03:21:11', NULL, 'c479a9dea6687b553bc638a9849cc5de', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBKPAZR4XEV8YW3PVR2XJBFC', 'T-405', '2026-06-12 03:21:31', '2026-06-12 03:21:31', NULL, 'e4e1695f838b8fbf02aae49a6f2df4fe', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBKPD85PFBPJJTQ0WS3PWWXR', 'T-406', '2026-06-12 03:21:49', '2026-06-12 03:21:49', NULL, '689352238d2050a3769b2a9613f0a793', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBKPFTC7H5NY0XHBTEGF8XQ4', 'T-407', '2026-06-12 03:22:10', '2026-06-12 03:22:10', NULL, '129d2b3c31022d53025a3e28169a060e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBN3VTK2MYQQ173MSJN6E1DM', 'T-408', '2026-06-12 06:40:25', '2026-06-12 06:40:25', NULL, '0353aaab57a40900b00883fb12e135f7', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBN3VYR84023Z5XFEX9DS0S0', 'T-409', '2026-06-12 06:40:26', '2026-06-12 06:40:26', NULL, '69c280319335a8d0ef646998f4531e96', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBP3EZC7AJANXZVF3D91QYWM', 'T-410', '2026-06-12 08:58:29', '2026-06-12 08:58:29', NULL, '4f726d1a66d38d14018a62c8d24ffe62', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBP3GM6V0RZBY2PXE9ZQFR88', 'T-411', '2026-06-12 08:58:42', '2026-06-12 08:58:42', NULL, 'bdd3f8b13caf25677ac661ec29599488', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBP3J7TXMG0F9E2WQDENPVJG', 'T-412', '2026-06-12 08:58:55', '2026-06-12 08:58:55', NULL, 'e56d50bc6fc04f6d646f22c104e63183', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBP3KRWM65MD3DS251NN9YX0', 'T-413', '2026-06-12 08:59:08', '2026-06-12 08:59:08', NULL, 'b5247ea05c106500682be978a47e61ee', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBP3P8YERJ5R7ENSD675BX00', 'T-414', '2026-06-12 08:59:28', '2026-06-12 08:59:28', NULL, '7d973f16c99441dbba0f8df89a665b32', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBP3P91QQQDT5J50F52FPCKM', 'T-415', '2026-06-12 08:59:28', '2026-06-12 08:59:28', NULL, 'a2dea9268d44b9e8a1fd746bbb947c92', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ8QNGJFFK7G24CBWQAR2C', 'T-416', '2026-06-12 10:25:00', '2026-06-12 10:25:00', NULL, 'f8c2a125e661607d5dd0c73cd2c3f2ab', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBQ4BYD4STCKCY8JNKF23Q4W', 'T-417', '2026-06-12 11:22:15', '2026-06-12 11:22:15', NULL, '15aa9b25417162126cbcde174d3537da', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBQ595H08JFTRFSR90GSZQ0G', 'T-418', '2026-06-12 11:26:14', '2026-06-12 11:26:14', NULL, '000e07ae64b08273a2d2d9f8a77d193f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBTTMGKSYMTF8M1KQWTG774W', 'T-419', '2026-06-12 19:58:58', '2026-06-12 19:58:58', NULL, 'd2b01a2c3d1ce24cc863ac6d9d814d3d', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FC2XY1T85A65YY9SG25VVEY4', 'T-420', '2026-06-13 14:51:51', '2026-06-13 14:51:51', NULL, '16ea4c9353a56798b894ab3d85fb7b56', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCDG3T4A7CYPTG535KVAVH6C', 'T-421', '2026-06-14 15:29:23', '2026-06-14 15:29:23', NULL, 'a28eed4b57104034c5216344a326195c', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCDKX4CVHWVGDAJC6X09602M', 'T-422', '2026-06-14 15:45:57', '2026-06-14 15:45:57', NULL, '5701c634f5737a2ba1612deab8df7049', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCDM61KAA3GV3CVTE8PAZ8N0', 'T-423', '2026-06-14 15:47:10', '2026-06-14 15:47:10', NULL, 'ce7dfb8b9bd088b4c2e8ddfacc8d2124', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCENXW1VF7VXQX64982X171R', 'T-424', '2026-06-14 18:14:36', '2026-06-14 18:14:36', NULL, 'ecbed75dcd34c39bcbd86e60d6f4a2c2', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCENXXZFBZ0HVD1VCW4ZASCC', 'T-425', '2026-06-14 18:14:36', '2026-06-14 18:14:36', NULL, 'b09fc55465f7de02cf98f69c99e0e6e3', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCEP60AS6AF654SWA189A5ZR', 'T-426', '2026-06-14 18:15:42', '2026-06-14 18:15:42', NULL, '91f50c6e38332047f8619db428d4b376', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCEP642C8ZZ1T20RXQQ3143M', 'T-427', '2026-06-14 18:15:43', '2026-06-14 18:15:43', NULL, '55a937def177025ef6b61a222d88b142', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCEP67ZHMBFW0GRH9JKDMQ7R', 'T-428', '2026-06-14 18:15:44', '2026-06-14 18:15:44', NULL, '185e7d3ce8529fbe1f4543f4c635f200', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCEP6BDBHGMK9VCRV6JQ00TW', 'T-429', '2026-06-14 18:15:45', '2026-06-14 18:15:45', NULL, 'ef268614a716384a7597b3e304a6c176', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCEP6EVN9S35T02MHA2AS7YW', 'T-430', '2026-06-14 18:15:46', '2026-06-14 18:15:46', NULL, 'd6333df4da5b7ab8958149a9f0d17974', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCGJ30V24BJB001GZCR5QKTC', 'T-431', '2026-06-14 22:37:27', '2026-06-14 22:37:27', NULL, 'b886820e87f5abd329126bf5e9f1a3da', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCM9ER04JVFW8CN3JW1AWYA8', 'T-432', '2026-06-15 07:18:58', '2026-06-15 07:18:58', NULL, '71f3e4c95f66abc5e7e5820548201e41', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCM9F446MZFXVHH65Q6CKTPM', 'T-433', '2026-06-15 07:19:01', '2026-06-15 07:19:01', NULL, 'b9a361f2c29b286bc808dbea57a05a7e', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCM9FHC8VX50759X35VNER1R', 'T-434', '2026-06-15 07:19:04', '2026-06-15 07:19:04', NULL, '403c4c8aa5659bb379cb8add9dff800b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCM9FYDEXCM15FXTER032K84', 'T-435', '2026-06-15 07:19:08', '2026-06-15 07:19:08', NULL, '7c2ed604aecea99b742b341166cf2257', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCM9GAQ2G0KCVMZS67SK3324', 'T-436', '2026-06-15 07:19:11', '2026-06-15 07:19:11', NULL, '3114ab57de9b03aa1e745af01001eee1', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCNYXXH5AAHZR7WV0550J3RC', 'T-437', '2026-06-15 11:12:36', '2026-06-15 11:12:36', NULL, '74dd08c8c42f556959746ee1a47561e6', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCQ8HB61N3TWVJ8YSMHH2TJ4', 'T-438', '2026-06-15 14:14:23', '2026-06-15 14:14:23', NULL, 'fa072ae8dd819784440bb44b5fe689d8', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCQHWQ40AY6SNVRJ86YWA0J8', 'T-439', '2026-06-15 14:55:15', '2026-06-15 14:55:15', NULL, '2427484ebb324d731cb8e099a2ad04ab', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCQZ47MAN835B215GSSMRV8W', 'T-440', '2026-06-15 15:53:05', '2026-06-15 15:53:05', NULL, 'f219bb1a70eb1f49e30975ce8c526051', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCZDVPBWGM5NHJ9BNQBVKCD0', 'T-441', '2026-06-16 09:16:07', '2026-06-16 09:16:07', NULL, 'fbabc4fc344b34476b38a186c2f44a16', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCZGG38FF8T9ADF945Z0XPMG', 'T-442', '2026-06-16 09:27:39', '2026-06-16 09:27:39', NULL, 'c85d8fd95cd73aec1e83b477612e1131', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCRERT7X5WMZSGKQCA6T0VB4', 'T-440', '2026-06-15 17:01:25', '2026-06-15 17:01:25', NULL, 'b8e152bf87ec8d81d1bddeb023f37883', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCQZ47MAN835B215GSSMRV8W', 'T-443', '2026-06-15 15:53:05', '2026-06-16 10:17:57', NULL, 'a4d4390596d24d7dc28d80861e36d66b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FD07ECS3GK2V7Z2WYYPJHJYC', 'T-444', '2026-06-16 11:07:54', '2026-06-16 11:07:54', NULL, 'ec7a0d8d01c984d931855a6e5c4e86ec', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FD09C4A0HPZSP8HP44F7A894', 'T-445', '2026-06-16 11:16:20', '2026-06-16 11:16:20', NULL, '418d561d50d37c3dd9b6e3abe5fc1b1f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FD09DH88J1659FDDYJ83JH1M', 'T-446', '2026-06-16 11:16:31', '2026-06-16 11:16:31', NULL, '7c0bc42be1a170b5bb2dd8bd7b027d69', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FD09SHDMGT66C4D1DRZQZ7RR', 'T-447', '2026-06-16 11:18:10', '2026-06-16 11:18:10', NULL, '203dfb0348a94392f2d087b79aee655f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FD09TVT3E3ZSV09QRNTSQ8J4', 'T-448', '2026-06-16 11:18:20', '2026-06-16 11:18:20', NULL, '765a91fb5b51889861a41f7eea308ea6', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FD09WB2XSRP0AZ204FDP681M', 'T-449', '2026-06-16 11:18:32', '2026-06-16 11:18:32', NULL, '1dbd17ff345551d3f091a226bb0f7164', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FD09XWEXRJ4JS8MFPQGJEY5M', 'T-450', '2026-06-16 11:18:45', '2026-06-16 11:18:45', NULL, '56f97ccefa83681c387ee9cc4ca6a477', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FD0A0ZTS9JZCSQ4W8ZVEH2VR', 'T-451', '2026-06-16 11:19:11', '2026-06-16 11:19:11', NULL, 'c329f6f1a5d205b7bdf5ab682812a6d1', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FD0A4MY8DF6NB0KNV96RQADR', 'T-452', '2026-06-16 11:19:41', '2026-06-16 11:19:41', NULL, '71a7729a8cf7ebc4e915a9e2736717bd', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FD0A6K9B60ADTFBZA6NBVJFM', 'T-453', '2026-06-16 11:19:57', '2026-06-16 11:19:57', NULL, 'd408d563785166ee1b40e7494c7f3bbc', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FD0ABC7QNEC3XCTV73YPSGR4', 'T-454', '2026-06-16 11:20:36', '2026-06-16 11:20:36', NULL, '27e2ae5b0897eb0f589f4617061101a9', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FD15S1A0WRTY9WWFG0R4AAZ4', 'T-455', '2026-06-16 13:20:25', '2026-06-16 13:20:25', NULL, '370e913c62eab739cf39bda08089e033', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FD15TY946689VZK3MNABSMDW', 'T-456', '2026-06-16 13:20:41', '2026-06-16 13:20:41', NULL, '6041202d66dd93ee3d22206ece3a7db7', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FD15W7SBVAD3QR5NVE67PKWR', 'T-457', '2026-06-16 13:20:52', '2026-06-16 13:20:52', NULL, 'c9bef415fb7d9d03444fde53ecac3bb1', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FD1HK7YKJTEK1WV4VHK0RT8R', 'T-458', '2026-06-16 14:12:04.212', '2026-06-16 14:12:04.212', NULL, '070f1def635ee013df639cb9fe81e357', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FD1JBRABJHX804CPMZJDC444', 'T-459', '2026-06-16 14:15:25.011', '2026-06-16 14:15:25.011', NULL, '44d5db70ef13ead00c4dcc437c387cec', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FD91A7VEW3VCY7QX1END2Z3G', 'T-460', '2026-06-17 07:39:25.019', '2026-06-17 07:39:25.019', NULL, 'e7e749d35dc413a560d3347be5f4a9ee', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FD91RWDWZPHFPJ72FHHHWS08', 'T-461', '2026-06-17 07:41:24.975', '2026-06-17 07:41:24.975', NULL, '4e3fba7aaad762b7b7cd854459cf664a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FDA0TPYSWEM10RP0Q76XAP58', 'T-462', '2026-06-17 09:57:06.422', '2026-06-17 09:57:06.422', NULL, '4be5f7eb00ca81eb07015af05ed144d3', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FDA0VPB99NGS4J6Z5B2RJM2M', 'T-463', '2026-06-17 09:57:14.458', '2026-06-17 09:57:14.458', NULL, 'd5d02453175411c13d21361b084494bd', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FDA0WCPG458GF5FXTXM9VY98', 'T-464', '2026-06-17 09:57:20.180', '2026-06-17 09:57:20.180', NULL, 'c787ef61befc6698286ebdaf613e2a41', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FDA0X5WFME83GS0DKYG3WVJ8', 'T-465', '2026-06-17 09:57:26.627', '2026-06-17 09:57:26.627', NULL, '116b1a377950dfcef4e5b6db90141faa', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FDA0XMA9BQV4RHJ55BFN4JR4', 'T-466', '2026-06-17 09:57:30.322', '2026-06-17 09:57:30.322', NULL, 'd25bc26eb29445fc35cf53f3d54049e5', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FDA0YCY2WGSG8W46RHQ5Z9MW', 'T-467', '2026-06-17 09:57:36.624', '2026-06-17 09:57:36.624', NULL, 'a47c675ca67b86ca3c8d4c1a8acc5b80', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FDA0YYCJ0NK8C4HMDYKJHRDG', 'T-468', '2026-06-17 09:57:41.092', '2026-06-17 09:57:41.092', NULL, 'b988d9578b1ca079c040f07265a008b4', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FDA10DRQE3SED10JAW2CZDCR', 'T-469', '2026-06-17 09:57:53.221', '2026-06-17 09:57:53.221', NULL, '2a72e3e647afc1b5b235ab1a97d298f8', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FDB1VFADV4QK1YG29T658T8C', 'T-470', '2026-06-17 12:21:23.411', '2026-06-17 12:21:23.411', NULL, '0f95e5a1faa7a7e902c765f449cceb15', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FDDJ17C3GZWNE98NRVXP189C', 'T-471', '2026-06-17 18:11:42.049', '2026-06-17 18:11:42.049', NULL, '10a9a957d647a63ce69dc4b6b564f6aa', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FDDTCGG5Z0KNQKF89W1VZSQ8', 'T-472', '2026-06-17 18:48:11.649', '2026-06-17 18:48:11.649', NULL, '097120cff851cb2dac9f54937f4c7b17', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FDDX5GVH3FTCVDEC1QAFACY4', 'T-473', '2026-06-17 19:00:20.828', '2026-06-17 19:00:20.828', NULL, '647782edc3fbb4e7285e4f82a1fb84be', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FDDX5KEAJ8KRWVV7ZSG6H7A0', 'T-474', '2026-06-17 19:00:21.490', '2026-06-17 19:00:21.490', NULL, '79576f18553ed885d3a2b745becdf2f5', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FDEMY3DQWDNY535PMMSB0CSW', 'T-475', '2026-06-17 20:44:11.501', '2026-06-17 20:44:11.501', NULL, 'bb2b56ea9a76d967123238f588c70aba', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FDXN3ZBRS6JK7Q8G6JVSPXFC', 'T-476', '2026-06-19 07:42:08.735', '2026-06-19 07:42:08.735', NULL, 'f75a0a8c00b0ec40c110c1169e42fe2c', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FEWB9JA5CMTXB5D7G1NSHAV4', 'T-477', '2026-06-22 07:13:19.958', '2026-06-22 07:13:19.958', NULL, '0314d96a690bdadc122ce0a1e9ed0f5c', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FFKFYBZFKBX0WV574QJEH2BC', 'T-478', '2026-06-24 13:09:16.923', '2026-06-24 13:09:16.923', NULL, 'f1ea48c2cfa08915841d99eea06a9974', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FFW49VYMPF18PYQXD9PCMHN8', 'T-477', '2026-06-25 09:16:42', '2026-06-25 09:16:42', NULL, '64605163f24e3846463f3afb4ed62fd1', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FFW49W3V175EM4F8ZHC6JFM4', 'T-478', '2026-06-25 09:16:42', '2026-06-25 09:16:42', NULL, '1c2e59e6220c0b288103c4a71a8282ca', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FFW49W6GP535GR8XD1XEHYWG', 'T-479', '2026-06-25 09:16:42', '2026-06-25 09:16:42', NULL, '2a6162f26c4c0b6e7bceb1f1a2ffe167', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FFW49W95HJK08BCRQSWFZBF4', 'T-480', '2026-06-25 09:16:42', '2026-06-25 09:16:42', NULL, '8a42c8c1fc2036d6ea73521266e87235', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FFW49WBTT3ESK6QG0XZ1VN2G', 'T-481', '2026-06-25 09:16:42', '2026-06-25 09:16:42', NULL, 'd1d616d020e6ea8661c1f5553e3001eb', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FFW49WEE5N4PESF5G1G5JRHR', 'T-482', '2026-06-25 09:16:42', '2026-06-25 09:16:42', NULL, '557f92392db9b5c1e6b6840fe1293b7d', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FFW49VYMPF18PYQXD9PCMHN8', 'T-483', '2026-06-25 09:16:42', '2026-06-26 21:35:04.076', NULL, '2841b381bbb03e6a9cdb970280cd2207', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FFW49W3V175EM4F8ZHC6JFM4', 'T-484', '2026-06-25 09:16:42', '2026-06-26 21:35:07.645', NULL, 'd90df1d5e2da44e81f60edb8c5fb2823', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGN13H42TP2MP3T27CTSCDRW', 'T-485', '2026-06-27 19:17:59.713', '2026-06-27 19:17:59.713', NULL, 'b345ba60d55cfdbc7c2e9bb9187ee171', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGPG4WNNH3BWDRVZXYQTW7Z0', 'T-486', '2026-06-27 22:43:31.629', '2026-06-27 22:43:31.629', NULL, 'cd344c35e0eca5673be26790aa8d292c', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSQ789MDB00EQAXTXBVJDXM', 'T-487', '2026-06-28 06:13:51.821', '2026-06-28 06:13:51.821', NULL, '184f63035c0a014dc4fb863e512f8779', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSQ8B7WDKZ174GJDGWW0GS0', 'T-488', '2026-06-28 06:14:00.768', '2026-06-28 06:14:00.768', NULL, '69e3283ee3c10bcd2ca5b5cbad6a8b1f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSQ8YSZA5YNP1JE8SJHXWBG', 'T-489', '2026-06-28 06:14:05.776', '2026-06-28 06:14:05.776', NULL, '0b37f24529eb3bb4f2b295dda3bb04ea', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSQP1YPG70RPQJ4XZDH2T1M', 'T-490', '2026-06-28 06:15:53.077', '2026-06-28 06:15:53.077', NULL, '586b7d8495ad019b436fddbf973c9e63', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGVCY4M0ZK72HZT2FSZF968W', 'T-491', '2026-06-28 10:08:32.933', '2026-06-28 10:08:32.933', NULL, '3895f296d80984ccd613ca9853a05eda', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGVDBD0F14FV5CDJQB063YSR', 'T-492', '2026-06-28 10:10:21.572', '2026-06-28 10:10:21.572', NULL, '341150811f14eb3f4486067ffb1197c4', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGVNCZS0JZP5Y7596GBV4RFC', 'T-493', '2026-06-28 10:45:31.721', '2026-06-28 10:45:31.721', NULL, 'eec40f4714242cf343035481684f2aba', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGX26B0NAC9WRJMVB0QE6CV8', 'T-494', '2026-06-28 14:01:13.733', '2026-06-28 14:01:13.733', NULL, '37bf4baec69cb3d06072793cd3d60a46', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGYPJ6FTEPP4JK3D7D01ZSMM', 'T-495', '2026-06-28 17:50:02.366', '2026-06-28 17:50:02.366', NULL, '40dbd25d323a8192e8f65a6e1c2dd33d', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGYS06SDJGZ4W3Z9V9HDEATW', 'T-496', '2026-06-28 18:00:41.420', '2026-06-28 18:00:41.420', NULL, 'd2e472745c710eb00555b2b824d4e214', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGZK6PWBRBK9J2XPJ55Y3630', 'T-497', '2026-06-28 19:55:10.439', '2026-06-28 19:55:10.439', NULL, '56f8bf5d0e9a52d9ce3c7a293b5f8972', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGZKEHPT1TMFMR0KYFGR087W', 'T-498', '2026-06-28 19:56:14.646', '2026-06-28 19:56:14.646', NULL, 'c62ee89f4aa203262fab74da8604777a', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGZKEHPSSHEG6ZBM0B4DMM6C', 'T-498', '2026-06-28 19:56:14.655', '2026-06-28 19:56:14.655', NULL, '1a47f2a97f13a7565080893758424fec', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGZKEHPW9GMXNACA38MK56HR', 'T-498', '2026-06-28 19:56:14.655', '2026-06-28 19:56:14.655', NULL, '2c606da2b11071cee3bfcee4855d4e66', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGZKJKW1721NKWY6XZG3KYB8', 'T-499', '2026-06-28 19:56:47.968', '2026-06-28 19:56:47.968', NULL, '135e7af3ddf32a676fcfadd150061dd6', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGZKJKW6EDH8TR45M86EWB5M', 'T-499', '2026-06-28 19:56:47.977', '2026-06-28 19:56:47.977', NULL, 'fc370ccee9cd94d0de9988f08963b8f1', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGZKJKW9P697RTQ68R3NKBR8', 'T-499', '2026-06-28 19:56:47.978', '2026-06-28 19:56:47.978', NULL, '99eb5554507cf5b29a158838f156d544', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGZKEHPW9GMXNACA38MK56HR', 'T-500', '2026-06-28 19:56:14.655', '2026-06-28 19:57:02.538', NULL, '6b529f95abd005b73e20b293dcba765c', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGZKEHPT1TMFMR0KYFGR087W', 'T-501', '2026-06-28 19:56:14.646', '2026-06-28 19:57:25.895', NULL, '4e1059be29e69c094168bb55e06704a4', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGZKJKW1721NKWY6XZG3KYB8', 'T-502', '2026-06-28 19:56:47.968', '2026-06-28 19:57:25.904', NULL, '2c08cf1dfc5c7ba16f756db7c80bc300', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGZKJKW6EDH8TR45M86EWB5M', 'T-503', '2026-06-28 19:56:47.977', '2026-06-28 19:57:25.905', NULL, '5177977a9215f17efa101e50b03ad8eb', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGZKJKW9P697RTQ68R3NKBR8', 'T-504', '2026-06-28 19:56:47.978', '2026-06-28 19:57:25.906', NULL, 'cb7f70a279326ff6e29a8c7bdeb78c0f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FH621XBYJBGE1XPSFFK4YZGM', 'T-505', '2026-06-29 10:58:54.943', '2026-06-29 10:58:54.943', NULL, 'b402cc72b921d446a6e4f6c759d72d54', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FHAX7FV5KWGZQ31617R63W94', 'T-506', '2026-06-29 22:16:52.953', '2026-06-29 22:16:52.953', NULL, 'fdeccc75d6a70fae57de814d11695473', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FJ4D0GAXM1FN42PJKG7FE34G', 'T-507', '2026-07-02 09:41:05.241', '2026-07-02 09:41:05.241', NULL, 'd9dec9b9ed45db65467318f53eb05157', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FJ4D1M6ESSSQ1ZERTH4V9YN4', 'T-508', '2026-07-02 09:41:14.425', '2026-07-02 09:41:14.425', NULL, '5389a964251dc22408c41ceac6954f4d', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FJ91RYFXBJH99HJ18QTHY2B0', 'T-509', '2026-07-02 20:31:02.783', '2026-07-02 20:31:02.783', NULL, 'ea835aca1960e1bee3d0710be19b8bba', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FK3CDZQD2JM95ZQY5MH53PWC', 'T-510', '2026-07-05 09:52:40.384', '2026-07-05 09:52:40.384', NULL, '6acffc225f49858f782c8c5e801e1c24', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FNR3DP0D48AZZ3NRA8JF3Q10', 'T-511', '2026-07-13 15:17:10.276', '2026-07-13 15:17:10.276', NULL, 'ffc35cbc7ffe3577e9f103ce6b411857', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
|
INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FNTF7KE5Y497PQC7SCFGR1KC', 'T-512', '2026-07-13 20:48:23.414', '2026-07-13 20:48:23.414', NULL, '90218f8881c60ea87ee29cdfc4e4bdb3', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_idmap.updated_at;
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
INSERT INTO ticket_labels (ticket_record_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCDG3T4A7CYPTG535KVAVH6C', 'multi-window', '2026-06-14 15:29:27', '2026-06-14 15:29:27', NULL, 'ce03f8eb534bc45e2c1c12e9b30a2c30', 2) ON CONFLICT(ticket_record_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_labels.updated_at;
|
||||||
|
INSERT INTO ticket_labels (ticket_record_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCDG3T4A7CYPTG535KVAVH6C', 'ipc', '2026-06-14 15:29:28', '2026-06-14 15:29:28', NULL, 'e6789b66db5c1de85daf6fc8d3474449', 2) ON CONFLICT(ticket_record_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_labels.updated_at;
|
||||||
|
INSERT INTO ticket_labels (ticket_record_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCNYXXH5AAHZR7WV0550J3RC', 'regression', '2026-06-15 11:12:41', '2026-06-15 11:12:41', NULL, 'd1aee45df369a9afed1ecc7bc6043255', 2) ON CONFLICT(ticket_record_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_labels.updated_at;
|
||||||
|
INSERT INTO ticket_labels (ticket_record_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCNYXXH5AAHZR7WV0550J3RC', 'claude-cli', '2026-06-15 11:12:41', '2026-06-15 11:12:41', NULL, '2d486f878edbd7a898ece18900e0d9d6', 2) ON CONFLICT(ticket_record_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_labels.updated_at;
|
||||||
|
INSERT INTO ticket_labels (ticket_record_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCQ8HB61N3TWVJ8YSMHH2TJ4', 'web', '2026-06-15 14:22:06', '2026-06-15 14:22:06', NULL, '6867c9766259a7f09e81ff515973914e', 2) ON CONFLICT(ticket_record_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_labels.updated_at;
|
||||||
|
INSERT INTO ticket_labels (ticket_record_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCQHWQ40AY6SNVRJ86YWA0J8', 'path', '2026-06-15 15:24:11', '2026-06-15 15:24:11', NULL, 'e73b3b85732a2c21be23353a0f7f1493', 2) ON CONFLICT(ticket_record_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_labels.updated_at;
|
||||||
|
INSERT INTO ticket_labels (ticket_record_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCQHWQ40AY6SNVRJ86YWA0J8', 'web', '2026-06-15 15:24:11', '2026-06-15 15:24:11', NULL, '8c93337891e74d67d2465ba2c3b901d5', 2) ON CONFLICT(ticket_record_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_labels.updated_at;
|
||||||
|
INSERT INTO ticket_labels (ticket_record_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCQZ47MAN835B215GSSMRV8W', 'web', '2026-06-15 15:53:35', '2026-06-15 15:53:35', NULL, '4cbf5007b12087b88b8acb36f3616bf8', 2) ON CONFLICT(ticket_record_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= ticket_labels.updated_at;
|
||||||
+173
-173
@@ -1,8 +1,8 @@
|
|||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6RDM2EKZX132GPV7M', 'task', '06FB0TNQM6T6580D8ABDVTMNZW', 'Add PRs tab to sidebar', 'Spec lists PRs as a left-panel section (icon rail position 5). No extension exists yet.', 'backlog', 'low', NULL, NULL, 'D-47', '2026-04-22 21:03:40', '2026-05-07 19:04:55', NULL, '089a32b8ded28139f19eaedafdd54d61', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6RDM2EKZX132GPV7M', 'task', '06FB0TNQM6T6580D8ABDVTMNZW', 'Add PRs tab to sidebar', 'Spec lists PRs as a left-panel section (icon rail position 5). No extension exists yet.', 'backlog', 'low', NULL, NULL, 'D-47', '2026-04-22 21:03:40', '2026-05-07 19:04:55', NULL, '089a32b8ded28139f19eaedafdd54d61', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5GSR5WPC2T7CJM8XW', 'epic', NULL, 'Tier 2 — pane model, editor, active-file awareness, CLI', NULL, 'done', 'medium', NULL, NULL, 'D-6', '2026-04-22 11:45:41', '2026-05-07 19:04:55', NULL, '0bd0e5fb1f1843eaada9520a7566cd65', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5GSR5WPC2T7CJM8XW', 'epic', NULL, 'Tier 2 — pane model, editor, active-file awareness, CLI', NULL, 'done', 'medium', NULL, NULL, 'D-6', '2026-04-22 11:45:41', '2026-05-07 19:04:55', NULL, '0bd0e5fb1f1843eaada9520a7566cd65', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7SS2V5Z1M1XJGQX0M', 'task', NULL, 'codify UI spacing constants (gaps, paddings, control sizes)', NULL, 'done', 'medium', NULL, NULL, NULL, '2026-05-06 13:28:58', '2026-05-07 19:04:55', NULL, '0bf3b9effbd9d99156f941f9e52d6d52', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7SS2V5Z1M1XJGQX0M', 'task', NULL, 'codify UI spacing constants (gaps, paddings, control sizes)', NULL, 'done', 'medium', NULL, NULL, NULL, '2026-05-06 13:28:58', '2026-05-07 19:04:55', NULL, '0bf3b9effbd9d99156f941f9e52d6d52', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7P6Q0DG4RG4CBHFJG', 'story', NULL, 'review Semantics widget coverage and UI testability', 'Audit all interactive widgets for Semantics coverage (labels, roles, states). Verify flutter test can locate and interact with every panel, button, and input via find.bySemanticsLabel. Run the existing a11y test suite and document gaps. Target: every user-facing action is testable without widget keys.', 'backlog', 'medium', NULL, NULL, NULL, '2026-04-24 06:34:16', '2026-05-07 19:04:55', NULL, '0c0e2af920b290c9375864a421b90b37', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7P6Q0DG4RG4CBHFJG', 'story', NULL, 'review Semantics widget coverage and UI testability', 'Audit all interactive widgets for Semantics coverage (labels, roles, states). Verify flutter test can locate and interact with every panel, button, and input via find.bySemanticsLabel. Run the existing a11y test suite and document gaps. Target: every user-facing action is testable without widget keys.', 'backlog', 'medium', NULL, NULL, NULL, '2026-04-24 06:34:16', '2026-05-07 19:04:55', NULL, '0c0e2af920b290c9375864a421b90b37', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4TQEYESK545T8F164', 'task', NULL, 'drag tab reordering in sidebar and context panel', 'Reorder tabs in the sidebar and context panel icon rails by dragging. Persist order to project settings.', 'backlog', 'medium', NULL, NULL, NULL, '2026-04-23 20:32:06', '2026-05-07 19:04:55', NULL, '11588b5a5ec97a4a9693f4221b1fc19e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4TQEYESK545T8F164', 'task', NULL, 'drag tab reordering in sidebar and context panel', 'Reorder tabs in the sidebar and context panel icon rails by dragging. Persist order to project settings.', 'backlog', 'medium', NULL, NULL, NULL, '2026-04-23 20:32:06', '2026-05-07 19:04:55', NULL, '11588b5a5ec97a4a9693f4221b1fc19e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5EP8B65T0AR52TQFW', 'bug', NULL, 'reflow tail-anchor reparenting can dangle on partially-filled lines', '**File:** `lib/src/terminal/src/core/reflow.dart` (`_LineReflow._addPart`).
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5EP8B65T0AR52TQFW', 'bug', NULL, 'reflow tail-anchor reparenting can dangle on partially-filled lines', '**File:** `lib/src/terminal/src/core/reflow.dart` (`_LineReflow._addPart`).
|
||||||
|
|
||||||
**Bug:** Anchors whose x-coordinate sits past the source line''s `trimmedLength` get reparented onto whatever `_builder._result` is active at that moment. After the main reparenting loop has run with `lineFilled` on the final iteration, `_builder.take()` has already moved the filled line into `_lines` and reset `_result` to a fresh empty `BufferLine`. The post-loop block (lines 144-150 in the current source) then reparents the tail anchor onto that fresh empty line. If no further content lands in the builder before `finish()` exits — which is the case whenever the post-loop block fires on a non-wrapped logical line — the empty builder line is never appended to `_lines`, and the anchor ends up pointing to a `BufferLine` that the reflow result never includes.
|
**Bug:** Anchors whose x-coordinate sits past the source line''s `trimmedLength` get reparented onto whatever `_builder._result` is active at that moment. After the main reparenting loop has run with `lineFilled` on the final iteration, `_builder.take()` has already moved the filled line into `_lines` and reset `_result` to a fresh empty `BufferLine`. The post-loop block (lines 144-150 in the current source) then reparents the tail anchor onto that fresh empty line. If no further content lands in the builder before `finish()` exits — which is the case whenever the post-loop block fires on a non-wrapped logical line — the empty builder line is never appended to `_lines`, and the anchor ends up pointing to a `BufferLine` that the reflow result never includes.
|
||||||
@@ -35,9 +35,9 @@ Don''t pick one without re-reading the full reflow flow + every caller of `reflo
|
|||||||
**Surfaced from:** T-91 test sweep (commit 3196c49). The 100% coverage on reflow.dart was achieved by exercising this branch but explicitly *not* asserting on the resulting line being in the output — see the test comment.
|
**Surfaced from:** T-91 test sweep (commit 3196c49). The 100% coverage on reflow.dart was achieved by exercising this branch but explicitly *not* asserting on the resulting line being in the output — see the test comment.
|
||||||
|
|
||||||
**Cross-references:** T-91 (epic parent for the test sweep that found this), T-89 (coverage epic), the test in `test/terminal/core/core_test.dart` group `reflow` named "anchors on the source line tail (past trimmedLength) get reparented" documents the current (buggy) behaviour.
|
**Cross-references:** T-91 (epic parent for the test sweep that found this), T-89 (coverage epic), the test in `test/terminal/core/core_test.dart` group `reflow` named "anchors on the source line tail (past trimmedLength) get reparented" documents the current (buggy) behaviour.
|
||||||
', 'done', 'high', NULL, NULL, NULL, '2026-05-07 05:51:48', '2026-05-07 19:04:55', NULL, '12904b2eafc7660410f6bd0036381d22', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
', 'done', 'high', NULL, NULL, NULL, '2026-05-07 05:51:48', '2026-05-07 19:04:55', NULL, '12904b2eafc7660410f6bd0036381d22', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM76XDA3SZMPWR8WQSC', 'story', NULL, 'auto-refresh decisions and tickets on file change and scheduler tick', 'Decisions panel subscribes to files.changed for decisions/*.md and to the 10-minute scheduler tick. Tickets panel subscribes to files.changed for tickets/ paths and to the 10-minute tick. Both use debounce to coalesce burst events. Keep existing data visible during refresh.', 'done', 'medium', NULL, NULL, NULL, '2026-04-24 06:34:16', '2026-05-07 19:04:55', NULL, '1c44eb72be315595ad2ea9afd494a5ba', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM76XDA3SZMPWR8WQSC', 'story', NULL, 'auto-refresh decisions and tickets on file change and scheduler tick', 'Decisions panel subscribes to files.changed for decisions/*.md and to the 10-minute scheduler tick. Tickets panel subscribes to files.changed for tickets/ paths and to the 10-minute tick. Both use debounce to coalesce burst events. Keep existing data visible during refresh.', 'done', 'medium', NULL, NULL, NULL, '2026-04-24 06:34:16', '2026-05-07 19:04:55', NULL, '1c44eb72be315595ad2ea9afd494a5ba', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5X2K66A0MQY2VZ7H4', 'task', NULL, 'design reusable sortable tab system for multitab panes', NULL, 'done', 'high', NULL, NULL, NULL, '2026-05-06 09:17:39', '2026-05-07 19:04:55', NULL, '1eda66b1427c5679656bf15c2d7e7533', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5X2K66A0MQY2VZ7H4', 'task', NULL, 'design reusable sortable tab system for multitab panes', NULL, 'done', 'high', NULL, NULL, NULL, '2026-05-06 09:17:39', '2026-05-07 19:04:55', NULL, '1eda66b1427c5679656bf15c2d7e7533', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM77477EN2R5872G95M', 'bug', NULL, 'TerminalView.onTapUp callback is wired to a dead path', '**File:** `lib/src/terminal/src/terminal_view.dart` (param + wiring) + `lib/src/terminal/src/ui/gesture/gesture_handler.dart` (pass-through) + `lib/src/terminal/src/ui/gesture/gesture_detector.dart` (dead field).
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM77477EN2R5872G95M', 'bug', NULL, 'TerminalView.onTapUp callback is wired to a dead path', '**File:** `lib/src/terminal/src/terminal_view.dart` (param + wiring) + `lib/src/terminal/src/ui/gesture/gesture_handler.dart` (pass-through) + `lib/src/terminal/src/ui/gesture/gesture_detector.dart` (dead field).
|
||||||
|
|
||||||
**Bug:** `TerminalView.onTapUp` is documented as "Callback for when the user taps on the terminal" but is wired to a code path that is never executed:
|
**Bug:** `TerminalView.onTapUp` is documented as "Callback for when the user taps on the terminal" but is wired to a code path that is never executed:
|
||||||
@@ -74,7 +74,7 @@ Recommendation: **option B**. The "remove unused public API" pattern matches the
|
|||||||
**Surfaced from:** T-91 test sweep on `terminal_view.dart`. The widget test that registered `onTapUp` and tapped via `tester.tap` confirmed the callback never fires regardless of `pumpAndSettle` / gesture flushing.
|
**Surfaced from:** T-91 test sweep on `terminal_view.dart`. The widget test that registered `onTapUp` and tapped via `tester.tap` confirmed the callback never fires regardless of `pumpAndSettle` / gesture flushing.
|
||||||
|
|
||||||
**Cross-references:** T-91 (epic parent), T-89 (coverage epic).
|
**Cross-references:** T-91 (epic parent), T-89 (coverage epic).
|
||||||
', 'done', 'high', NULL, NULL, NULL, '2026-05-07 06:33:47', '2026-05-07 19:04:55', NULL, '2064576379e694666661b7b1a82e995e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
', 'done', 'high', NULL, NULL, NULL, '2026-05-07 06:33:47', '2026-05-07 19:04:55', NULL, '2064576379e694666661b7b1a82e995e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5NS39QCDHNVVVT1R4', 'task', '06FB0TNQM6T6580D8ABDVTMNZW', 'add dart doc generation to CI', 'Wire `dart doc` into the CI pipeline so the public API surface (everything in lib/*.dart barrel exports) renders to HTML on every push to main.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5NS39QCDHNVVVT1R4', 'task', '06FB0TNQM6T6580D8ABDVTMNZW', 'add dart doc generation to CI', 'Wire `dart doc` into the CI pipeline so the public API surface (everything in lib/*.dart barrel exports) renders to HTML on every push to main.
|
||||||
|
|
||||||
**Acceptance:**
|
**Acceptance:**
|
||||||
@@ -82,7 +82,7 @@ INSERT INTO tickets (record_id, type, parent_record_id, title, description, stat
|
|||||||
- Documentation comments on public APIs are validated (no broken references); `dart doc --validate-links` part of the run.
|
- Documentation comments on public APIs are validated (no broken references); `dart doc --validate-links` part of the run.
|
||||||
- Generated docs published somewhere browsable — Gitea Pages, GitHub Pages once the repo moves, or an S3-style static host (decision deferred until Gitea actions land per D-32).
|
- Generated docs published somewhere browsable — Gitea Pages, GitHub Pages once the repo moves, or an S3-style static host (decision deferred until Gitea actions land per D-32).
|
||||||
|
|
||||||
**Not in scope:** writing missing docstrings (separate sweep), private-API docs, package.json-style metadata for pub.dev (we never publish to pub.dev — single binary).', 'done', 'medium', NULL, NULL, 'D-32', '2026-04-22 13:26:29', '2026-05-07 19:04:55', NULL, '2128b4a4ae28fcacd71b072868fc2d14', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
**Not in scope:** writing missing docstrings (separate sweep), private-API docs, package.json-style metadata for pub.dev (we never publish to pub.dev — single binary).', 'done', 'medium', NULL, NULL, 'D-32', '2026-04-22 13:26:29', '2026-05-07 19:04:55', NULL, '2128b4a4ae28fcacd71b072868fc2d14', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7Y0DFP66HSP073XHC', 'task', NULL, 'track dugite-native upstream releases for security updates', 'D-59 (bundled git via dugite-native) costs out: "Must track dugite-native releases for security updates." Up to today this lived only in the D-record prose with no tracking — clean-house v1 flagged it as RULE-SUNSET-WITHOUT-TICKET.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7Y0DFP66HSP073XHC', 'task', NULL, 'track dugite-native upstream releases for security updates', 'D-59 (bundled git via dugite-native) costs out: "Must track dugite-native releases for security updates." Up to today this lived only in the D-record prose with no tracking — clean-house v1 flagged it as RULE-SUNSET-WITHOUT-TICKET.
|
||||||
|
|
||||||
**Acceptance:**
|
**Acceptance:**
|
||||||
@@ -92,15 +92,15 @@ INSERT INTO tickets (record_id, type, parent_record_id, title, description, stat
|
|||||||
|
|
||||||
**Periodicity:** quarterly check is enough during normal operation; faster on git CVE announcements (subscribe to https://github.com/git/git/security/advisories, https://github.com/desktop/dugite-native/security/advisories).
|
**Periodicity:** quarterly check is enough during normal operation; faster on git CVE announcements (subscribe to https://github.com/git/git/security/advisories, https://github.com/desktop/dugite-native/security/advisories).
|
||||||
|
|
||||||
**Out of scope:** the rebuild itself is T-25 (CI reproducible build for libtree-sitter.so) — same shape applies to dugite. This ticket is the calendar; T-25 is the machine.', 'backlog', 'low', NULL, NULL, 'D-59', '2026-05-06 14:34:35', '2026-05-07 19:04:55', NULL, '2a6bbef9dbb21a40a1dfd90e882f0e62', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
**Out of scope:** the rebuild itself is T-25 (CI reproducible build for libtree-sitter.so) — same shape applies to dugite. This ticket is the calendar; T-25 is the machine.', 'backlog', 'low', NULL, NULL, 'D-59', '2026-05-06 14:34:35', '2026-05-07 19:04:55', NULL, '2a6bbef9dbb21a40a1dfd90e882f0e62', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4005W4QV0ZPBMQ02C', 'story', '06FB0TNQM5GSR5WPC2T7CJM8XW', 'Implement editor-above-Claude mode in middle column', '⌘E opens editor above Claude with draggable divider, 30-40% height. ⌘W closes. Viewer ↔ editor swap: ✎ promotes to editor, 👁 demotes to viewer. Prompt bar Y stays fixed.', 'done', 'medium', NULL, NULL, 'D-49', '2026-04-22 20:34:06', '2026-05-07 19:04:55', NULL, '2fbe8bb6f449c6442b8972a0d2b11dd8', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4005W4QV0ZPBMQ02C', 'story', '06FB0TNQM5GSR5WPC2T7CJM8XW', 'Implement editor-above-Claude mode in middle column', '⌘E opens editor above Claude with draggable divider, 30-40% height. ⌘W closes. Viewer ↔ editor swap: ✎ promotes to editor, 👁 demotes to viewer. Prompt bar Y stays fixed.', 'done', 'medium', NULL, NULL, 'D-49', '2026-04-22 20:34:06', '2026-05-07 19:04:55', NULL, '2fbe8bb6f449c6442b8972a0d2b11dd8', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM454GCK8ENRKRA44NW', 'story', NULL, 'native folder picker for Open Workspace', 'Replace the text input in the welcome screen Open Workspace flow with a native folder picker dialog (gtk_file_chooser on Linux, NSOpenPanel on macOS). Fall back to the text input if the native dialog is unavailable. The selected path should validate as a git repo before opening.', 'done', 'medium', NULL, NULL, NULL, '2026-04-23 20:31:35', '2026-05-07 19:04:55', NULL, '30493e1d88497d9e9fd0df5f97c10e19', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM454GCK8ENRKRA44NW', 'story', NULL, 'native folder picker for Open Workspace', 'Replace the text input in the welcome screen Open Workspace flow with a native folder picker dialog (gtk_file_chooser on Linux, NSOpenPanel on macOS). Fall back to the text input if the native dialog is unavailable. The selected path should validate as a git repo before opening.', 'done', 'medium', NULL, NULL, NULL, '2026-04-23 20:31:35', '2026-05-07 19:04:55', NULL, '30493e1d88497d9e9fd0df5f97c10e19', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7CEKQCMZAV751402G', 'story', '06FB0TNQM79H4MPEWW2TWQ89D0', 'clide self-update mechanism', 'Check for new versions on startup (or on demand via command palette). Show a non-intrusive notification when an update is available. Support in-place update without losing running Claude sessions (tmux sessions survive). Respect POLICY.md: no silent network calls on default launch path — the check should be opt-in or gated behind a setting. Consider delta updates for bandwidth efficiency.', 'backlog', 'medium', NULL, NULL, NULL, '2026-04-23 20:28:43', '2026-05-07 19:04:55', NULL, '31a55dc12bc4f0ee447dc2ab853613c1', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7CEKQCMZAV751402G', 'story', '06FB0TNQM79H4MPEWW2TWQ89D0', 'clide self-update mechanism', 'Check for new versions on startup (or on demand via command palette). Show a non-intrusive notification when an update is available. Support in-place update without losing running Claude sessions (tmux sessions survive). Respect POLICY.md: no silent network calls on default launch path — the check should be opt-in or gated behind a setting. Consider delta updates for bandwidth efficiency.', 'backlog', 'medium', NULL, NULL, NULL, '2026-04-23 20:28:43', '2026-05-07 19:04:55', NULL, '31a55dc12bc4f0ee447dc2ab853613c1', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM50X0DX8XTVZEA5GN8', 'story', NULL, 'workspace trust prompt', 'Prompt before running extensions or loading project settings in untrusted repositories. Trust decision persisted per repo path. Untrusted mode disables third-party extensions and restricts IPC commands.', 'backlog', 'medium', NULL, NULL, NULL, '2026-04-23 20:32:06', '2026-05-07 19:04:55', NULL, '32fd3d312ab5d4fa379911ea408825b0', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM50X0DX8XTVZEA5GN8', 'story', NULL, 'workspace trust prompt', 'Prompt before running extensions or loading project settings in untrusted repositories. Trust decision persisted per repo path. Untrusted mode disables third-party extensions and restricts IPC commands.', 'backlog', 'medium', NULL, NULL, NULL, '2026-04-23 20:32:06', '2026-05-07 19:04:55', NULL, '32fd3d312ab5d4fa379911ea408825b0', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6P00AT6KGVZ1EF60C', 'task', NULL, 'audit error handling in PTY and IPC critical paths', NULL, 'done', 'medium', NULL, NULL, 'D-5', '2026-04-22 13:26:29', '2026-05-07 19:04:55', NULL, '388873359f62ba188715066ed30d88c1', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6P00AT6KGVZ1EF60C', 'task', NULL, 'audit error handling in PTY and IPC critical paths', NULL, 'done', 'medium', NULL, NULL, 'D-5', '2026-04-22 13:26:29', '2026-05-07 19:04:55', NULL, '388873359f62ba188715066ed30d88c1', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM427FX3GTR3VNNKM40', 'task', NULL, 'manual refresh button in sidebar panels', 'Add a small arrowClockwise icon button next to the filter box in decisions, tickets, and pql markdown panels. Triggers immediate data reload. Disabled while refresh is in-flight.', 'done', 'medium', NULL, NULL, NULL, '2026-04-24 06:34:16', '2026-05-07 19:04:55', NULL, '3cdf2629c314204365d9ad6a56bf9546', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM427FX3GTR3VNNKM40', 'task', NULL, 'manual refresh button in sidebar panels', 'Add a small arrowClockwise icon button next to the filter box in decisions, tickets, and pql markdown panels. Triggers immediate data reload. Disabled while refresh is in-flight.', 'done', 'medium', NULL, NULL, NULL, '2026-04-24 06:34:16', '2026-05-07 19:04:55', NULL, '3cdf2629c314204365d9ad6a56bf9546', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM66FTCTWHH9AQTNFKR', 'story', NULL, 'system tray and dock persistence', 'Minimize to system tray on Linux (AppIndicator) or Dock on macOS. Reopening from tray restores the window without cold boot. tmux sessions stay alive in background regardless.', 'backlog', 'medium', NULL, NULL, NULL, '2026-04-23 20:32:06', '2026-05-07 19:04:55', NULL, '3e40de19315f626560fb598a06e86cea', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM66FTCTWHH9AQTNFKR', 'story', NULL, 'system tray and dock persistence', 'Minimize to system tray on Linux (AppIndicator) or Dock on macOS. Reopening from tray restores the window without cold boot. tmux sessions stay alive in background regardless.', 'backlog', 'medium', NULL, NULL, NULL, '2026-04-23 20:32:06', '2026-05-07 19:04:55', NULL, '3e40de19315f626560fb598a06e86cea', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM79H4MPEWW2TWQ89D0', 'epic', NULL, 'cross-platform clide installer', 'Build a distribution-aware installer for clide. Detects platform (Linux distro, macOS, WSL) and package manager (apt, dnf, pacman, brew, winget). Handles: Flutter runtime or bundled AOT binary, ptyc compilation or prebuilt binary, tmux and other runtime dependencies, font installation (Josefin Sans, JetBrains Mono, Phosphor Icons), desktop entry / .app bundle / Start Menu shortcut, and PATH registration. Should support both interactive install and headless CI mode (--unattended). Consider AppImage/Flatpak for Linux, .dmg for macOS.', 'backlog', 'medium', NULL, NULL, NULL, '2026-04-23 20:27:58', '2026-05-07 19:04:55', NULL, '424f000fff97ccd5e2c8a4eb260d7b3e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM79H4MPEWW2TWQ89D0', 'epic', NULL, 'cross-platform clide installer', 'Build a distribution-aware installer for clide. Detects platform (Linux distro, macOS, WSL) and package manager (apt, dnf, pacman, brew, winget). Handles: Flutter runtime or bundled AOT binary, ptyc compilation or prebuilt binary, tmux and other runtime dependencies, font installation (Josefin Sans, JetBrains Mono, Phosphor Icons), desktop entry / .app bundle / Start Menu shortcut, and PATH registration. Should support both interactive install and headless CI mode (--unattended). Consider AppImage/Flatpak for Linux, .dmg for macOS.', 'backlog', 'medium', NULL, NULL, NULL, '2026-04-23 20:27:58', '2026-05-07 19:04:55', NULL, '424f000fff97ccd5e2c8a4eb260d7b3e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM734YZ060Q63H40EYG', 'task', NULL, 'Standardize errno constants + logger in PTY/IPC/daemon', 'From the PTY/IPC error-handling audit (T-18, see docs/audits/pty-ipc-error-handling-2026-05-05.md). Two cleanup items rolled together:
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM734YZ060Q63H40EYG', 'task', NULL, 'Standardize errno constants + logger in PTY/IPC/daemon', 'From the PTY/IPC error-handling audit (T-18, see docs/audits/pty-ipc-error-handling-2026-05-05.md). Two cleanup items rolled together:
|
||||||
|
|
||||||
**Errno constants (audit item #23):**
|
**Errno constants (audit item #23):**
|
||||||
@@ -114,10 +114,10 @@ INSERT INTO tickets (record_id, type, parent_record_id, title, description, stat
|
|||||||
- Pick one logger interface (kernel `log` already exists for the app side), wire `DaemonServer` and the daemon-side handlers to use it.
|
- Pick one logger interface (kernel `log` already exists for the app side), wire `DaemonServer` and the daemon-side handlers to use it.
|
||||||
- Dispatch error messages should prefix with the request `cmd` so log correlation works (audit item #26).
|
- Dispatch error messages should prefix with the request `cmd` so log correlation works (audit item #26).
|
||||||
|
|
||||||
**Out of scope for this ticket:** changes to log-LEVEL policy, log retention, log files vs stderr — pure substitution job.', 'backlog', 'low', NULL, NULL, NULL, '2026-05-05 12:58:59', '2026-05-07 19:04:55', NULL, '4c0e40a586fa780532aff53460a6a8dc', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
**Out of scope for this ticket:** changes to log-LEVEL policy, log retention, log files vs stderr — pure substitution job.', 'backlog', 'low', NULL, NULL, NULL, '2026-05-05 12:58:59', '2026-05-07 19:04:55', NULL, '4c0e40a586fa780532aff53460a6a8dc', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7DV4ZS010XWZJ9A84', 'epic', NULL, 'Tier 4 — pql integration: query panel, file tree, backlinks, problems', NULL, 'done', 'medium', NULL, NULL, 'D-3', '2026-04-22 11:45:41', '2026-05-07 19:04:55', NULL, '4c409f6313eca2db64e10bc13dc36a0a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7DV4ZS010XWZJ9A84', 'epic', NULL, 'Tier 4 — pql integration: query panel, file tree, backlinks, problems', NULL, 'done', 'medium', NULL, NULL, 'D-3', '2026-04-22 11:45:41', '2026-05-07 19:04:55', NULL, '4c409f6313eca2db64e10bc13dc36a0a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM62E3MNW8TBTKSR9GM', 'task', '06FB0TNQM7DV4ZS010XWZJ9A84', 'validate pql init installation cycle', NULL, 'done', 'medium', NULL, NULL, 'D-39', '2026-04-22 09:41:51', '2026-05-07 19:04:55', NULL, '4e2209accbd6cdb2732da96ba06212eb', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM62E3MNW8TBTKSR9GM', 'task', '06FB0TNQM7DV4ZS010XWZJ9A84', 'validate pql init installation cycle', NULL, 'done', 'medium', NULL, NULL, 'D-39', '2026-04-22 09:41:51', '2026-05-07 19:04:55', NULL, '4e2209accbd6cdb2732da96ba06212eb', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM460GRBMZMV8E5339M', 'task', NULL, 'IPC server: per-request timeout, broadcast logging, stale-socket race', NULL, 'done', 'high', NULL, NULL, NULL, '2026-05-05 12:58:59', '2026-05-07 19:04:55', NULL, '4ebb203c91dfc0cc58c23879a077b409', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM460GRBMZMV8E5339M', 'task', NULL, 'IPC server: per-request timeout, broadcast logging, stale-socket race', NULL, 'done', 'high', NULL, NULL, NULL, '2026-05-05 12:58:59', '2026-05-07 19:04:55', NULL, '4ebb203c91dfc0cc58c23879a077b409', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7162Z26FDWXG35VH0', 'epic', NULL, 'Tier 5 — canvas and graph view', 'Tier 5 of the build plan: bring the canvas pane (Obsidian-style spatial whiteboard) and the graph view (force-directed view of vault links) to feature parity.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7162Z26FDWXG35VH0', 'epic', NULL, 'Tier 5 — canvas and graph view', 'Tier 5 of the build plan: bring the canvas pane (Obsidian-style spatial whiteboard) and the graph view (force-directed view of vault links) to feature parity.
|
||||||
|
|
||||||
**Canvas pane (`builtin.canvas`):**
|
**Canvas pane (`builtin.canvas`):**
|
||||||
@@ -132,11 +132,11 @@ INSERT INTO tickets (record_id, type, parent_record_id, title, description, stat
|
|||||||
- Filter pane: tag include/exclude, file glob, depth-from-active.
|
- Filter pane: tag include/exclude, file glob, depth-from-active.
|
||||||
- pql provides the link data (`pql backlinks` / `pql outlinks`); rendering owned in-app.
|
- pql provides the link data (`pql backlinks` / `pql outlinks`); rendering owned in-app.
|
||||||
|
|
||||||
Both panes use the existing `MultitabPane` (T-83) for tab management once they ship. Each lives in its own slot per D-47 (canvas in workspace, graph in context panel).', 'backlog', 'medium', NULL, NULL, 'D-17', '2026-04-22 11:45:41', '2026-05-07 19:04:55', NULL, '500ef5c50eda06e7a656cd91f8b5aebc', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Both panes use the existing `MultitabPane` (T-83) for tab management once they ship. Each lives in its own slot per D-47 (canvas in workspace, graph in context panel).', 'backlog', 'medium', NULL, NULL, 'D-17', '2026-04-22 11:45:41', '2026-05-07 19:04:55', NULL, '500ef5c50eda06e7a656cd91f8b5aebc', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM50DVPFP4WY74RQBB8', 'task', NULL, 'kernel scheduler service with tiered timer events', 'Add SchedulerService to the kernel with Timer.periodic instances at five tiers (1min, 10min, 15min, 60min, midnight). Emits SchedulerTick events on the DaemonBus. Extensions subscribe and filter by tier.', 'done', 'medium', NULL, NULL, NULL, '2026-04-24 06:34:16', '2026-05-07 19:04:55', NULL, '52ddb1654c819675daad6f00013b97a2', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM50DVPFP4WY74RQBB8', 'task', NULL, 'kernel scheduler service with tiered timer events', 'Add SchedulerService to the kernel with Timer.periodic instances at five tiers (1min, 10min, 15min, 60min, midnight). Emits SchedulerTick events on the DaemonBus. Extensions subscribe and filter by tier.', 'done', 'medium', NULL, NULL, NULL, '2026-04-24 06:34:16', '2026-05-07 19:04:55', NULL, '52ddb1654c819675daad6f00013b97a2', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4QHBTA4VE6TWQT43R', 'task', '06FB0TNQM7DV4ZS010XWZJ9A84', 'pql query panel — sidebar tab for vault queries', NULL, 'done', 'medium', NULL, NULL, 'D-3', '2026-04-22 11:47:18', '2026-05-07 19:04:55', NULL, '54f291ecabdb2450d339156fbeb74346', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4QHBTA4VE6TWQT43R', 'task', '06FB0TNQM7DV4ZS010XWZJ9A84', 'pql query panel — sidebar tab for vault queries', NULL, 'done', 'medium', NULL, NULL, 'D-3', '2026-04-22 11:47:18', '2026-05-07 19:04:55', NULL, '54f291ecabdb2450d339156fbeb74346', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4XZA5399D2EHYCVFC', 'epic', NULL, 'Tier 3 — git panel, diff tab, clide git CLI', NULL, 'done', 'medium', NULL, NULL, 'D-13', '2026-04-22 11:45:41', '2026-05-07 19:04:55', NULL, '593a5ab99da6ded40b6fc5b6a0563546', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4XZA5399D2EHYCVFC', 'epic', NULL, 'Tier 3 — git panel, diff tab, clide git CLI', NULL, 'done', 'medium', NULL, NULL, 'D-13', '2026-04-22 11:45:41', '2026-05-07 19:04:55', NULL, '593a5ab99da6ded40b6fc5b6a0563546', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM64DC28XV20JJ8KW00', 'story', NULL, 'Wire canonical keyboard shortcuts from interaction model', 'Add commands and keybindings: ⌘⇧1/⌘⇧3 collapse, ⌘1/⌘2/⌘3 focus panel, ⌘. focus mode, ⌥1-5 left section switch, ⌘E editor, ⌘W close editor, Esc dismiss.', 'done', 'high', NULL, NULL, 'D-54', '2026-04-22 20:34:01', '2026-05-07 19:04:55', NULL, '5b7704d640d42c839175a961c51d6ac8', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM64DC28XV20JJ8KW00', 'story', NULL, 'Wire canonical keyboard shortcuts from interaction model', 'Add commands and keybindings: ⌘⇧1/⌘⇧3 collapse, ⌘1/⌘2/⌘3 focus panel, ⌘. focus mode, ⌥1-5 left section switch, ⌘E editor, ⌘W close editor, Esc dismiss.', 'done', 'high', NULL, NULL, 'D-54', '2026-04-22 20:34:01', '2026-05-07 19:04:55', NULL, '5b7704d640d42c839175a961c51d6ac8', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM79CNBXJ2S3CFQR7VM', 'task', NULL, 'Misc PTY/IPC/git polish (audit medium-priority items)', 'Catch-all for the medium-priority items from the PTY/IPC error-handling audit (T-18, see docs/audits/pty-ipc-error-handling-2026-05-05.md) that didn`t earn dedicated tickets:
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM79CNBXJ2S3CFQR7VM', 'task', NULL, 'Misc PTY/IPC/git polish (audit medium-priority items)', 'Catch-all for the medium-priority items from the PTY/IPC error-handling audit (T-18, see docs/audits/pty-ipc-error-handling-2026-05-05.md) that didn`t earn dedicated tickets:
|
||||||
|
|
||||||
- **#17** — `files.read` `readAsStringSync` is unguarded; UTF-8 errors / permissions / mid-read deletion become 500-style dispatch errors. Wrap in try/catch and emit a clean `IpcResponse.err`.
|
- **#17** — `files.read` `readAsStringSync` is unguarded; UTF-8 errors / permissions / mid-read deletion become 500-style dispatch errors. Wrap in try/catch and emit a clean `IpcResponse.err`.
|
||||||
@@ -148,15 +148,15 @@ INSERT INTO tickets (record_id, type, parent_record_id, title, description, stat
|
|||||||
- **#28** — `IpcResponse.fromJson` throws `TypeError` on a malformed peer response missing `error`. Graceful degrade.
|
- **#28** — `IpcResponse.fromJson` throws `TypeError` on a malformed peer response missing `error`. Graceful degrade.
|
||||||
- **#29** — PATH resolution in `native_pty.dart` uses the first existing match without `X_OK` check; non-executable files shadow valid binaries further along PATH.
|
- **#29** — PATH resolution in `native_pty.dart` uses the first existing match without `X_OK` check; non-executable files shadow valid binaries further along PATH.
|
||||||
|
|
||||||
Land each as a small focused commit; ticket closes when all items above are merged.', 'backlog', 'low', NULL, NULL, NULL, '2026-05-05 12:58:59', '2026-05-07 19:04:55', NULL, '5c2549784fb9173868ab84a7812e928e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Land each as a small focused commit; ticket closes when all items above are merged.', 'backlog', 'low', NULL, NULL, NULL, '2026-05-05 12:58:59', '2026-05-07 19:04:55', NULL, '5c2549784fb9173868ab84a7812e928e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM67ZXPWX71ND4C699C', 'story', '06FB0TNQM6M1VZ8Z2SZ94F0EQR', 'Ship clide tmux.conf for Claude pane sessions', 'Bundle a clide-specific tmux.conf (no status bar, large scrollback, zero escape delay, 256color passthrough). Claude pane spawn passes -f to use it. Includes bottom-anchoring via initial escape sequence or shell profile trick after attach.', 'done', 'high', NULL, NULL, 'D-41', '2026-04-22 22:01:13', '2026-05-07 19:04:55', NULL, '60497a8d7f7ca4c5dba68187ddc8c594', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM67ZXPWX71ND4C699C', 'story', '06FB0TNQM6M1VZ8Z2SZ94F0EQR', 'Ship clide tmux.conf for Claude pane sessions', 'Bundle a clide-specific tmux.conf (no status bar, large scrollback, zero escape delay, 256color passthrough). Claude pane spawn passes -f to use it. Includes bottom-anchoring via initial escape sequence or shell profile trick after attach.', 'done', 'high', NULL, NULL, 'D-41', '2026-04-22 22:01:13', '2026-05-07 19:04:55', NULL, '60497a8d7f7ca4c5dba68187ddc8c594', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5QHMB46NSHHPVQRF0', 'task', '06FB0TNQM6M1VZ8Z2SZ94F0EQR', 'secondary Claude pane UI wiring', NULL, 'done', 'medium', NULL, NULL, 'D-41', '2026-04-22 14:08:40', '2026-05-07 19:04:55', NULL, '60707a19e9176a9e4b62ce0672bd5f68', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5QHMB46NSHHPVQRF0', 'task', '06FB0TNQM6M1VZ8Z2SZ94F0EQR', 'secondary Claude pane UI wiring', NULL, 'done', 'medium', NULL, NULL, 'D-41', '2026-04-22 14:08:40', '2026-05-07 19:04:55', NULL, '60707a19e9176a9e4b62ce0672bd5f68', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4Q4XW93E3WA1SD9KW', 'task', NULL, 'PTY: surface errno from forkpty/execve/write/ioctl failures', NULL, 'done', 'high', NULL, NULL, NULL, '2026-05-05 12:58:59', '2026-05-07 19:04:55', NULL, '6a8edaab6a388961f032fd4151e7be70', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4Q4XW93E3WA1SD9KW', 'task', NULL, 'PTY: surface errno from forkpty/execve/write/ioctl failures', NULL, 'done', 'high', NULL, NULL, NULL, '2026-05-05 12:58:59', '2026-05-07 19:04:55', NULL, '6a8edaab6a388961f032fd4151e7be70', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4W194B2421P2SF83R', 'task', '06FB0TNQM6T6580D8ABDVTMNZW', 'CI reproducible build for libtree-sitter.so', 'BUILD.md at app/native/linux-x64/ has TODO checklist: build from pinned source SHA in CI, record SHA-256, cross-compile for macOS (aarch64, x86_64) and Windows (x86_64). Currently built on contributor machine.', 'backlog', 'medium', NULL, NULL, NULL, '2026-04-22 20:14:24', '2026-05-07 19:04:55', NULL, '6dd3b1f754ee2b4b8177d51384917f61', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4W194B2421P2SF83R', 'task', '06FB0TNQM6T6580D8ABDVTMNZW', 'CI reproducible build for libtree-sitter.so', 'BUILD.md at app/native/linux-x64/ has TODO checklist: build from pinned source SHA in CI, record SHA-256, cross-compile for macOS (aarch64, x86_64) and Windows (x86_64). Currently built on contributor machine.', 'backlog', 'medium', NULL, NULL, NULL, '2026-04-22 20:14:24', '2026-05-07 19:04:55', NULL, '6dd3b1f754ee2b4b8177d51384917f61', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6JXWYYQ6MT6N8STYM', 'task', '06FB0TNQM7DV4ZS010XWZJ9A84', 'Contribute markdown viewer tab to context panel', 'The markdown shipped extension exists as a stub but doesn''t contribute a TabContribution to Slots.contextPanel. Spec lists viewer as the primary right-panel section.', 'done', 'medium', NULL, NULL, 'D-47', '2026-04-22 21:03:40', '2026-05-07 19:04:55', NULL, '6e1744b2365f3fdfac29a67d59491e5e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6JXWYYQ6MT6N8STYM', 'task', '06FB0TNQM7DV4ZS010XWZJ9A84', 'Contribute markdown viewer tab to context panel', 'The markdown shipped extension exists as a stub but doesn''t contribute a TabContribution to Slots.contextPanel. Spec lists viewer as the primary right-panel section.', 'done', 'medium', NULL, NULL, 'D-47', '2026-04-22 21:03:40', '2026-05-07 19:04:55', NULL, '6e1744b2365f3fdfac29a67d59491e5e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM70QNVQY1MQGP3A33G', 'bug', NULL, 'files.read path traversal — validate paths stay under workspace root', NULL, 'done', 'high', NULL, NULL, NULL, '2026-05-05 12:58:59', '2026-05-07 19:04:55', NULL, '7035741737fc86fd87dd406858d53185', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM70QNVQY1MQGP3A33G', 'bug', NULL, 'files.read path traversal — validate paths stay under workspace root', NULL, 'done', 'high', NULL, NULL, NULL, '2026-05-05 12:58:59', '2026-05-07 19:04:55', NULL, '7035741737fc86fd87dd406858d53185', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM75XRV8AQG2HEQZEJ0', 'task', '06FB0TNQM7DV4ZS010XWZJ9A84', 'problems panel — surface pql doctor + validate warnings', NULL, 'done', 'medium', NULL, NULL, 'D-3', '2026-04-22 11:47:18', '2026-05-07 19:04:55', NULL, '77cb623b768e6276dafff9eabac364fb', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM75XRV8AQG2HEQZEJ0', 'task', '06FB0TNQM7DV4ZS010XWZJ9A84', 'problems panel — surface pql doctor + validate warnings', NULL, 'done', 'medium', NULL, NULL, 'D-3', '2026-04-22 11:47:18', '2026-05-07 19:04:55', NULL, '77cb623b768e6276dafff9eabac364fb', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4M63G18VAQFG6R3XW', 'task', '06FB0TNQM6T6580D8ABDVTMNZW', 'feed POLICY.md rules into D-records', 'POLICY.md (added 2026-04-22) defines rules for: no-network-on-default-launch-path, dependency vetting checklist, vendored binary rebuild process, telemetry prohibition, license compatibility matrix. These need corresponding D-records in decisions/ so the architectural decision trail is complete. Some may overlap with or supersede existing D-records.', 'done', 'medium', NULL, NULL, NULL, '2026-04-22 20:14:52', '2026-05-07 19:04:55', NULL, '7d51899d6c3b30effc9596c8cb26367b', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4M63G18VAQFG6R3XW', 'task', '06FB0TNQM6T6580D8ABDVTMNZW', 'feed POLICY.md rules into D-records', 'POLICY.md (added 2026-04-22) defines rules for: no-network-on-default-launch-path, dependency vetting checklist, vendored binary rebuild process, telemetry prohibition, license compatibility matrix. These need corresponding D-records in decisions/ so the architectural decision trail is complete. Some may overlap with or supersede existing D-records.', 'done', 'medium', NULL, NULL, NULL, '2026-04-22 20:14:52', '2026-05-07 19:04:55', NULL, '7d51899d6c3b30effc9596c8cb26367b', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6T6580D8ABDVTMNZW', 'epic', NULL, 'Tier 6 — extension API, settings, theming, distributable builds', 'Tier 6 of the build plan: the things that make clide a real product instead of a working prototype.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6T6580D8ABDVTMNZW', 'epic', NULL, 'Tier 6 — extension API, settings, theming, distributable builds', 'Tier 6 of the build plan: the things that make clide a real product instead of a working prototype.
|
||||||
|
|
||||||
**Extension API (third-party Lua):**
|
**Extension API (third-party Lua):**
|
||||||
@@ -180,9 +180,9 @@ INSERT INTO tickets (record_id, type, parent_record_id, title, description, stat
|
|||||||
- Self-update mechanism — see T-47.
|
- Self-update mechanism — see T-47.
|
||||||
- License manifest auto-regen as part of the release build.
|
- License manifest auto-regen as part of the release build.
|
||||||
|
|
||||||
Big epic — children land incrementally. Most concrete child tickets already exist; this is the umbrella.', 'backlog', 'medium', NULL, NULL, 'D-15', '2026-04-22 11:45:41', '2026-05-07 19:04:55', NULL, '7f30f7e08fb60ff98d8d92a4fba6a60d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Big epic — children land incrementally. Most concrete child tickets already exist; this is the umbrella.', 'backlog', 'medium', NULL, NULL, 'D-15', '2026-04-22 11:45:41', '2026-05-07 19:04:55', NULL, '7f30f7e08fb60ff98d8d92a4fba6a60d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM699HAWC76SHRA7AM4', 'task', '06FB0TNQM5GSR5WPC2T7CJM8XW', 'implement welcome screen per hi-fi design', NULL, 'done', 'medium', NULL, NULL, 'D-43', '2026-04-22 14:08:40', '2026-05-07 19:04:55', NULL, '84f40649f98dd8e3e944fac492c81561', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM699HAWC76SHRA7AM4', 'task', '06FB0TNQM5GSR5WPC2T7CJM8XW', 'implement welcome screen per hi-fi design', NULL, 'done', 'medium', NULL, NULL, 'D-43', '2026-04-22 14:08:40', '2026-05-07 19:04:55', NULL, '84f40649f98dd8e3e944fac492c81561', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6PMW57C70KBJVAV10', 'task', '06FB0TNQM5GSR5WPC2T7CJM8XW', 'multi-buffer editor tabs', NULL, 'cancelled', 'medium', NULL, NULL, 'D-6', '2026-04-22 14:08:40', '2026-05-07 19:04:55', NULL, '8649e78bfc5229e2409dca4ff3c25732', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6PMW57C70KBJVAV10', 'task', '06FB0TNQM5GSR5WPC2T7CJM8XW', 'multi-buffer editor tabs', NULL, 'cancelled', 'medium', NULL, NULL, 'D-6', '2026-04-22 14:08:40', '2026-05-07 19:04:55', NULL, '8649e78bfc5229e2409dca4ff3c25732', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM52JT96V5067SM0DMR', 'bug', NULL, 'kill secondary Claude tmux sessions on tab close and on app shutdown', 'D-41 lifecycle contract: "closing a secondary kills that tmux session" and "secondary numbering (-1, -2, ...) resets between clide runs since ephemeral state is lost" — the second clause only holds if non-primary tmux sessions are reaped on app shutdown.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM52JT96V5067SM0DMR', 'bug', NULL, 'kill secondary Claude tmux sessions on tab close and on app shutdown', 'D-41 lifecycle contract: "closing a secondary kills that tmux session" and "secondary numbering (-1, -2, ...) resets between clide runs since ephemeral state is lost" — the second clause only holds if non-primary tmux sessions are reaped on app shutdown.
|
||||||
|
|
||||||
Neither happens today.
|
Neither happens today.
|
||||||
@@ -197,15 +197,15 @@ Neither happens today.
|
|||||||
- `_nextSecondary` index policy: keep the in-process counter for the running app; cold-start always begins at 1 because secondary sessions are gone.
|
- `_nextSecondary` index policy: keep the in-process counter for the running app; cold-start always begins at 1 because secondary sessions are gone.
|
||||||
- Add a test that exercises the close path and asserts the kill-session command was invoked (mock the tmux runner).
|
- Add a test that exercises the close path and asserts the kill-session command was invoked (mock the tmux runner).
|
||||||
|
|
||||||
**Out of scope:** primary lifecycle (unchanged — survives shutdown by design), general-purpose terminal panes (no tmux wrapping per D-41), Windows behaviour.', 'done', 'high', NULL, NULL, 'D-41', '2026-05-06 13:46:07', '2026-05-07 19:04:55', NULL, '897bb28855ae3b87703db5e7fb65dafc', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
**Out of scope:** primary lifecycle (unchanged — survives shutdown by design), general-purpose terminal panes (no tmux wrapping per D-41), Windows behaviour.', 'done', 'high', NULL, NULL, 'D-41', '2026-05-06 13:46:07', '2026-05-07 19:04:55', NULL, '897bb28855ae3b87703db5e7fb65dafc', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7AVABFH067XGTTCVM', 'task', NULL, 'PTY: fix resource leaks and reader-isolate races', NULL, 'done', 'high', NULL, NULL, NULL, '2026-05-05 12:58:59', '2026-05-07 19:04:55', NULL, '8c5f7ff42a9c056c3e742c2b6f53f476', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7AVABFH067XGTTCVM', 'task', NULL, 'PTY: fix resource leaks and reader-isolate races', NULL, 'done', 'high', NULL, NULL, NULL, '2026-05-05 12:58:59', '2026-05-07 19:04:55', NULL, '8c5f7ff42a9c056c3e742c2b6f53f476', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5JZ2AKN74FKMK3MR8', 'story', NULL, 'Claude pane: fullscreen mode + mouse-wheel scroll', NULL, 'done', 'medium', NULL, NULL, NULL, '2026-05-05 12:52:52', '2026-05-07 19:04:55', NULL, '92e8ece6ef3789c757cf58d960ba64c0', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5JZ2AKN74FKMK3MR8', 'story', NULL, 'Claude pane: fullscreen mode + mouse-wheel scroll', NULL, 'done', 'medium', NULL, NULL, NULL, '2026-05-05 12:52:52', '2026-05-07 19:04:55', NULL, '92e8ece6ef3789c757cf58d960ba64c0', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4KH7VR0BMZV5SSTXC', 'task', '06FB0TNQM7DV4ZS010XWZJ9A84', 'Contribute tickets & decisions tabs to sidebar', 'The decisions and tickets shipped extensions exist as stubs but don''t contribute TabContributions to Slots.sidebar yet. Spec lists them as the default left-panel section.', 'done', 'medium', NULL, NULL, 'D-47', '2026-04-22 21:03:40', '2026-05-07 19:04:55', NULL, '9496693b45b87c78298677bf6c85864e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4KH7VR0BMZV5SSTXC', 'task', '06FB0TNQM7DV4ZS010XWZJ9A84', 'Contribute tickets & decisions tabs to sidebar', 'The decisions and tickets shipped extensions exist as stubs but don''t contribute TabContributions to Slots.sidebar yet. Spec lists them as the default left-panel section.', 'done', 'medium', NULL, NULL, 'D-47', '2026-04-22 21:03:40', '2026-05-07 19:04:55', NULL, '9496693b45b87c78298677bf6c85864e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM606BMYDDGRSJBVPG8', 'bug', NULL, 'Bold text breaks terminal cell grid (workaround: suppress bold)', NULL, 'done', 'medium', NULL, NULL, NULL, '2026-05-05 12:52:56', '2026-05-07 19:04:55', NULL, '96d977e955a0642e2abcbfa920811658', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM606BMYDDGRSJBVPG8', 'bug', NULL, 'Bold text breaks terminal cell grid (workaround: suppress bold)', NULL, 'done', 'medium', NULL, NULL, NULL, '2026-05-05 12:52:56', '2026-05-07 19:04:55', NULL, '96d977e955a0642e2abcbfa920811658', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5JH7WV2RH5DGEA2AC', 'task', '06FB0TNQM6KX7HEQJ65HZ566DG', 'translate four design themes into YAML theme files', NULL, 'done', 'medium', NULL, NULL, 'D-44', '2026-04-22 14:08:40', '2026-05-07 19:04:55', NULL, '9716a4756a628296229d13d1afa96a49', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5JH7WV2RH5DGEA2AC', 'task', '06FB0TNQM6KX7HEQJ65HZ566DG', 'translate four design themes into YAML theme files', NULL, 'done', 'medium', NULL, NULL, 'D-44', '2026-04-22 14:08:40', '2026-05-07 19:04:55', NULL, '9716a4756a628296229d13d1afa96a49', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM79D19C0ZTXAVPKCCG', 'task', '06FB0TNQM6KX7HEQJ65HZ566DG', 'bundled dependency licensing', NULL, 'done', 'medium', NULL, NULL, 'D-42', '2026-04-22 11:47:03', '2026-05-07 19:04:55', NULL, '98a155f2841f4c6916840cec22a94dd0', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM79D19C0ZTXAVPKCCG', 'task', '06FB0TNQM6KX7HEQJ65HZ566DG', 'bundled dependency licensing', NULL, 'done', 'medium', NULL, NULL, 'D-42', '2026-04-22 11:47:03', '2026-05-07 19:04:55', NULL, '98a155f2841f4c6916840cec22a94dd0', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5Q6AWSTKGT0P64TRR', 'task', '06FB0TNQM7DV4ZS010XWZJ9A84', 'Contribute graph view tab to context panel', 'The graph shipped extension exists as a stub but doesn''t contribute a TabContribution to Slots.contextPanel. Spec lists pql graph as a right-panel section.', 'done', 'medium', NULL, NULL, 'D-47', '2026-04-22 21:03:40', '2026-05-07 19:04:55', NULL, '99c21c45c30875b7928ddd6638665357', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5Q6AWSTKGT0P64TRR', 'task', '06FB0TNQM7DV4ZS010XWZJ9A84', 'Contribute graph view tab to context panel', 'The graph shipped extension exists as a stub but doesn''t contribute a TabContribution to Slots.contextPanel. Spec lists pql graph as a right-panel section.', 'done', 'medium', NULL, NULL, 'D-47', '2026-04-22 21:03:40', '2026-05-07 19:04:55', NULL, '99c21c45c30875b7928ddd6638665357', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5WXV1RKPDK810C3FR', 'story', NULL, 'Implement focus mode (full-window takeover)', 'Focus mode via double-click header, hover ⛶ glyph, or ⌘. shortcut. Snapshot LayoutArrangement on enter, restore on Esc. Show Esc hint in header.', 'done', 'medium', NULL, NULL, 'D-52', '2026-04-22 20:33:56', '2026-05-07 19:04:55', NULL, '9bf21bda23ddae9eead766c10656f8e9', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5WXV1RKPDK810C3FR', 'story', NULL, 'Implement focus mode (full-window takeover)', 'Focus mode via double-click header, hover ⛶ glyph, or ⌘. shortcut. Snapshot LayoutArrangement on enter, restore on Esc. Show Esc hint in header.', 'done', 'medium', NULL, NULL, 'D-52', '2026-04-22 20:33:56', '2026-05-07 19:04:55', NULL, '9bf21bda23ddae9eead766c10656f8e9', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5AACHWPFWZDCJ3CPW', 'task', NULL, 'ship matching bold weight to restore semantic bold rendering', 'Workaround in T-70 / `lib/src/terminal/src/ui/painter.dart` suppresses bold rendering entirely because Flutter`s synthetic bold drifts glyph advance widths and breaks the monospace cell grid. We lose semantic bold (bash prompts, emphasis in TUIs) as a side effect.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5AACHWPFWZDCJ3CPW', 'task', NULL, 'ship matching bold weight to restore semantic bold rendering', 'Workaround in T-70 / `lib/src/terminal/src/ui/painter.dart` suppresses bold rendering entirely because Flutter`s synthetic bold drifts glyph advance widths and breaks the monospace cell grid. We lose semantic bold (bash prompts, emphasis in TUIs) as a side effect.
|
||||||
|
|
||||||
**Acceptance:**
|
**Acceptance:**
|
||||||
@@ -229,8 +229,8 @@ Investigation showed the perceived over-bolding in the Claude pane was synthetic
|
|||||||
3. `lib/src/terminal/src/ui/painter.dart:198`: revert the `bold: false` override and delete the now-stale comment block at lines 193-195.
|
3. `lib/src/terminal/src/ui/painter.dart:198`: revert the `bold: false` override and delete the now-stale comment block at lines 193-195.
|
||||||
4. Test: render a mixed-weight buffer and assert `paragraph.maxIntrinsicWidth` matches the all-regular measurement (cell drift = 0). If parity fails, the fallback options stay open (variable JetBrainsMono / Berkeley Mono / IBM Plex Mono).
|
4. Test: render a mixed-weight buffer and assert `paragraph.maxIntrinsicWidth` matches the all-regular measurement (cell drift = 0). If parity fails, the fallback options stay open (variable JetBrainsMono / Berkeley Mono / IBM Plex Mono).
|
||||||
|
|
||||||
Workaround comment (`Skip bold rendering — Flutter`s synthetic bold...`) goes away in step 3.', 'done', 'medium', NULL, NULL, NULL, '2026-05-05 12:53:21', '2026-05-07 19:04:55', NULL, '9e38408074619d9a46f3382a043d2f7b', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Workaround comment (`Skip bold rendering — Flutter`s synthetic bold...`) goes away in step 3.', 'done', 'medium', NULL, NULL, NULL, '2026-05-05 12:53:21', '2026-05-07 19:04:55', NULL, '9e38408074619d9a46f3382a043d2f7b', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6VMWWSP4BV8Q11W0M', 'task', '06FB0TNQM6KX7HEQJ65HZ566DG', 'expand SurfaceTokens with syntax highlighting roles', NULL, 'done', 'medium', NULL, NULL, 'D-45', '2026-04-22 14:08:40', '2026-05-07 19:04:55', NULL, 'a65f93e3f8bea36f544e9f8358655f7d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6VMWWSP4BV8Q11W0M', 'task', '06FB0TNQM6KX7HEQJ65HZ566DG', 'expand SurfaceTokens with syntax highlighting roles', NULL, 'done', 'medium', NULL, NULL, 'D-45', '2026-04-22 14:08:40', '2026-05-07 19:04:55', NULL, 'a65f93e3f8bea36f544e9f8358655f7d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM74S58G8XZV1766VD0', 'task', '06FB0TNQM6TNXTJCQBH9VADC4M', 'install ratcheting coverage gate at current floor', 'First child of T-89. Locks in the no-regression contract before any test-writing children land — so subsequent floor bumps are explicit and reviewable.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM74S58G8XZV1766VD0', 'task', '06FB0TNQM6TNXTJCQBH9VADC4M', 'install ratcheting coverage gate at current floor', 'First child of T-89. Locks in the no-regression contract before any test-writing children land — so subsequent floor bumps are explicit and reviewable.
|
||||||
|
|
||||||
**What lands:**
|
**What lands:**
|
||||||
@@ -257,30 +257,30 @@ INSERT INTO tickets (record_id, type, parent_record_id, title, description, stat
|
|||||||
- `lcov` CLI is not installed on this dev machine; parser must be self-contained (awk or python). Don''t introduce `lcov` as a dependency of the gate.
|
- `lcov` CLI is not installed on this dev machine; parser must be self-contained (awk or python). Don''t introduce `lcov` as a dependency of the gate.
|
||||||
- `coverage/lcov.info` is the standard Dart output path of `flutter test --coverage`. Don''t relocate.
|
- `coverage/lcov.info` is the standard Dart output path of `flutter test --coverage`. Don''t relocate.
|
||||||
- `flutter test --coverage` runs all tests including `forkpty`-tagged ones, which fail under the flutter test runner (see comment in `test/pty/session_test.dart`); `--exclude-tags forkpty` matches `ci/test.sh`. Forkpty-tagged tests don''t currently feed lcov because they run via `dart test`; check whether their coverage can be merged later (separate ticket if not).
|
- `flutter test --coverage` runs all tests including `forkpty`-tagged ones, which fail under the flutter test runner (see comment in `test/pty/session_test.dart`); `--exclude-tags forkpty` matches `ci/test.sh`. Forkpty-tagged tests don''t currently feed lcov because they run via `dart test`; check whether their coverage can be merged later (separate ticket if not).
|
||||||
', 'done', 'high', NULL, NULL, 'D-66', '2026-05-06 20:38:14', '2026-05-07 19:04:55', NULL, 'a907d54f65ad968399d04613d4a2f10f', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
', 'done', 'high', NULL, NULL, 'D-66', '2026-05-06 20:38:14', '2026-05-07 19:04:55', NULL, 'a907d54f65ad968399d04613d4a2f10f', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4QKBQY7FPCNX6N28R', 'task', '06FB0TNQM6M1VZ8Z2SZ94F0EQR', 'detect and install tmux on first launch', 'On first launch, check if tmux is on PATH. If missing, prompt the user with platform-appropriate install instructions (apt, dnf, brew) or offer to install automatically. Claude pane requires tmux per D-41; without it the primary session cannot persist.', 'backlog', 'medium', NULL, NULL, NULL, '2026-04-23 20:27:28', '2026-05-07 19:04:55', NULL, 'ac47da5ff5680a148aff82226ce6ca8c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4QKBQY7FPCNX6N28R', 'task', '06FB0TNQM6M1VZ8Z2SZ94F0EQR', 'detect and install tmux on first launch', 'On first launch, check if tmux is on PATH. If missing, prompt the user with platform-appropriate install instructions (apt, dnf, brew) or offer to install automatically. Claude pane requires tmux per D-41; without it the primary session cannot persist.', 'backlog', 'medium', NULL, NULL, NULL, '2026-04-23 20:27:28', '2026-05-07 19:04:55', NULL, 'ac47da5ff5680a148aff82226ce6ca8c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7MKCHC37G69SJGQ04', 'story', NULL, 'Persist layout state across sessions', 'Save collapse state, active sections, pql pane state, editor split ratio, and fuzzy find recent picks to .clide/settings.yaml via SettingsStore. Restore on boot.', 'done', 'medium', NULL, NULL, 'D-53', '2026-04-22 20:33:58', '2026-05-07 19:04:55', NULL, 'b2153c7d4cd67c9589a95f80b6b65bb0', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7MKCHC37G69SJGQ04', 'story', NULL, 'Persist layout state across sessions', 'Save collapse state, active sections, pql pane state, editor split ratio, and fuzzy find recent picks to .clide/settings.yaml via SettingsStore. Restore on boot.', 'done', 'medium', NULL, NULL, 'D-53', '2026-04-22 20:33:58', '2026-05-07 19:04:55', NULL, 'b2153c7d4cd67c9589a95f80b6b65bb0', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM57AEVK5E0GWVPGAY8', 'task', NULL, 'pane.spawn / editor.open: map errno to actionable error kinds', NULL, 'done', 'medium', NULL, NULL, NULL, '2026-05-05 12:58:59', '2026-05-07 19:04:55', NULL, 'b323a71a6f615032617486ebc06e724c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM57AEVK5E0GWVPGAY8', 'task', NULL, 'pane.spawn / editor.open: map errno to actionable error kinds', NULL, 'done', 'medium', NULL, NULL, NULL, '2026-05-05 12:58:59', '2026-05-07 19:04:55', NULL, 'b323a71a6f615032617486ebc06e724c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM42RQZVEWTF9CJSRF8', 'task', NULL, 'consolidate theme-ui into ui-design skill with theme/surface/geometry/icons references', NULL, 'done', 'medium', NULL, NULL, NULL, '2026-05-06 13:28:58', '2026-05-07 19:04:55', NULL, 'b5c089cb0bf30ec3fff9c969baa5e41d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM42RQZVEWTF9CJSRF8', 'task', NULL, 'consolidate theme-ui into ui-design skill with theme/surface/geometry/icons references', NULL, 'done', 'medium', NULL, NULL, NULL, '2026-05-06 13:28:58', '2026-05-07 19:04:55', NULL, 'b5c089cb0bf30ec3fff9c969baa5e41d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM67JSC5RKS6M9182KG', 'task', '06FB0TNQM7162Z26FDWXG35VH0', 'Add images tab to context panel', 'Spec lists images as a right-panel section. No extension exists yet.', 'backlog', 'low', NULL, NULL, 'D-47', '2026-04-22 21:03:40', '2026-05-07 19:04:55', NULL, 'bedeea36964687cded4ad249e7adba1d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM67JSC5RKS6M9182KG', 'task', '06FB0TNQM7162Z26FDWXG35VH0', 'Add images tab to context panel', 'Spec lists images as a right-panel section. No extension exists yet.', 'backlog', 'low', NULL, NULL, 'D-47', '2026-04-22 21:03:40', '2026-05-07 19:04:55', NULL, 'bedeea36964687cded4ad249e7adba1d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5YG22EV7BFTX5RTPR', 'task', '06FB0TNQM6T6580D8ABDVTMNZW', 'web-tree-sitter via JS interop for browser builds', 'Conditional import behind TreeSitterService: native impl uses dart:ffi to libtree-sitter.so, web impl uses dart:js_interop to web-tree-sitter (official emscripten build from tree-sitter org). Same grammar .wasm files on both platforms. Vendor web-tree-sitter .wasm + JS glue as Flutter web assets, pinned version, added to licenses.yaml.', 'backlog', 'medium', NULL, NULL, NULL, '2026-04-22 20:14:33', '2026-05-07 19:04:55', NULL, 'c787dd66b8ed15cc58e69683c0b67a2f', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5YG22EV7BFTX5RTPR', 'task', '06FB0TNQM6T6580D8ABDVTMNZW', 'web-tree-sitter via JS interop for browser builds', 'Conditional import behind TreeSitterService: native impl uses dart:ffi to libtree-sitter.so, web impl uses dart:js_interop to web-tree-sitter (official emscripten build from tree-sitter org). Same grammar .wasm files on both platforms. Vendor web-tree-sitter .wasm + JS glue as Flutter web assets, pinned version, added to licenses.yaml.', 'backlog', 'medium', NULL, NULL, NULL, '2026-04-22 20:14:33', '2026-05-07 19:04:55', NULL, 'c787dd66b8ed15cc58e69683c0b67a2f', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4PMYC2E1X99HX4MDM', 'task', NULL, 'MultitabPane: drag-to-reorder gesture wiring', NULL, 'done', 'medium', NULL, NULL, NULL, '2026-05-06 10:16:02', '2026-05-07 19:04:55', NULL, 'cd9defeed3125d8c7bc52f7c47cdeb81', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4PMYC2E1X99HX4MDM', 'task', NULL, 'MultitabPane: drag-to-reorder gesture wiring', NULL, 'done', 'medium', NULL, NULL, NULL, '2026-05-06 10:16:02', '2026-05-07 19:04:55', NULL, 'cd9defeed3125d8c7bc52f7c47cdeb81', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4VVHNKNXPYD4XWRYW', 'story', NULL, 'Implement 12px collapse spine for side panels', 'Replace current visibility toggle with a 12px spine widget: rotated label, paper-2 bg, inner-edge border, click-to-expand, badge dot with count for pending context.', 'done', 'high', NULL, NULL, 'D-51', '2026-04-22 20:33:53', '2026-05-07 19:04:55', NULL, 'd3952bbf29579fce6721345196d76e52', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4VVHNKNXPYD4XWRYW', 'story', NULL, 'Implement 12px collapse spine for side panels', 'Replace current visibility toggle with a 12px spine widget: rotated label, paper-2 bg, inner-edge border, click-to-expand, badge dot with count for pending context.', 'done', 'high', NULL, NULL, 'D-51', '2026-04-22 20:33:53', '2026-05-07 19:04:55', NULL, 'd3952bbf29579fce6721345196d76e52', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5A8DYZ3BCJN1DEY7C', 'task', NULL, 'PTY read buffer: 4KB → 64KB', NULL, 'done', 'medium', NULL, NULL, NULL, '2026-05-05 12:53:01', '2026-05-07 19:04:55', NULL, 'da519a6d00b8425ae1337a2df5089730', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5A8DYZ3BCJN1DEY7C', 'task', NULL, 'PTY read buffer: 4KB → 64KB', NULL, 'done', 'medium', NULL, NULL, NULL, '2026-05-05 12:53:01', '2026-05-07 19:04:55', NULL, 'da519a6d00b8425ae1337a2df5089730', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6YBQP75NQQ4Y9DN9C', 'task', NULL, 'inline terminal emulator (drop xterm.dart dependency)', NULL, 'done', 'medium', NULL, NULL, NULL, '2026-05-05 12:52:48', '2026-05-07 19:04:55', NULL, 'dcdcdbe3b1716c317a5f80ce9137a3f3', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6YBQP75NQQ4Y9DN9C', 'task', NULL, 'inline terminal emulator (drop xterm.dart dependency)', NULL, 'done', 'medium', NULL, NULL, NULL, '2026-05-05 12:52:48', '2026-05-07 19:04:55', NULL, 'dcdcdbe3b1716c317a5f80ce9137a3f3', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7CEP425DNV3W7RFPM', 'task', NULL, 'tmux: isolated -L clide socket so user''s tmux config doesn''t bleed into clide', NULL, 'done', 'medium', NULL, NULL, NULL, '2026-05-05 12:53:05', '2026-05-07 19:04:55', NULL, 'e0fdd5b963e1907050b3ce8b758d643c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7CEP425DNV3W7RFPM', 'task', NULL, 'tmux: isolated -L clide socket so user''s tmux config doesn''t bleed into clide', NULL, 'done', 'medium', NULL, NULL, NULL, '2026-05-05 12:53:05', '2026-05-07 19:04:55', NULL, 'e0fdd5b963e1907050b3ce8b758d643c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6GHHRANK5532VJVJR', 'story', NULL, 'Add icon rail to right panel (context section switcher)', 'Right panel currently has no bottom icon rail. Add one matching the left sidebar rail pattern: viewer, pql graph, links, images as section tabs.', 'done', 'medium', NULL, NULL, 'D-47', '2026-04-22 20:34:03', '2026-05-07 19:04:55', NULL, 'e52e07c18fcb5ce69807191301bd621b', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6GHHRANK5532VJVJR', 'story', NULL, 'Add icon rail to right panel (context section switcher)', 'Right panel currently has no bottom icon rail. Add one matching the left sidebar rail pattern: viewer, pql graph, links, images as section tabs.', 'done', 'medium', NULL, NULL, 'D-47', '2026-04-22 20:34:03', '2026-05-07 19:04:55', NULL, 'e52e07c18fcb5ce69807191301bd621b', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6M1VZ8Z2SZ94F0EQR', 'epic', NULL, 'Tier 1 — Claude in xterm pane, PTY, session persistence', NULL, 'done', 'medium', NULL, NULL, 'D-41', '2026-04-22 11:45:41', '2026-05-07 19:04:55', NULL, 'e5843d5c59e66f047f632e9fc723ea18', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6M1VZ8Z2SZ94F0EQR', 'epic', NULL, 'Tier 1 — Claude in xterm pane, PTY, session persistence', NULL, 'done', 'medium', NULL, NULL, 'D-41', '2026-04-22 11:45:41', '2026-05-07 19:04:55', NULL, 'e5843d5c59e66f047f632e9fc723ea18', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM48MDE8ZZ82VWNY994', 'task', '06FB0TNQM6T6580D8ABDVTMNZW', 'migrate shipped extensions from builtin/ to extensions/ per D-46', 'D-46 defines the boundary: content extensions (editor, claude, claude-control, markdown, diff, git-ui, pql, canvas, graph, decisions, tickets, todos, problems) move from app/lib/builtin/ to app/lib/extensions/. Incremental — one at a time, each behind a working build. Extension contract must support bundled Dart extension as a first-class category.', 'backlog', 'medium', NULL, NULL, NULL, '2026-04-22 20:14:45', '2026-05-07 19:04:55', NULL, 'e6c38225ea932b419ab114733c3ce219', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM48MDE8ZZ82VWNY994', 'task', '06FB0TNQM6T6580D8ABDVTMNZW', 'migrate shipped extensions from builtin/ to extensions/ per D-46', 'D-46 defines the boundary: content extensions (editor, claude, claude-control, markdown, diff, git-ui, pql, canvas, graph, decisions, tickets, todos, problems) move from app/lib/builtin/ to app/lib/extensions/. Incremental — one at a time, each behind a working build. Extension contract must support bundled Dart extension as a first-class category.', 'backlog', 'medium', NULL, NULL, NULL, '2026-04-22 20:14:45', '2026-05-07 19:04:55', NULL, 'e6c38225ea932b419ab114733c3ce219', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7QREFG3SBG2QPYY7R', 'task', NULL, 'progress indicators in status bar', 'Loading bar or spinner in the status bar for long-running operations: git pull/push, pql sync, extension install. Operations register with the kernel; status bar renders the active set.', 'backlog', 'medium', NULL, NULL, NULL, '2026-04-23 20:32:06', '2026-05-07 19:04:55', NULL, 'e9a76c10008aea830f77eb3a237e3ff0', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7QREFG3SBG2QPYY7R', 'task', NULL, 'progress indicators in status bar', 'Loading bar or spinner in the status bar for long-running operations: git pull/push, pql sync, extension install. Operations register with the kernel; status bar renders the active set.', 'backlog', 'medium', NULL, NULL, NULL, '2026-04-23 20:32:06', '2026-05-07 19:04:55', NULL, 'e9a76c10008aea830f77eb3a237e3ff0', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7D8AG5AY1CW58HCB4', 'task', NULL, 'activity badges on sidebar icons', 'Show unread count dots on sidebar icons: git changes count, new problems, pending notifications. Badges clear when the tab is viewed.', 'backlog', 'medium', NULL, NULL, NULL, '2026-04-23 20:32:06', '2026-05-07 19:04:55', NULL, 'eccccf10f621d9c78f870c08f714056c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7D8AG5AY1CW58HCB4', 'task', NULL, 'activity badges on sidebar icons', 'Show unread count dots on sidebar icons: git changes count, new problems, pending notifications. Badges clear when the tab is viewed.', 'backlog', 'medium', NULL, NULL, NULL, '2026-04-23 20:32:06', '2026-05-07 19:04:55', NULL, 'eccccf10f621d9c78f870c08f714056c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6TS48DVFDVJNZ5WGC', 'task', '06FB0TNQM7DV4ZS010XWZJ9A84', 'pql skill install + stopgap removal', NULL, 'done', 'medium', NULL, NULL, 'D-39', '2026-04-22 11:47:02', '2026-05-07 19:04:55', NULL, 'ef56815872eedd7254826d86cbd47b2b', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6TS48DVFDVJNZ5WGC', 'task', '06FB0TNQM7DV4ZS010XWZJ9A84', 'pql skill install + stopgap removal', NULL, 'done', 'medium', NULL, NULL, 'D-39', '2026-04-22 11:47:02', '2026-05-07 19:04:55', NULL, 'ef56815872eedd7254826d86cbd47b2b', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM59BAJSJ1JESDTPNER', 'task', '06FB0TNQM7DV4ZS010XWZJ9A84', 'backlinks panel — show inbound links to active file', NULL, 'done', 'medium', NULL, NULL, 'D-3', '2026-04-22 11:47:18', '2026-05-07 19:04:55', NULL, 'f00d9c2888181b29d120e2daa18692ab', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM59BAJSJ1JESDTPNER', 'task', '06FB0TNQM7DV4ZS010XWZJ9A84', 'backlinks panel — show inbound links to active file', NULL, 'done', 'medium', NULL, NULL, 'D-3', '2026-04-22 11:47:18', '2026-05-07 19:04:55', NULL, 'f00d9c2888181b29d120e2daa18692ab', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7YHYTWJGWPFJNHEAR', 'task', '06FB0TNQM6KX7HEQJ65HZ566DG', 'Python stopgap tooling', NULL, 'done', 'medium', NULL, NULL, 'D-40', '2026-04-22 11:47:02', '2026-05-07 19:04:55', NULL, 'f107f3a9dc0013a26faff6193b4723d8', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7YHYTWJGWPFJNHEAR', 'task', '06FB0TNQM6KX7HEQJ65HZ566DG', 'Python stopgap tooling', NULL, 'done', 'medium', NULL, NULL, 'D-40', '2026-04-22 11:47:02', '2026-05-07 19:04:55', NULL, 'f107f3a9dc0013a26faff6193b4723d8', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4R0WRHSJV1MVCW31M', 'task', '06FB0TNQM6KX7HEQJ65HZ566DG', 'Q&D record system + ADR migration', NULL, 'done', 'medium', NULL, NULL, 'D-34', '2026-04-22 11:47:02', '2026-05-07 19:04:55', NULL, 'f17f648be8c2860e5caa2f36862b6604', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4R0WRHSJV1MVCW31M', 'task', '06FB0TNQM6KX7HEQJ65HZ566DG', 'Q&D record system + ADR migration', NULL, 'done', 'medium', NULL, NULL, 'D-34', '2026-04-22 11:47:02', '2026-05-07 19:04:55', NULL, 'f17f648be8c2860e5caa2f36862b6604', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6KX7HEQJ65HZ566DG', 'epic', NULL, 'Tier 0 — app + daemon handshake, empty IDE shell', NULL, 'done', 'medium', NULL, NULL, 'D-7', '2026-04-22 11:45:26', '2026-05-07 19:04:55', NULL, 'f96d937e7cf667c19f1b66e09a91c948', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6KX7HEQJ65HZ566DG', 'epic', NULL, 'Tier 0 — app + daemon handshake, empty IDE shell', NULL, 'done', 'medium', NULL, NULL, 'D-7', '2026-04-22 11:45:26', '2026-05-07 19:04:55', NULL, 'f96d937e7cf667c19f1b66e09a91c948', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7TW8EJNJ2VP306A20', 'task', '06FB0TNQM7DV4ZS010XWZJ9A84', 'pql-backed file tree — replace or augment files.ls with pql files', NULL, 'done', 'medium', NULL, NULL, 'D-3', '2026-04-22 11:47:18', '2026-05-07 19:04:55', NULL, 'fe6790873528626dd2713569184e19f0', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7TW8EJNJ2VP306A20', 'task', '06FB0TNQM7DV4ZS010XWZJ9A84', 'pql-backed file tree — replace or augment files.ls with pql files', NULL, 'done', 'medium', NULL, NULL, 'D-3', '2026-04-22 11:47:18', '2026-05-07 19:04:55', NULL, 'fe6790873528626dd2713569184e19f0', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM48X0763Z9DZSM0HFR', 'task', NULL, 'wire pql plan merge as git custom merge driver', NULL, 'cancelled', 'medium', NULL, NULL, NULL, '2026-05-07 19:08:29', '2026-05-07 19:08:52', NULL, 'ea6c396c7136af7c7d3ef40c7a936692', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM48X0763Z9DZSM0HFR', 'task', NULL, 'wire pql plan merge as git custom merge driver', NULL, 'cancelled', 'medium', NULL, NULL, NULL, '2026-05-07 19:08:29', '2026-05-07 19:08:52', NULL, 'ea6c396c7136af7c7d3ef40c7a936692', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5WCDTR41VN9P1EGMC', 'bug', NULL, 'NativePty reader-isolate hangs ~5% of spawns', 'The reader isolate spawned by `NativePty._spawnReaderAsync` (`lib/src/pty/native_pty.dart`) hangs intermittently — about 5% of fresh spawns — with poll() on the master fd never returning POLLIN or POLLHUP, even when the child has clearly written and exited. Probed: 2 hangs out of 30 sequential `/bin/sh -c "printf hello-pty"` spawns over a 30s/spawn timeout.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5WCDTR41VN9P1EGMC', 'bug', NULL, 'NativePty reader-isolate hangs ~5% of spawns', 'The reader isolate spawned by `NativePty._spawnReaderAsync` (`lib/src/pty/native_pty.dart`) hangs intermittently — about 5% of fresh spawns — with poll() on the master fd never returning POLLIN or POLLHUP, even when the child has clearly written and exited. Probed: 2 hangs out of 30 sequential `/bin/sh -c "printf hello-pty"` spawns over a 30s/spawn timeout.
|
||||||
|
|
||||||
**Root cause — found 2026-05-17 via forensic probe:**
|
**Root cause — found 2026-05-17 via forensic probe:**
|
||||||
@@ -310,7 +310,7 @@ Why not always? Lock state at fork() time is timing-dependent. ~95% of the time
|
|||||||
- `lib/src/pty/native_pty.dart:170-191` (child-side post-fork code that deadlocks)
|
- `lib/src/pty/native_pty.dart:170-191` (child-side post-fork code that deadlocks)
|
||||||
- `lib/src/pty/native_pty.dart:235-262` (reader spawn — not the bug; downstream symptom)
|
- `lib/src/pty/native_pty.dart:235-262` (reader spawn — not the bug; downstream symptom)
|
||||||
- glibc posix_spawn docs: https://www.gnu.org/software/libc/manual/html_node/Process-Creation-Example.html
|
- glibc posix_spawn docs: https://www.gnu.org/software/libc/manual/html_node/Process-Creation-Example.html
|
||||||
', 'done', 'medium', NULL, NULL, NULL, '2026-05-17 17:16:01', '2026-05-17 18:11:18', NULL, '3600ef630f2bde152f85de29b981d394', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
', 'done', 'medium', NULL, NULL, NULL, '2026-05-17 17:16:01', '2026-05-17 18:11:18', NULL, '3600ef630f2bde152f85de29b981d394', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7F3V130BQXQH6HDVC', 'bug', '06FB0TNQM56CF9W94FSFDSBKGW', 'fix untrusted-workspace RCE in dugite git resolution', '`toolchain_paths.dart:79` builds `''$workspaceRoot/native/dugite/bin''` and runs `_firstExisting([''$dugite/git''])` — if that file exists in the open workspace it becomes the git binary for all GitClient calls, before falling back to PATH. A malicious repo commits an executable at `native/dugite/bin/git`; clide runs it on the first auto-fired `git.status`. Arbitrary code execution from merely opening a repo.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7F3V130BQXQH6HDVC', 'bug', '06FB0TNQM56CF9W94FSFDSBKGW', 'fix untrusted-workspace RCE in dugite git resolution', '`toolchain_paths.dart:79` builds `''$workspaceRoot/native/dugite/bin''` and runs `_firstExisting([''$dugite/git''])` — if that file exists in the open workspace it becomes the git binary for all GitClient calls, before falling back to PATH. A malicious repo commits an executable at `native/dugite/bin/git`; clide runs it on the first auto-fired `git.status`. Arbitrary code execution from merely opening a repo.
|
||||||
|
|
||||||
**Fix:** resolve `native/dugite` against `Platform.resolvedExecutable`''s directory (or a known install root), never `workspaceRoot`.
|
**Fix:** resolve `native/dugite` against `Platform.resolvedExecutable`''s directory (or a known install root), never `workspaceRoot`.
|
||||||
@@ -320,14 +320,14 @@ INSERT INTO tickets (record_id, type, parent_record_id, title, description, stat
|
|||||||
2. Test that a planted `native/dugite/bin/git` in the temp-dir workspace is ignored.
|
2. Test that a planted `native/dugite/bin/git` in the temp-dir workspace is ignored.
|
||||||
3. Existing dugite-in-install-dir behavior preserved.
|
3. Existing dugite-in-install-dir behavior preserved.
|
||||||
|
|
||||||
Source: consultants.md "Security — Findings — [Critical]".', 'done', 'critical', NULL, NULL, NULL, '2026-05-17 18:47:13', '2026-05-17 18:55:57', NULL, '29057f361b6c923d9202bf720decc360', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Source: consultants.md "Security — Findings — [Critical]".', 'done', 'critical', NULL, NULL, NULL, '2026-05-17 18:47:13', '2026-05-17 18:55:57', NULL, '29057f361b6c923d9202bf720decc360', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4QNZM15V1ZK32YS6G', 'bug', '06FB0TNQM56CF9W94FSFDSBKGW', 'add symlink re-resolution + containment re-check to files.read / files.ls', '`path_safety.dart:35-51` explicitly does not resolve symlinks; the filesystem layer (`files_commands.dart:81-85`) doesn''t either. A repo symlink `config -> /etc/shadow` passes the containment check (the link path is under root) and clide reads the target.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4QNZM15V1ZK32YS6G', 'bug', '06FB0TNQM56CF9W94FSFDSBKGW', 'add symlink re-resolution + containment re-check to files.read / files.ls', '`path_safety.dart:35-51` explicitly does not resolve symlinks; the filesystem layer (`files_commands.dart:81-85`) doesn''t either. A repo symlink `config -> /etc/shadow` passes the containment check (the link path is under root) and clide reads the target.
|
||||||
|
|
||||||
**Fix:** after `resolveUnderRoot`, call `resolveSymbolicLinksSync()` and re-verify containment against the workspace root.
|
**Fix:** after `resolveUnderRoot`, call `resolveSymbolicLinksSync()` and re-verify containment against the workspace root.
|
||||||
|
|
||||||
**Acceptance:** test that a symlink pointing outside the workspace is rejected by both `files.read` and `files.ls`.
|
**Acceptance:** test that a symlink pointing outside the workspace is rejected by both `files.read` and `files.ls`.
|
||||||
|
|
||||||
Source: consultants.md "Security — Findings — [Major] Path-safety does not defend against symlink escape".', 'done', 'high', NULL, NULL, NULL, '2026-05-17 18:47:33', '2026-05-17 19:01:39', NULL, '7ea8e511e8a3f5b7407a47170ccc5d12', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Source: consultants.md "Security — Findings — [Major] Path-safety does not defend against symlink escape".', 'done', 'high', NULL, NULL, NULL, '2026-05-17 18:47:33', '2026-05-17 19:01:39', NULL, '7ea8e511e8a3f5b7407a47170ccc5d12', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7NRKR9J1QTDSP9650', 'task', '06FB0TNQM56CF9W94FSFDSBKGW', 'rewrite README + docs/initial-plan to match current architecture', '`README.md` and `docs/initial-plan.md` describe an architecture that no longer exists. README documents `ptyc/` as a live component (`README.md:10`) and `make ptyc-build` (`:36`) — `ptyc/` is gone (D-5 amendment 2026-05-07) and the Makefile has no such target. `README.md:44` links to a `decisions/` directory that has moved to `governance/`. `docs/initial-plan.md` still describes a Go sidecar, separate `clide --daemon` long-running process, `app/` subdirectory, and `project.yaml` — all contradicted by D-5, D-56, and the single-package-at-root reality. A new contributor''s first read builds a wrong mental model.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7NRKR9J1QTDSP9650', 'task', '06FB0TNQM56CF9W94FSFDSBKGW', 'rewrite README + docs/initial-plan to match current architecture', '`README.md` and `docs/initial-plan.md` describe an architecture that no longer exists. README documents `ptyc/` as a live component (`README.md:10`) and `make ptyc-build` (`:36`) — `ptyc/` is gone (D-5 amendment 2026-05-07) and the Makefile has no such target. `README.md:44` links to a `decisions/` directory that has moved to `governance/`. `docs/initial-plan.md` still describes a Go sidecar, separate `clide --daemon` long-running process, `app/` subdirectory, and `project.yaml` — all contradicted by D-5, D-56, and the single-package-at-root reality. A new contributor''s first read builds a wrong mental model.
|
||||||
|
|
||||||
**Fix:**
|
**Fix:**
|
||||||
@@ -336,14 +336,14 @@ INSERT INTO tickets (record_id, type, parent_record_id, title, description, stat
|
|||||||
3. Either banner `docs/initial-plan.md` as historical (preserved as a snapshot) or extract a current `docs/architecture.md` that matches today''s code.
|
3. Either banner `docs/initial-plan.md` as historical (preserved as a snapshot) or extract a current `docs/architecture.md` that matches today''s code.
|
||||||
4. Spot-check other doc references to dissolved components.
|
4. Spot-check other doc references to dissolved components.
|
||||||
|
|
||||||
Source: consultants.md "Docs — Findings — [Critical]".', 'done', 'high', NULL, NULL, NULL, '2026-05-17 18:47:29', '2026-05-17 19:01:39', NULL, '8cc8901d96c79925cbc0114207ccda4e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Source: consultants.md "Docs — Findings — [Critical]".', 'done', 'high', NULL, NULL, NULL, '2026-05-17 18:47:29', '2026-05-17 19:01:39', NULL, '8cc8901d96c79925cbc0114207ccda4e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6MP9JD93ZE0CDGFFW', 'bug', '06FB0TNQM56CF9W94FSFDSBKGW', 'fix SchedulerService._startTicker isolate-spawn race', '`scheduler.dart:71`: `Isolate.spawn(_isolateEntry, _port!.sendPort).then((iso) => _isolate = iso)`. If `_stopTicker()` runs before the spawn future completes, `_isolate` is still null, nothing is killed, and the just-spawned isolate (with its `Timer.periodic`) leaks forever.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6MP9JD93ZE0CDGFFW', 'bug', '06FB0TNQM56CF9W94FSFDSBKGW', 'fix SchedulerService._startTicker isolate-spawn race', '`scheduler.dart:71`: `Isolate.spawn(_isolateEntry, _port!.sendPort).then((iso) => _isolate = iso)`. If `_stopTicker()` runs before the spawn future completes, `_isolate` is still null, nothing is killed, and the just-spawned isolate (with its `Timer.periodic`) leaks forever.
|
||||||
|
|
||||||
Same race shape we just fixed in `NativePty` via `_readerReady` (T-96).
|
Same race shape we just fixed in `NativePty` via `_readerReady` (T-96).
|
||||||
|
|
||||||
**Fix:** track the spawn future as `_isolateReady`; `_stopTicker` awaits it before killing.
|
**Fix:** track the spawn future as `_isolateReady`; `_stopTicker` awaits it before killing.
|
||||||
|
|
||||||
Source: consultants.md "Code quality — Findings — [Major]".', 'done', 'medium', NULL, NULL, NULL, '2026-05-17 18:47:51', '2026-05-17 19:18:43', NULL, '41a8876d254298e5384507bd7e1ba156', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Source: consultants.md "Code quality — Findings — [Major]".', 'done', 'medium', NULL, NULL, NULL, '2026-05-17 18:47:51', '2026-05-17 19:18:43', NULL, '41a8876d254298e5384507bd7e1ba156', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7WW3008NZRJWJ88HG', 'task', '06FB0TNQM56CF9W94FSFDSBKGW', 'quick-wins: governance + docs reconciliation', 'Batch of small consultant findings that share a domain (governance/docs):
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7WW3008NZRJWJ88HG', 'task', '06FB0TNQM56CF9W94FSFDSBKGW', 'quick-wins: governance + docs reconciliation', 'Batch of small consultant findings that share a domain (governance/docs):
|
||||||
|
|
||||||
1. **Amend D-66** to match current floor location/value: the floor lives in `pubspec.yaml` `coverage_floor:` (single source of truth as of this session), not `coverage/floor.txt`. Add a dated amendment line.
|
1. **Amend D-66** to match current floor location/value: the floor lives in `pubspec.yaml` `coverage_floor:` (single source of truth as of this session), not `coverage/floor.txt`. Add a dated amendment line.
|
||||||
@@ -352,12 +352,12 @@ INSERT INTO tickets (record_id, type, parent_record_id, title, description, stat
|
|||||||
4. **Drop `--no-fatal-infos` from `ci/test.sh`** now that the import queue is clear (post test-sweep this session).
|
4. **Drop `--no-fatal-infos` from `ci/test.sh`** now that the import queue is clear (post test-sweep this session).
|
||||||
5. Add a `.claude/skills/README.md` inventory.
|
5. Add a `.claude/skills/README.md` inventory.
|
||||||
|
|
||||||
Source: consultants.md (Docs + Tests + Security Findings — Minor).', 'done', 'low', NULL, NULL, NULL, '2026-05-17 18:48:24', '2026-05-17 19:18:43', NULL, 'aae158db5020241de743cf7541dc78c6', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Source: consultants.md (Docs + Tests + Security Findings — Minor).', 'done', 'low', NULL, NULL, NULL, '2026-05-17 18:48:24', '2026-05-17 19:18:43', NULL, 'aae158db5020241de743cf7541dc78c6', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM493QAZNJTJQHYFGCC', 'task', '06FB0TNQM56CF9W94FSFDSBKGW', 'add test-integration + smoke-bundle to make push-check', '`make push-check` runs `decisions-validate test-core test test-a11y coverage-gate changelog-gate`. `test-integration` and `smoke-bundle` are omitted — a boot-order regression sails through the pre-push gate.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM493QAZNJTJQHYFGCC', 'task', '06FB0TNQM56CF9W94FSFDSBKGW', 'add test-integration + smoke-bundle to make push-check', '`make push-check` runs `decisions-validate test-core test test-a11y coverage-gate changelog-gate`. `test-integration` and `smoke-bundle` are omitted — a boot-order regression sails through the pre-push gate.
|
||||||
|
|
||||||
**Acceptance:** `make push-check` runs the integration test layer + smoke-bundle. Wall-clock budget acceptable for pre-push (target <2 min total). If they''re too slow, gate them behind a separate `make push-check-full` and document.
|
**Acceptance:** `make push-check` runs the integration test layer + smoke-bundle. Wall-clock budget acceptable for pre-push (target <2 min total). If they''re too slow, gate them behind a separate `make push-check-full` and document.
|
||||||
|
|
||||||
Source: consultants.md "Tests — Findings — [Major] make push-check does not run integration tests".', 'done', 'high', NULL, NULL, NULL, '2026-05-17 18:47:39', '2026-05-17 19:18:43', NULL, 'be329e62f9d6cf0322b67038f08883e5', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Source: consultants.md "Tests — Findings — [Major] make push-check does not run integration tests".', 'done', 'high', NULL, NULL, NULL, '2026-05-17 18:47:39', '2026-05-17 19:18:43', NULL, 'be329e62f9d6cf0322b67038f08883e5', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6MWAKNB2NE3ZZ0XKW', 'story', '06FB0TNQM56CF9W94FSFDSBKGW', 'replace root KeyboardListener with scoped Shortcuts/Actions; move off keyLabel', '**Superseded by T-117 — Done.**
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6MWAKNB2NE3ZZ0XKW', 'story', '06FB0TNQM56CF9W94FSFDSBKGW', 'replace root KeyboardListener with scoped Shortcuts/Actions; move off keyLabel', '**Superseded by T-117 — Done.**
|
||||||
|
|
||||||
The consultant findings here — single root `KeyboardListener` will conflict with text-input fields; `KebindingResolver.fromKeyEvent` keys off layout-dependent `logicalKey.keyLabel` — are both addressed by the keystroke mapper layer (T-117):
|
The consultant findings here — single root `KeyboardListener` will conflict with text-input fields; `KebindingResolver.fromKeyEvent` keys off layout-dependent `logicalKey.keyLabel` — are both addressed by the keystroke mapper layer (T-117):
|
||||||
@@ -367,7 +367,7 @@ The consultant findings here — single root `KeyboardListener` will conflict wi
|
|||||||
|
|
||||||
Remaining cleanup (deletion of the now-vestigial `KeybindingResolver` class + the legacy `KeyboardListener` wrap once Flutter Shortcuts widget integration is on every feature) is small and lands as part of T-100 or its own follow-up.
|
Remaining cleanup (deletion of the now-vestigial `KeybindingResolver` class + the legacy `KeyboardListener` wrap once Flutter Shortcuts widget integration is on every feature) is small and lands as part of T-100 or its own follow-up.
|
||||||
|
|
||||||
Original text: Replace root KeyboardListener with scoped Shortcuts/Actions; move KebindingResolver off layout-dependent keyLabel.', 'done', 'medium', NULL, NULL, NULL, '2026-05-17 18:48:09', '2026-05-17 19:39:12', NULL, '0b55dbdf9c854b5cde5bde806187d512', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Original text: Replace root KeyboardListener with scoped Shortcuts/Actions; move KebindingResolver off layout-dependent keyLabel.', 'done', 'medium', NULL, NULL, NULL, '2026-05-17 18:48:09', '2026-05-17 19:39:12', NULL, '0b55dbdf9c854b5cde5bde806187d512', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM60QRRNEEWG84VWKXC', 'story', NULL, 'JetBrains keybinding preset', 'Ship a JetBrains/IntelliJ-compatible keybinding preset mapping standard JetBrains shortcuts to clide commands. Covers navigation, refactoring, search, run/debug, and tool windows.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM60QRRNEEWG84VWKXC', 'story', NULL, 'JetBrains keybinding preset', 'Ship a JetBrains/IntelliJ-compatible keybinding preset mapping standard JetBrains shortcuts to clide commands. Covers navigation, refactoring, search, run/debug, and tool windows.
|
||||||
|
|
||||||
**Unblocked by T-117 (2026-05-17):** the keystroke mapper layer is in place. Implementation is authoring `assets/keymaps/jetbrains.yaml` against the typed Intents + `command:<id>` bindings, plus when-clauses for the contexts JetBrains presets typically scope to (`editor.focused`, `inputFocused`, etc.).
|
**Unblocked by T-117 (2026-05-17):** the keystroke mapper layer is in place. Implementation is authoring `assets/keymaps/jetbrains.yaml` against the typed Intents + `command:<id>` bindings, plus when-clauses for the contexts JetBrains presets typically scope to (`editor.focused`, `inputFocused`, etc.).
|
||||||
@@ -375,7 +375,7 @@ INSERT INTO tickets (record_id, type, parent_record_id, title, description, stat
|
|||||||
**Acceptance:**
|
**Acceptance:**
|
||||||
1. `assets/keymaps/jetbrains.yaml` ships covering the documented IntelliJ default keybindings.
|
1. `assets/keymaps/jetbrains.yaml` ships covering the documented IntelliJ default keybindings.
|
||||||
2. `KeymapService.setPreset("jetbrains")` activates the preset and all asserted bindings resolve.
|
2. `KeymapService.setPreset("jetbrains")` activates the preset and all asserted bindings resolve.
|
||||||
3. A regression test exercises a representative subset (e.g. shift+shift → quick-open command — see Q-9 if the search-everywhere overlay needs its own intent).', 'backlog', 'medium', NULL, NULL, NULL, '2026-04-24 06:34:16', '2026-05-17 19:39:37', NULL, '35d89793092f79d3668bea287b346301', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
3. A regression test exercises a representative subset (e.g. shift+shift → quick-open command — see Q-9 if the search-everywhere overlay needs its own intent).', 'backlog', 'medium', NULL, NULL, NULL, '2026-04-24 06:34:16', '2026-05-17 19:39:37', NULL, '35d89793092f79d3668bea287b346301', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM42M9RK4399B4F4WSG', 'story', NULL, 'VS Code keybinding preset', 'Ship a VS Code-compatible keybinding preset that maps standard VS Code shortcuts to clide commands. Users select it in settings. Covers file navigation, editor actions, panel toggles, search, and terminal.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM42M9RK4399B4F4WSG', 'story', NULL, 'VS Code keybinding preset', 'Ship a VS Code-compatible keybinding preset that maps standard VS Code shortcuts to clide commands. Users select it in settings. Covers file navigation, editor actions, panel toggles, search, and terminal.
|
||||||
|
|
||||||
**Unblocked by T-117 (2026-05-17):** the keystroke mapper layer is now in place. Implementation is now just authoring `assets/keymaps/vscode.yaml` against the typed Intents in `lib/kernel/src/keymap/intents.dart` (plus `command:<id>` bindings for VS-Code-specific commands the preset wants to bind to clide commands). Users will switch presets via `app.keymap.preset = vscode` once a settings UI exists, or directly via the setting today.
|
**Unblocked by T-117 (2026-05-17):** the keystroke mapper layer is now in place. Implementation is now just authoring `assets/keymaps/vscode.yaml` against the typed Intents in `lib/kernel/src/keymap/intents.dart` (plus `command:<id>` bindings for VS-Code-specific commands the preset wants to bind to clide commands). Users will switch presets via `app.keymap.preset = vscode` once a settings UI exists, or directly via the setting today.
|
||||||
@@ -386,7 +386,7 @@ INSERT INTO tickets (record_id, type, parent_record_id, title, description, stat
|
|||||||
3. The preset uses when-clauses where VS Code does (`editor.focused`, `inputFocused`, `palette.open`, …).
|
3. The preset uses when-clauses where VS Code does (`editor.focused`, `inputFocused`, `palette.open`, …).
|
||||||
4. A regression test loads the preset and asserts a representative subset (e.g. ctrl+p → quick-open command, ctrl+shift+p → palette).
|
4. A regression test loads the preset and asserts a representative subset (e.g. ctrl+p → quick-open command, ctrl+shift+p → palette).
|
||||||
|
|
||||||
**Out of scope:** clide commands that have no VS Code analogue (those keep their default-preset bindings).', 'backlog', 'medium', NULL, NULL, NULL, '2026-04-24 06:34:16', '2026-05-17 19:39:37', NULL, 'de6e0f61b152438b5ec6f506020bd707', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
**Out of scope:** clide commands that have no VS Code analogue (those keep their default-preset bindings).', 'backlog', 'medium', NULL, NULL, NULL, '2026-04-24 06:34:16', '2026-05-17 19:39:37', NULL, 'de6e0f61b152438b5ec6f506020bd707', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM65SSVGN5M36T4QNDC', 'task', '06FB0TNQM56CF9W94FSFDSBKGW', 'keystroke mapper layer — intents + presets + when-clauses + overlay', 'Build the keymap mechanism that all keyboard-driven work plugs into. Lands before T-100 so widget wiring (ClideTappable, ClidePalette, focus traversal) goes through typed Intents, not raw key handlers. Closes T-110 (consultant: scoped Shortcuts/Actions; move off layout-dependent keyLabel). Unblocks T-64/T-65/T-66 (vim/vscode/jetbrains preset data).
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM65SSVGN5M36T4QNDC', 'task', '06FB0TNQM56CF9W94FSFDSBKGW', 'keystroke mapper layer — intents + presets + when-clauses + overlay', 'Build the keymap mechanism that all keyboard-driven work plugs into. Lands before T-100 so widget wiring (ClideTappable, ClidePalette, focus traversal) goes through typed Intents, not raw key handlers. Closes T-110 (consultant: scoped Shortcuts/Actions; move off layout-dependent keyLabel). Unblocks T-64/T-65/T-66 (vim/vscode/jetbrains preset data).
|
||||||
|
|
||||||
## Design (locked 2026-05-17)
|
## Design (locked 2026-05-17)
|
||||||
@@ -414,7 +414,7 @@ INSERT INTO tickets (record_id, type, parent_record_id, title, description, stat
|
|||||||
- A settings UI for editing bindings (file editing + preset switching is enough for v1).
|
- A settings UI for editing bindings (file editing + preset switching is enough for v1).
|
||||||
- ClideTappable/Palette widget integration (T-100 — comes immediately after this lands).
|
- ClideTappable/Palette widget integration (T-100 — comes immediately after this lands).
|
||||||
|
|
||||||
Source: 2026-05-17 design conversation; supersedes T-110.', 'done', 'high', NULL, NULL, NULL, '2026-05-17 19:28:28', '2026-05-17 19:39:40', NULL, 'a52184b3075848c2f955b46afa3e79d5', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Source: 2026-05-17 design conversation; supersedes T-110.', 'done', 'high', NULL, NULL, NULL, '2026-05-17 19:28:28', '2026-05-17 19:39:40', NULL, 'a52184b3075848c2f955b46afa3e79d5', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4CWANNSKNF2X5JEJ4', 'story', '06FB0TNQM56CF9W94FSFDSBKGW', 'make ClideTappable keyboard-operable; add palette arrow-keys + Escape', '`ClideTappable` (`lib/widgets/src/clide_tappable.dart`) is the base of nearly every interactive widget — `ClideButton`, `_WinBtn`, `_RecentProjectRow`, `_ActionRow`, most builtin list items — and it is `MouseRegion` + `GestureDetector` only. No `Focus`, no Enter/Space handler, no focus ring. None of these widgets can be reached by Tab or activated from the keyboard. The keyboard-traversal test passes only because it externally wraps in a `Focus` node — it tests non-blocking, not operability.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4CWANNSKNF2X5JEJ4', 'story', '06FB0TNQM56CF9W94FSFDSBKGW', 'make ClideTappable keyboard-operable; add palette arrow-keys + Escape', '`ClideTappable` (`lib/widgets/src/clide_tappable.dart`) is the base of nearly every interactive widget — `ClideButton`, `_WinBtn`, `_RecentProjectRow`, `_ActionRow`, most builtin list items — and it is `MouseRegion` + `GestureDetector` only. No `Focus`, no Enter/Space handler, no focus ring. None of these widgets can be reached by Tab or activated from the keyboard. The keyboard-traversal test passes only because it externally wraps in a `Focus` node — it tests non-blocking, not operability.
|
||||||
|
|
||||||
`ClidePalette` (`lib/widgets/src/clide_palette.dart`) is similarly broken: `onSubmitted` only ever invokes `filtered.first`; no up/down handling, no selected index, no selection highlight, no Escape handler.
|
`ClidePalette` (`lib/widgets/src/clide_palette.dart`) is similarly broken: `onSubmitted` only ever invokes `filtered.first`; no up/down handling, no selected index, no selection highlight, no Escape handler.
|
||||||
@@ -424,7 +424,7 @@ INSERT INTO tickets (record_id, type, parent_record_id, title, description, stat
|
|||||||
2. Add arrow-key navigation + selected-index + Escape + Enter-on-selected to `ClidePalette` (model after `_ProjectSwitcherDropdown.onKeyEvent` at `app.dart:446-452`).
|
2. Add arrow-key navigation + selected-index + Escape + Enter-on-selected to `ClidePalette` (model after `_ProjectSwitcherDropdown.onKeyEvent` at `app.dart:446-452`).
|
||||||
3. Extend the a11y test layer to assert operability (Tab + Enter actually invokes), not just Semantics presence.
|
3. Extend the a11y test layer to assert operability (Tab + Enter actually invokes), not just Semantics presence.
|
||||||
|
|
||||||
Source: consultants.md "UX — Findings — [Critical]".', 'done', 'high', NULL, NULL, NULL, '2026-05-17 18:47:23', '2026-05-17 19:47:50', NULL, 'e049271ae2749e4e1557d2e35c14caac', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Source: consultants.md "UX — Findings — [Critical]".', 'done', 'high', NULL, NULL, NULL, '2026-05-17 18:47:23', '2026-05-17 19:47:50', NULL, 'e049271ae2749e4e1557d2e35c14caac', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM63H3CXCKB13E3RNHW', 'story', '06FB0TNQM56CF9W94FSFDSBKGW', 'establish focus-traversal model; integrate FocusTracker with Flutter focus', 'No `FocusScope`/`FocusTraversalGroup` wiring across panels. `FocusTracker` (`lib/kernel/src/focus.dart`) tracks an active contribution id for the `clide active` CLI but doesn''t plug into Flutter''s focus system — it parallels it. Tab order across sidebar → workspace → context is undefined.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM63H3CXCKB13E3RNHW', 'story', '06FB0TNQM56CF9W94FSFDSBKGW', 'establish focus-traversal model; integrate FocusTracker with Flutter focus', 'No `FocusScope`/`FocusTraversalGroup` wiring across panels. `FocusTracker` (`lib/kernel/src/focus.dart`) tracks an active contribution id for the `clide active` CLI but doesn''t plug into Flutter''s focus system — it parallels it. Tab order across sidebar → workspace → context is undefined.
|
||||||
|
|
||||||
**Fix:**
|
**Fix:**
|
||||||
@@ -434,14 +434,14 @@ INSERT INTO tickets (record_id, type, parent_record_id, title, description, stat
|
|||||||
|
|
||||||
Depends on T-100 (ClideTappable accepting focus).
|
Depends on T-100 (ClideTappable accepting focus).
|
||||||
|
|
||||||
Source: consultants.md "UX — Findings — [Major] No focus-traversal wiring".', 'done', 'medium', NULL, NULL, NULL, '2026-05-17 18:47:47', '2026-05-17 19:56:28', NULL, 'b5088d1873da937dbe2bd266b361f3a5', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Source: consultants.md "UX — Findings — [Major] No focus-traversal wiring".', 'done', 'medium', NULL, NULL, NULL, '2026-05-17 18:47:47', '2026-05-17 19:56:28', NULL, 'b5088d1873da937dbe2bd266b361f3a5', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM40PV7G53JMHHNYPYG', 'task', '06FB0TNQM56CF9W94FSFDSBKGW', 'replace wall-clock sleeps in watcher_test / session_test with event-driven waits', '`test/files/watcher_test.dart:67-82` uses fixed `Future.delayed`. `test/pty/session_test.dart` polls 50×100ms and uses a bare `500ms` settle. `session_test.dart`''s `timeout(5s, onTimeout: () {})` swallows the timeout — a never-producing PTY proceeds to a confusing assertion failure rather than a clear timeout.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM40PV7G53JMHHNYPYG', 'task', '06FB0TNQM56CF9W94FSFDSBKGW', 'replace wall-clock sleeps in watcher_test / session_test with event-driven waits', '`test/files/watcher_test.dart:67-82` uses fixed `Future.delayed`. `test/pty/session_test.dart` polls 50×100ms and uses a bare `500ms` settle. `session_test.dart`''s `timeout(5s, onTimeout: () {})` swallows the timeout — a never-producing PTY proceeds to a confusing assertion failure rather than a clear timeout.
|
||||||
|
|
||||||
**Fix:**
|
**Fix:**
|
||||||
1. Replace fixed sleeps with `expectLater(stream, emits(...))` or equivalent event-driven waits.
|
1. Replace fixed sleeps with `expectLater(stream, emits(...))` or equivalent event-driven waits.
|
||||||
2. Replace swallowed `onTimeout: () {}` with `onTimeout: () => fail(''...'')`.
|
2. Replace swallowed `onTimeout: () {}` with `onTimeout: () => fail(''...'')`.
|
||||||
|
|
||||||
Source: consultants.md "Tests — Findings — [Major]".', 'done', 'medium', NULL, NULL, NULL, '2026-05-17 18:47:59', '2026-05-17 20:05:38', NULL, 'ed94e5ac754a620ee81220c59ff4386d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Source: consultants.md "Tests — Findings — [Major]".', 'done', 'medium', NULL, NULL, NULL, '2026-05-17 18:47:59', '2026-05-17 20:05:38', NULL, 'ed94e5ac754a620ee81220c59ff4386d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4ZNR15BSANVX07N1R', 'task', '06FB0TNQM56CF9W94FSFDSBKGW', 'quick-wins: code-quality cleanups', 'Batch of small consultant findings that share a domain (code quality):
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4ZNR15BSANVX07N1R', 'task', '06FB0TNQM56CF9W94FSFDSBKGW', 'quick-wins: code-quality cleanups', 'Batch of small consultant findings that share a domain (code quality):
|
||||||
|
|
||||||
1. Replace silent `catch (_)` in `tree_sitter_ffi.dart:197,206` with a logged last-error — `DynamicLibrary.open` failures are currently discarded.
|
1. Replace silent `catch (_)` in `tree_sitter_ffi.dart:197,206` with a logged last-error — `DynamicLibrary.open` failures are currently discarded.
|
||||||
@@ -452,7 +452,7 @@ INSERT INTO tickets (record_id, type, parent_record_id, title, description, stat
|
|||||||
6. Verify `file_tree_view.dart:8` barrel leak (commit `5cad982` may already cover this).
|
6. Verify `file_tree_view.dart:8` barrel leak (commit `5cad982` may already cover this).
|
||||||
7. Move `test_app.dart` out of production `main.dart` import graph (gate behind separate entrypoint or `kDebugMode`).
|
7. Move `test_app.dart` out of production `main.dart` import graph (gate behind separate entrypoint or `kDebugMode`).
|
||||||
|
|
||||||
Source: consultants.md (Code Quality + Architecture Findings — Minor).', 'done', 'low', NULL, NULL, NULL, '2026-05-17 18:48:20', '2026-05-17 20:11:16', NULL, '7f7b369ec7d257859d122dd9bdc31ef7', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Source: consultants.md (Code Quality + Architecture Findings — Minor).', 'done', 'low', NULL, NULL, NULL, '2026-05-17 18:48:20', '2026-05-17 20:11:16', NULL, '7f7b369ec7d257859d122dd9bdc31ef7', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4W20PVMHX1BBJ4TVW', 'task', '06FB0TNQM56CF9W94FSFDSBKGW', 'add high-contrast + colour-blind theme variants', 'Per D-69, the four named themes (clide, midnight, paper, terminal) keep
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4W20PVMHX1BBJ4TVW', 'task', '06FB0TNQM56CF9W94FSFDSBKGW', 'add high-contrast + colour-blind theme variants', 'Per D-69, the four named themes (clide, midnight, paper, terminal) keep
|
||||||
their published palettes and only pass the baseline canonicalPairs
|
their published palettes and only pass the baseline canonicalPairs
|
||||||
gate. The stricter extendedPairs set in
|
gate. The stricter extendedPairs set in
|
||||||
@@ -474,7 +474,7 @@ Scope:
|
|||||||
4. The contrast gate at test/a11y/contrast_test.dart already covers
|
4. The contrast gate at test/a11y/contrast_test.dart already covers
|
||||||
them — adding the files is enough.
|
them — adding the files is enough.
|
||||||
|
|
||||||
Sources: D-22, D-69, consultants.md ("UX — Findings — [Minor]").', 'done', 'low', NULL, NULL, 'D-69', '2026-05-17 20:51:47', '2026-05-17 20:53:41', NULL, '61ba5bea84a89e1f72d013460b81ab45', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Sources: D-22, D-69, consultants.md ("UX — Findings — [Minor]").', 'done', 'low', NULL, NULL, 'D-69', '2026-05-17 20:51:47', '2026-05-17 20:53:41', NULL, '61ba5bea84a89e1f72d013460b81ab45', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7FG92QKNFJSCAP888', 'task', '06FB0TNQM56CF9W94FSFDSBKGW', 'quick-wins: a11y + contrast gate expansion', 'Batch of small consultant findings that share a domain (a11y / visual):
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7FG92QKNFJSCAP888', 'task', '06FB0TNQM56CF9W94FSFDSBKGW', 'quick-wins: a11y + contrast gate expansion', 'Batch of small consultant findings that share a domain (a11y / visual):
|
||||||
|
|
||||||
1. Expand contrast gate `canonicalPairs` (`test/a11y/contrast_test.dart`) to cover `globalTextMuted` (muted text is everywhere), the `status*` foregrounds, syntax tokens on `panelBackground`, and `panelActiveBorder`.
|
1. Expand contrast gate `canonicalPairs` (`test/a11y/contrast_test.dart`) to cover `globalTextMuted` (muted text is everywhere), the `status*` foregrounds, syntax tokens on `panelBackground`, and `panelActiveBorder`.
|
||||||
@@ -482,7 +482,7 @@ INSERT INTO tickets (record_id, type, parent_record_id, title, description, stat
|
|||||||
3. Add a focus-ring rendering at the token level so every focusable widget gets it for free (depends on T-100).
|
3. Add a focus-ring rendering at the token level so every focusable widget gets it for free (depends on T-100).
|
||||||
4. Surface text-zoom (Ctrl +/-/0) in the palette so it''s discoverable.
|
4. Surface text-zoom (Ctrl +/-/0) in the palette so it''s discoverable.
|
||||||
|
|
||||||
Source: consultants.md "UX — Findings — [Minor]" + Strengths section.', 'done', 'low', NULL, NULL, NULL, '2026-05-17 18:48:28', '2026-05-18 07:04:38', NULL, 'ab216d9c583bac8285588827a271115d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Source: consultants.md "UX — Findings — [Minor]" + Strengths section.', 'done', 'low', NULL, NULL, NULL, '2026-05-17 18:48:28', '2026-05-18 07:04:38', NULL, 'ab216d9c583bac8285588827a271115d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7Y9KHNVRZ41VYW1YM', 'story', '06FB0TNQM56CF9W94FSFDSBKGW', 'drag-resize keyboard parity + clide panel resize CLI', '`drag_resize.dart` and `app.dart:870-912` are pure `Listener` pointer handlers — no keyboard equivalent, no Semantics node. Per the user/Claude parity rule (D-6), panel sizing should have a CLI affordance. Neither exists.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7Y9KHNVRZ41VYW1YM', 'story', '06FB0TNQM56CF9W94FSFDSBKGW', 'drag-resize keyboard parity + clide panel resize CLI', '`drag_resize.dart` and `app.dart:870-912` are pure `Listener` pointer handlers — no keyboard equivalent, no Semantics node. Per the user/Claude parity rule (D-6), panel sizing should have a CLI affordance. Neither exists.
|
||||||
|
|
||||||
**Fix:**
|
**Fix:**
|
||||||
@@ -491,7 +491,7 @@ INSERT INTO tickets (record_id, type, parent_record_id, title, description, stat
|
|||||||
|
|
||||||
Coordinate with T-99 (IPC implementation) if the CLI verb needs new dispatch wiring.
|
Coordinate with T-99 (IPC implementation) if the CLI verb needs new dispatch wiring.
|
||||||
|
|
||||||
Source: consultants.md "UX — Findings — [Major] Drag-resize handles".', 'done', 'medium', NULL, NULL, NULL, '2026-05-17 18:48:14', '2026-05-18 07:43:45', NULL, '711d757f542600cc20738194f5fe47d2', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Source: consultants.md "UX — Findings — [Major] Drag-resize handles".', 'done', 'medium', NULL, NULL, NULL, '2026-05-17 18:48:14', '2026-05-18 07:43:45', NULL, '711d757f542600cc20738194f5fe47d2', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5W67PPRVA8SAJXHFG', 'task', '06FB0TNQM56CF9W94FSFDSBKGW', 'schema-validate IPC argument surface; reject -prefixed values', '`DaemonDispatcher.dispatch` (`dispatcher.dart:26`) and `IpcRequest.fromJson` (`envelope.dart:49`) do no schema validation. No size limit on `files.read`, no count cap on `git.log`. `git diff`/`stage` use `--` separators (good), but `checkout(branch)` and `push(remote, branch)` (`git_commands.dart:240`) do not — argument injection (e.g. `git checkout --upload-pack=...`) is possible.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5W67PPRVA8SAJXHFG', 'task', '06FB0TNQM56CF9W94FSFDSBKGW', 'schema-validate IPC argument surface; reject -prefixed values', '`DaemonDispatcher.dispatch` (`dispatcher.dart:26`) and `IpcRequest.fromJson` (`envelope.dart:49`) do no schema validation. No size limit on `files.read`, no count cap on `git.log`. `git diff`/`stage` use `--` separators (good), but `checkout(branch)` and `push(remote, branch)` (`git_commands.dart:240`) do not — argument injection (e.g. `git checkout --upload-pack=...`) is possible.
|
||||||
|
|
||||||
**Fix:**
|
**Fix:**
|
||||||
@@ -501,7 +501,7 @@ INSERT INTO tickets (record_id, type, parent_record_id, title, description, stat
|
|||||||
|
|
||||||
**Acceptance:** unit tests cover the rejection path for each injection vector listed.
|
**Acceptance:** unit tests cover the rejection path for each injection vector listed.
|
||||||
|
|
||||||
Source: consultants.md "Security — Findings — [Major]".', 'done', 'high', NULL, NULL, NULL, '2026-05-17 18:47:42', '2026-05-18 07:53:10', NULL, '6d17568c12cbcab8832650e45b190213', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Source: consultants.md "Security — Findings — [Major]".', 'done', 'high', NULL, NULL, NULL, '2026-05-17 18:47:42', '2026-05-18 07:53:10', NULL, '6d17568c12cbcab8832650e45b190213', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4TTAC53CQYWDQ91H0', 'task', '06FB0TNQM56CF9W94FSFDSBKGW', 'write CONTRIBUTING.md; cut interim release to drain Unreleased; merge duplicate changelog headings', 'Three docs items:
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4TTAC53CQYWDQ91H0', 'task', '06FB0TNQM56CF9W94FSFDSBKGW', 'write CONTRIBUTING.md; cut interim release to drain Unreleased; merge duplicate changelog headings', 'Three docs items:
|
||||||
|
|
||||||
1. **No `CONTRIBUTING.md`.** Build/test story is scattered across `CLAUDE.md` (Claude-addressed), `README.md` (partly wrong — see T-101), and Makefile help. Write a human-addressed contributor guide: clone → `make hooks && flutter pub get` → `make test` → DQR workflow → commit conventions.
|
1. **No `CONTRIBUTING.md`.** Build/test story is scattered across `CLAUDE.md` (Claude-addressed), `README.md` (partly wrong — see T-101), and Makefile help. Write a human-addressed contributor guide: clone → `make hooks && flutter pub get` → `make test` → DQR workflow → commit conventions.
|
||||||
@@ -510,7 +510,7 @@ INSERT INTO tickets (record_id, type, parent_record_id, title, description, stat
|
|||||||
|
|
||||||
Order matters: 2 → 3 → 1 (clean changelog, release, then doc the workflow).
|
Order matters: 2 → 3 → 1 (clean changelog, release, then doc the workflow).
|
||||||
|
|
||||||
Source: consultants.md "Docs — Findings".', 'done', 'medium', NULL, NULL, NULL, '2026-05-17 18:48:03', '2026-05-18 08:07:23', NULL, 'e7e81d29221956cdaa80068e8a406ee6', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Source: consultants.md "Docs — Findings".', 'done', 'medium', NULL, NULL, NULL, '2026-05-17 18:48:03', '2026-05-18 08:07:23', NULL, 'e7e81d29221956cdaa80068e8a406ee6', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM45DS16DX0NKMN9Q3G', 'task', '06FB0TNQM56CF9W94FSFDSBKGW', 'cut interim release to drain Unreleased (split from T-109)', 'Item 3 of T-109. With CONTRIBUTING.md landed and [Unreleased] consolidated, the remaining piece is cutting an actual release so the ~80-commit Unreleased backlog drains into a dated heading.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM45DS16DX0NKMN9Q3G', 'task', '06FB0TNQM56CF9W94FSFDSBKGW', 'cut interim release to drain Unreleased (split from T-109)', 'Item 3 of T-109. With CONTRIBUTING.md landed and [Unreleased] consolidated, the remaining piece is cutting an actual release so the ~80-commit Unreleased backlog drains into a dated heading.
|
||||||
|
|
||||||
Per .claude/skills/git-commit/SKILL.md "Cutting a release":
|
Per .claude/skills/git-commit/SKILL.md "Cutting a release":
|
||||||
@@ -521,7 +521,7 @@ Per .claude/skills/git-commit/SKILL.md "Cutting a release":
|
|||||||
|
|
||||||
Version pick is the user''s call — likely 2.1.0 given the scope since 2.0.0 (D-66 95% coverage gate, T-117 keymap, contrast-gate split, IPC hardening, panel-keyboard parity, etc.).
|
Version pick is the user''s call — likely 2.1.0 given the scope since 2.0.0 (D-66 95% coverage gate, T-117 keymap, contrast-gate split, IPC hardening, panel-keyboard parity, etc.).
|
||||||
|
|
||||||
Source: consultants.md "Docs — Findings" item 3.', 'done', 'medium', NULL, NULL, NULL, '2026-05-18 08:07:23', '2026-05-18 08:22:19', NULL, '740bb2fcfc0a793f18cb8d6e93e85cae', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Source: consultants.md "Docs — Findings" item 3.', 'done', 'medium', NULL, NULL, NULL, '2026-05-18 08:07:23', '2026-05-18 08:22:19', NULL, '740bb2fcfc0a793f18cb8d6e93e85cae', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM614M7ES54V3SETAQM', 'story', NULL, 'startup project picker; "always open this project" override', 'Startup flow change: on launch, always show the project picker screen unless the user has explicitly checked an "always open this project" box for a specific project (sticky default).
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM614M7ES54V3SETAQM', 'story', NULL, 'startup project picker; "always open this project" override', 'Startup flow change: on launch, always show the project picker screen unless the user has explicitly checked an "always open this project" box for a specific project (sticky default).
|
||||||
|
|
||||||
**Acceptance:**
|
**Acceptance:**
|
||||||
@@ -535,7 +535,7 @@ INSERT INTO tickets (record_id, type, parent_record_id, title, description, stat
|
|||||||
|
|
||||||
**Out of scope:** multi-project workspaces, project groups, recent-project ordering changes.
|
**Out of scope:** multi-project workspaces, project groups, recent-project ordering changes.
|
||||||
|
|
||||||
**Source:** user request 2026-05-17.', 'done', 'medium', NULL, NULL, NULL, '2026-05-17 19:10:21', '2026-05-18 09:30:59', NULL, 'e5895d60605001ae4d69dffdc089b2ff', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
**Source:** user request 2026-05-17.', 'done', 'medium', NULL, NULL, NULL, '2026-05-17 19:10:21', '2026-05-18 09:30:59', NULL, 'e5895d60605001ae4d69dffdc089b2ff', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4RJ9K19P5AX14RHRR', 'task', '06FB0TNQM4HGK6KR0314P2M32M', 'split lib/src/terminal/.../escape/parser.dart (1139 LOC)', 'parser.dart is a single 1139-line file containing the full ESC/CSI/OSC/DCS handler tree for the terminal emulator. Functional but unwieldy; the consultant flagged it as ''consider splitting'' in the T-107 review.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4RJ9K19P5AX14RHRR', 'task', '06FB0TNQM4HGK6KR0314P2M32M', 'split lib/src/terminal/.../escape/parser.dart (1139 LOC)', 'parser.dart is a single 1139-line file containing the full ESC/CSI/OSC/DCS handler tree for the terminal emulator. Functional but unwieldy; the consultant flagged it as ''consider splitting'' in the T-107 review.
|
||||||
|
|
||||||
Suggested split (sequenced with the T-91 coverage sweep on lib/src/terminal/, so the split doesn''t fight in-flight test work):
|
Suggested split (sequenced with the T-91 coverage sweep on lib/src/terminal/, so the split doesn''t fight in-flight test work):
|
||||||
@@ -553,14 +553,14 @@ Done when:
|
|||||||
- All existing parser tests pass without changes
|
- All existing parser tests pass without changes
|
||||||
- No new public surface; everything stays library-private
|
- No new public surface; everything stays library-private
|
||||||
|
|
||||||
Source: T-107 / consultants.md "Code quality — Findings — [Major]".', 'backlog', 'low', NULL, NULL, NULL, '2026-05-18 10:29:02', '2026-05-18 10:29:02', NULL, 'd812c0c9d1401967041981dff920fed8', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Source: T-107 / consultants.md "Code quality — Findings — [Major]".', 'backlog', 'low', NULL, NULL, NULL, '2026-05-18 10:29:02', '2026-05-18 10:29:02', NULL, 'd812c0c9d1401967041981dff920fed8', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7FXS713CKYDZ284NC', 'task', '06FB0TNQM56CF9W94FSFDSBKGW', 'decide lib/src/terminal/ status: formally vendor or clean to project bar', '~7k LOC forked from xterm.dart in an undeclared middle state. Carries commented-out `print()` debugging (`custom_text_edit.dart:244-275`), dangling TODOs (`parser.dart:110-113`, `keytab.dart:91`), a 1137-line `parser.dart`, and the only `// ignore: invalid_use_of_protected_member` in the repo (`terminal_view.dart:363`). Memory says "code under `lib/` is owned, not vendored."
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7FXS713CKYDZ284NC', 'task', '06FB0TNQM56CF9W94FSFDSBKGW', 'decide lib/src/terminal/ status: formally vendor or clean to project bar', '~7k LOC forked from xterm.dart in an undeclared middle state. Carries commented-out `print()` debugging (`custom_text_edit.dart:244-275`), dangling TODOs (`parser.dart:110-113`, `keytab.dart:91`), a 1137-line `parser.dart`, and the only `// ignore: invalid_use_of_protected_member` in the repo (`terminal_view.dart:363`). Memory says "code under `lib/` is owned, not vendored."
|
||||||
|
|
||||||
**Decide one path and execute:**
|
**Decide one path and execute:**
|
||||||
- **(a)** Formally vendor: relocate to `native/` or document as frozen in a D-record + `licenses.yaml`. Coverage carve-out documented.
|
- **(a)** Formally vendor: relocate to `native/` or document as frozen in a D-record + `licenses.yaml`. Coverage carve-out documented.
|
||||||
- **(b)** Clean to the project bar: remove debug prints, resolve TODOs, justify or remove the protected-member suppression, consider splitting `parser.dart`.
|
- **(b)** Clean to the project bar: remove debug prints, resolve TODOs, justify or remove the protected-member suppression, consider splitting `parser.dart`.
|
||||||
|
|
||||||
Source: consultants.md "Code quality — Findings — [Major]".', 'done', 'medium', NULL, NULL, NULL, '2026-05-17 18:47:55', '2026-05-18 10:30:30', NULL, '49a34b2f3d09c36a62fac63a4a70444b', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Source: consultants.md "Code quality — Findings — [Major]".', 'done', 'medium', NULL, NULL, NULL, '2026-05-17 18:47:55', '2026-05-18 10:30:30', NULL, '49a34b2f3d09c36a62fac63a4a70444b', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4H5C2Z6GCBCQ85QGR', 'bug', '06FB0TNQM56CF9W94FSFDSBKGW', 'integration_test/theme_picker_test.dart hangs pumpAndSettle on theme.pick', 'When running `flutter test integration_test/theme_picker_test.dart` against the real boot path, calling `services.commands.execute(''theme.pick'')` followed by `await tester.pumpAndSettle()` does not settle — the test hangs for 60+ seconds and never reaches the `Select theme` / `Cancel` assertions. Likely an animation loop or a never-completing Future in the modal mount path.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4H5C2Z6GCBCQ85QGR', 'bug', '06FB0TNQM56CF9W94FSFDSBKGW', 'integration_test/theme_picker_test.dart hangs pumpAndSettle on theme.pick', 'When running `flutter test integration_test/theme_picker_test.dart` against the real boot path, calling `services.commands.execute(''theme.pick'')` followed by `await tester.pumpAndSettle()` does not settle — the test hangs for 60+ seconds and never reaches the `Select theme` / `Cancel` assertions. Likely an animation loop or a never-completing Future in the modal mount path.
|
||||||
|
|
||||||
Blocks T-103 from adding integration tests to `make push-check` (the other two integration tests pass after viewport + assertion fixes).
|
Blocks T-103 from adding integration tests to `make push-check` (the other two integration tests pass after viewport + assertion fixes).
|
||||||
@@ -570,7 +570,7 @@ Blocks T-103 from adding integration tests to `make push-check` (the other two i
|
|||||||
2. Both assertions (`Select theme` visible after `theme.pick`; gone after `Cancel`) pass.
|
2. Both assertions (`Select theme` visible after `theme.pick`; gone after `Cancel`) pass.
|
||||||
3. T-103''s `push-check-full` can include integration tests without the theme-picker hanging.
|
3. T-103''s `push-check-full` can include integration tests without the theme-picker hanging.
|
||||||
|
|
||||||
Source: surfaced 2026-05-17 during T-103 work.', 'done', 'medium', NULL, NULL, NULL, '2026-05-17 19:14:31', '2026-05-18 11:22:46', NULL, '1f5a84168d1d82828c77cbe3f269a0aa', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Source: surfaced 2026-05-17 during T-103 work.', 'done', 'medium', NULL, NULL, NULL, '2026-05-17 19:14:31', '2026-05-18 11:22:46', NULL, '1f5a84168d1d82828c77cbe3f269a0aa', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM53N56Z60B4SQ5VTRG', 'task', NULL, 'forward real mouse events to TUI apps (not just PgUp/PgDown)', 'Mouse wheel scroll is currently translated to PgUp/PgDown key input in `lib/src/terminal/src/terminal_view.dart` as a pragmatic workaround — TUIs that capture mouse events without binding the wheel get a no-op otherwise. The downside: any TUI that does its own wheel handling (selection, click-to-position) loses the actual mouse coordinates because all we send is keyboard.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM53N56Z60B4SQ5VTRG', 'task', NULL, 'forward real mouse events to TUI apps (not just PgUp/PgDown)', 'Mouse wheel scroll is currently translated to PgUp/PgDown key input in `lib/src/terminal/src/terminal_view.dart` as a pragmatic workaround — TUIs that capture mouse events without binding the wheel get a no-op otherwise. The downside: any TUI that does its own wheel handling (selection, click-to-position) loses the actual mouse coordinates because all we send is keyboard.
|
||||||
|
|
||||||
**Acceptance:**
|
**Acceptance:**
|
||||||
@@ -579,7 +579,7 @@ INSERT INTO tickets (record_id, type, parent_record_id, title, description, stat
|
|||||||
- Falls back to PgUp/PgDown only when the inner program has not declared a mouse mode.
|
- Falls back to PgUp/PgDown only when the inner program has not declared a mouse mode.
|
||||||
- The `mouseInput` API on `Terminal` is wired through `Listener.onPointerSignal` instead of being bypassed.
|
- The `mouseInput` API on `Terminal` is wired through `Listener.onPointerSignal` instead of being bypassed.
|
||||||
|
|
||||||
**Why this isn`t the default already:** the bypass was the cheapest fix to get scroll working at all when the multitab/Scrollable ate scroll events. With those fixes landed, the right-shaped mouse forwarding is the proper next step.', 'done', 'medium', NULL, NULL, NULL, '2026-05-05 12:53:22', '2026-05-18 11:51:40', NULL, 'fea6f554862caab5d1f0dbb40a703bc8', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
**Why this isn`t the default already:** the bypass was the cheapest fix to get scroll working at all when the multitab/Scrollable ate scroll events. With those fixes landed, the right-shaped mouse forwarding is the proper next step.', 'done', 'medium', NULL, NULL, NULL, '2026-05-05 12:53:22', '2026-05-18 11:51:40', NULL, 'fea6f554862caab5d1f0dbb40a703bc8', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4AV8YXV4NYWS2ZQYW', 'task', '06FB0TNQM76Q97D8R01CRTTA9R', 'unix-domain IPC server, wired into Flutter app boot', 'First slice of T-99(a). Foundation for the rest.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4AV8YXV4NYWS2ZQYW', 'task', '06FB0TNQM76Q97D8R01CRTTA9R', 'unix-domain IPC server, wired into Flutter app boot', 'First slice of T-99(a). Foundation for the rest.
|
||||||
|
|
||||||
Open a per-workspace unix-domain socket on Flutter app boot. Accept JSON-lines per the existing IpcRequest envelope. Route each request through the existing DaemonDispatcher (already wired in main.dart via daemonClientFactory). Tear down on app shutdown.
|
Open a per-workspace unix-domain socket on Flutter app boot. Accept JSON-lines per the existing IpcRequest envelope. Route each request through the existing DaemonDispatcher (already wired in main.dart via daemonClientFactory). Tear down on app shutdown.
|
||||||
@@ -597,7 +597,7 @@ Open a per-workspace unix-domain socket on Flutter app boot. Accept JSON-lines p
|
|||||||
5. Stale socket on boot (left over from a crashed clide) is detected and unlinked before binding — same `live-daemon probe` pattern already used elsewhere in the codebase.
|
5. Stale socket on boot (left over from a crashed clide) is detected and unlinked before binding — same `live-daemon probe` pattern already used elsewhere in the codebase.
|
||||||
6. No client yet — that lands in T-126.
|
6. No client yet — that lands in T-126.
|
||||||
|
|
||||||
Source: T-99 sketch. Coordinates with: T-127 (InProcessClient swap), T-130 (MCP).', 'done', 'high', NULL, NULL, NULL, '2026-05-18 11:58:47', '2026-05-18 12:51:08', NULL, 'c002da123b9382b8cfd7b4318ccf4a47', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Source: T-99 sketch. Coordinates with: T-127 (InProcessClient swap), T-130 (MCP).', 'done', 'high', NULL, NULL, NULL, '2026-05-18 11:58:47', '2026-05-18 12:51:08', NULL, 'c002da123b9382b8cfd7b4318ccf4a47', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6KY9JVRKF22GGFMXR', 'task', '06FB0TNQM76Q97D8R01CRTTA9R', 'argv→IpcRequest translator on the Dart side', 'Second slice of T-99(a). Owns the CLI grammar so the C client stays a dumb pipe.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6KY9JVRKF22GGFMXR', 'task', '06FB0TNQM76Q97D8R01CRTTA9R', 'argv→IpcRequest translator on the Dart side', 'Second slice of T-99(a). Owns the CLI grammar so the C client stays a dumb pipe.
|
||||||
|
|
||||||
Add lib/src/cli/argv_to_request.dart: takes a List<String> (the argv after `clide`) and returns an IpcRequest. Handles `clide <subsystem> <verb> [positionals...] [--flag value] [-- argv...]` per D-6''s shape. Errors (unknown subsystem/verb, malformed flag) surface as IpcResponse.err with the right exit code per pql''s contract.
|
Add lib/src/cli/argv_to_request.dart: takes a List<String> (the argv after `clide`) and returns an IpcRequest. Handles `clide <subsystem> <verb> [positionals...] [--flag value] [-- argv...]` per D-6''s shape. Errors (unknown subsystem/verb, malformed flag) surface as IpcResponse.err with the right exit code per pql''s contract.
|
||||||
@@ -608,7 +608,7 @@ Acceptance:
|
|||||||
3. Round-trip tests against the existing IpcRequest envelope.
|
3. Round-trip tests against the existing IpcRequest envelope.
|
||||||
4. Sysexit-code parity with pql (0/1/2/3/4 + 64-78 reserved).
|
4. Sysexit-code parity with pql (0/1/2/3/4 + 64-78 reserved).
|
||||||
|
|
||||||
Source: T-99 sketch.', 'done', 'high', NULL, NULL, NULL, '2026-05-18 11:58:52', '2026-05-18 15:51:09', NULL, 'fb49caf38db53b7e7bbedecfdbe3b52d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Source: T-99 sketch.', 'done', 'high', NULL, NULL, NULL, '2026-05-18 11:58:52', '2026-05-18 15:51:09', NULL, 'fb49caf38db53b7e7bbedecfdbe3b52d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM78E2NAM4YK3A2AV6R', 'task', '06FB0TNQM76Q97D8R01CRTTA9R', 'thin C `clide` client binary in native/clide-cli/', 'Third slice of T-99(a). The user-facing entry point.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM78E2NAM4YK3A2AV6R', 'task', '06FB0TNQM76Q97D8R01CRTTA9R', 'thin C `clide` client binary in native/clide-cli/', 'Third slice of T-99(a). The user-facing entry point.
|
||||||
|
|
||||||
~150 LOC of C in native/clide-cli/. Resolves the socket path (env override + default), connects, sends a single JSON-line request shaped as {"argv": [...]} (parsing happens in Dart per T-125), reads the JSON-line response, writes stdout/stderr per the pql contract, exits with the response''s exit code.
|
~150 LOC of C in native/clide-cli/. Resolves the socket path (env override + default), connects, sends a single JSON-line request shaped as {"argv": [...]} (parsing happens in Dart per T-125), reads the JSON-line response, writes stdout/stderr per the pql contract, exits with the response''s exit code.
|
||||||
@@ -620,7 +620,7 @@ Acceptance:
|
|||||||
4. `clide nonsense` returns the right exit code (sysexit 64 = usage error per D-6).
|
4. `clide nonsense` returns the right exit code (sysexit 64 = usage error per D-6).
|
||||||
5. Documented in assets/licenses.yaml + a one-paragraph note in CONTRIBUTING.md.
|
5. Documented in assets/licenses.yaml + a one-paragraph note in CONTRIBUTING.md.
|
||||||
|
|
||||||
Source: T-99 sketch. Depends on T-124 (server) + T-125 (argv translator).', 'done', 'high', NULL, NULL, NULL, '2026-05-18 11:58:57', '2026-05-18 16:04:29', NULL, '111faf9e03df8450abc4ef50bd38e80b', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Source: T-99 sketch. Depends on T-124 (server) + T-125 (argv translator).', 'done', 'high', NULL, NULL, NULL, '2026-05-18 11:58:57', '2026-05-18 16:04:29', NULL, '111faf9e03df8450abc4ef50bd38e80b', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7J40S0A8Q8PC0PDY8', 'task', '06FB0TNQM76Q97D8R01CRTTA9R', 'replace InProcessClient call sites with the socket loopback', 'Fourth slice of T-99(a). Convert the in-process callers — KernelServices.boot''s daemonClientFactory and friends — to talk to the local socket instead of the direct in-process dispatch path. Delete InProcessClient afterward.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7J40S0A8Q8PC0PDY8', 'task', '06FB0TNQM76Q97D8R01CRTTA9R', 'replace InProcessClient call sites with the socket loopback', 'Fourth slice of T-99(a). Convert the in-process callers — KernelServices.boot''s daemonClientFactory and friends — to talk to the local socket instead of the direct in-process dispatch path. Delete InProcessClient afterward.
|
||||||
|
|
||||||
Acceptance:
|
Acceptance:
|
||||||
@@ -630,7 +630,7 @@ Acceptance:
|
|||||||
4. Wall-clock perf delta is within reason (no widget rebuild storm; round-trip ~ms) — measure before/after under a representative test.
|
4. Wall-clock perf delta is within reason (no widget rebuild storm; round-trip ~ms) — measure before/after under a representative test.
|
||||||
5. Falls back to in-process direct dispatch if the perf delta is unacceptable; surface the finding in a Q-record before doing so.
|
5. Falls back to in-process direct dispatch if the perf delta is unacceptable; surface the finding in a Q-record before doing so.
|
||||||
|
|
||||||
Source: T-99 sketch. Depends on T-124 (server must exist). Blocks T-128 (legacy IPC cleanup).', 'done', 'high', NULL, NULL, NULL, '2026-05-18 11:59:02', '2026-05-19 10:03:26', NULL, '4dbfa582f178cfb41925b65a24fdbb58', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Source: T-99 sketch. Depends on T-124 (server must exist). Blocks T-128 (legacy IPC cleanup).', 'done', 'high', NULL, NULL, NULL, '2026-05-18 11:59:02', '2026-05-19 10:03:26', NULL, '4dbfa582f178cfb41925b65a24fdbb58', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6KEY6593FMW8Y40VC', 'task', '06FB0TNQM76Q97D8R01CRTTA9R', 'delete IsolateClient + Backend + backend_entry.dart; collapse service registration', 'Fifth slice of T-99(a). Pure cleanup once T-127 lands.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6KEY6593FMW8Y40VC', 'task', '06FB0TNQM76Q97D8R01CRTTA9R', 'delete IsolateClient + Backend + backend_entry.dart; collapse service registration', 'Fifth slice of T-99(a). Pure cleanup once T-127 lands.
|
||||||
|
|
||||||
Remove the third unused IPC path entirely. Today three implementations coexist: DaemonClient (socket — gets a real server in T-124), InProcessClient (deleted in T-127), and IsolateClient + Backend + backend_entry.dart (a backend isolate path that was never wired through). After T-127, none of those should still be referenced.
|
Remove the third unused IPC path entirely. Today three implementations coexist: DaemonClient (socket — gets a real server in T-124), InProcessClient (deleted in T-127), and IsolateClient + Backend + backend_entry.dart (a backend isolate path that was never wired through). After T-127, none of those should still be referenced.
|
||||||
@@ -642,7 +642,7 @@ Acceptance:
|
|||||||
2. Single service-registration site; no duplicate registerPaneCommands / registerFilesCommands / etc. across files.
|
2. Single service-registration site; no duplicate registerPaneCommands / registerFilesCommands / etc. across files.
|
||||||
3. flutter analyze + full test suite green.
|
3. flutter analyze + full test suite green.
|
||||||
|
|
||||||
Source: T-99 sketch. Depends on T-127.', 'done', 'medium', NULL, NULL, NULL, '2026-05-18 11:59:06', '2026-05-19 10:06:46', NULL, 'd59b5ab3b77ef993dc3a9e776b851ff5', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Source: T-99 sketch. Depends on T-127.', 'done', 'medium', NULL, NULL, NULL, '2026-05-18 11:59:06', '2026-05-19 10:06:46', NULL, 'd59b5ab3b77ef993dc3a9e776b851ff5', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM40XWGSN99DBDQDHJR', 'task', '06FB0TNQM76Q97D8R01CRTTA9R', 'event streaming over the socket — `clide tail --events`', 'Sixth slice of T-99(a). Long-lived subscription channel — the second half of D-6 (`clide tail --events [--filter <subsystem>[:<id>]]`).
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM40XWGSN99DBDQDHJR', 'task', '06FB0TNQM76Q97D8R01CRTTA9R', 'event streaming over the socket — `clide tail --events`', 'Sixth slice of T-99(a). Long-lived subscription channel — the second half of D-6 (`clide tail --events [--filter <subsystem>[:<id>]]`).
|
||||||
|
|
||||||
Client opens a connection, sends {"subscribe": "<subsystem>|*"}, server pushes JSON-line events until the client closes. Per D-6: replay buffer per subsystem (default depth 16) so a late subscriber still sees recent effects.
|
Client opens a connection, sends {"subscribe": "<subsystem>|*"}, server pushes JSON-line events until the client closes. Per D-6: replay buffer per subsystem (default depth 16) so a late subscriber still sees recent effects.
|
||||||
@@ -653,7 +653,7 @@ Acceptance:
|
|||||||
3. Server doesn''t block writes on a slow client (back-pressure handling per Q-2 — drop with a warning or apply flow control; resolve in this ticket).
|
3. Server doesn''t block writes on a slow client (back-pressure handling per Q-2 — drop with a warning or apply flow control; resolve in this ticket).
|
||||||
4. End-to-end smoke: launch app, run `clide tail --events --filter pane` in another shell, perform a pane action in the UI, observe the event.
|
4. End-to-end smoke: launch app, run `clide tail --events --filter pane` in another shell, perform a pane action in the UI, observe the event.
|
||||||
|
|
||||||
Source: T-99 sketch. Depends on T-124 + T-126.', 'done', 'medium', NULL, NULL, NULL, '2026-05-18 11:59:11', '2026-05-19 12:19:51', NULL, 'c93cdc6d0a99a0f89768b0c9b1fb83e4', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Source: T-99 sketch. Depends on T-124 + T-126.', 'done', 'medium', NULL, NULL, NULL, '2026-05-18 11:59:11', '2026-05-19 12:19:51', NULL, 'c93cdc6d0a99a0f89768b0c9b1fb83e4', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5MW2V3QCMWKMY4VQM', 'task', '06FB0TNQM76Q97D8R01CRTTA9R', 'MCP server alongside the CLI, wrapping the same dispatcher (D-68)', 'Seventh slice of T-99(a). Adds an /ide-compatible MCP endpoint per D-68 so Claude Code instances outside clide can connect via /ide.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5MW2V3QCMWKMY4VQM', 'task', '06FB0TNQM76Q97D8R01CRTTA9R', 'MCP server alongside the CLI, wrapping the same dispatcher (D-68)', 'Seventh slice of T-99(a). Adds an /ide-compatible MCP endpoint per D-68 so Claude Code instances outside clide can connect via /ide.
|
||||||
|
|
||||||
Minimum tools (per D-68): mcp__ide__getDiagnostics, mcp__ide__executeCode. Optional mcp__clide__* namespace deferred to Q-32. Transport choice (SSE vs WebSocket vs stdio) — resolve Q-33 at the start of this ticket.
|
Minimum tools (per D-68): mcp__ide__getDiagnostics, mcp__ide__executeCode. Optional mcp__clide__* namespace deferred to Q-32. Transport choice (SSE vs WebSocket vs stdio) — resolve Q-33 at the start of this ticket.
|
||||||
@@ -666,7 +666,7 @@ Acceptance:
|
|||||||
3. Both minimum tools work end-to-end against a real Claude Code session.
|
3. Both minimum tools work end-to-end against a real Claude Code session.
|
||||||
4. Q-32 + Q-33 closed (either as decisions or with resolutions written into the ticket).
|
4. Q-32 + Q-33 closed (either as decisions or with resolutions written into the ticket).
|
||||||
|
|
||||||
Source: T-99 sketch. Depends on T-124 (server foundation must exist). Can land in parallel with T-127 / T-128 / T-129.', 'done', 'medium', NULL, NULL, 'D-68', '2026-05-18 11:59:17', '2026-05-19 12:33:52', NULL, '61783e1808aaf90f14b81186c104b236', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Source: T-99 sketch. Depends on T-124 (server foundation must exist). Can land in parallel with T-127 / T-128 / T-129.', 'done', 'medium', NULL, NULL, 'D-68', '2026-05-18 11:59:17', '2026-05-19 12:33:52', NULL, '61783e1808aaf90f14b81186c104b236', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5ZSRZARG7SXCC71NM', 'task', '06FB0TNQM76Q97D8R01CRTTA9R', 'T-99 wrap-up: governance + docs + unblock T-119 / T-120', 'Eighth and final slice of T-99(a). Bookkeeping once the substantive work lands.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5ZSRZARG7SXCC71NM', 'task', '06FB0TNQM76Q97D8R01CRTTA9R', 'T-99 wrap-up: governance + docs + unblock T-119 / T-120', 'Eighth and final slice of T-99(a). Bookkeeping once the substantive work lands.
|
||||||
|
|
||||||
Acceptance:
|
Acceptance:
|
||||||
@@ -677,7 +677,7 @@ Acceptance:
|
|||||||
5. T-120 (typed IPC schema framework) re-scoped if needed; the wire contract is now real.
|
5. T-120 (typed IPC schema framework) re-scoped if needed; the wire contract is now real.
|
||||||
6. T-99 itself transitions to done.
|
6. T-99 itself transitions to done.
|
||||||
|
|
||||||
Source: T-99 sketch. Depends on T-124 + T-125 + T-126 + T-127 + T-128 (+T-129, +T-130 if landed).', 'done', 'medium', NULL, NULL, NULL, '2026-05-18 11:59:23', '2026-05-19 13:14:41', NULL, '0a1e7189d21ee6542777379f23779dce', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Source: T-99 sketch. Depends on T-124 + T-125 + T-126 + T-127 + T-128 (+T-129, +T-130 if landed).', 'done', 'medium', NULL, NULL, NULL, '2026-05-18 11:59:23', '2026-05-19 13:14:41', NULL, '0a1e7189d21ee6542777379f23779dce', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM76Q97D8R01CRTTA9R', 'task', '06FB0TNQM56CF9W94FSFDSBKGW', 'implement (or amend) the IPC socket server per D-1/D-6/D-56/D-68', 'D-56 specifies the Flutter app hosts an in-process IPC server reachable by a thin C client over a Unix socket; D-1/D-6 commit to CLI-first. Today no `ServerSocket` for unix-domain exists anywhere in `lib/`. Three IPC clients coexist (`DaemonClient` socket, `InProcessClient`, `IsolateClient` + `Backend`/`backend_entry.dart`); two service-wiring sites duplicate registration. The load-bearing CLI-first guardrail has no runtime path. D-68 (filed in this session) commits to the dual-surface plan.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM76Q97D8R01CRTTA9R', 'task', '06FB0TNQM56CF9W94FSFDSBKGW', 'implement (or amend) the IPC socket server per D-1/D-6/D-56/D-68', 'D-56 specifies the Flutter app hosts an in-process IPC server reachable by a thin C client over a Unix socket; D-1/D-6 commit to CLI-first. Today no `ServerSocket` for unix-domain exists anywhere in `lib/`. Three IPC clients coexist (`DaemonClient` socket, `InProcessClient`, `IsolateClient` + `Backend`/`backend_entry.dart`); two service-wiring sites duplicate registration. The load-bearing CLI-first guardrail has no runtime path. D-68 (filed in this session) commits to the dual-surface plan.
|
||||||
|
|
||||||
**Pick one path:**
|
**Pick one path:**
|
||||||
@@ -690,8 +690,8 @@ INSERT INTO tickets (record_id, type, parent_record_id, title, description, stat
|
|||||||
3. Service registration happens in one place.
|
3. Service registration happens in one place.
|
||||||
4. D-records updated to match reality.
|
4. D-records updated to match reality.
|
||||||
|
|
||||||
Source: consultants.md "Architecture — Findings — [Critical] No IPC socket server exists".', 'done', 'high', NULL, NULL, NULL, '2026-05-17 18:47:18', '2026-05-19 13:14:41', NULL, 'e4cc9c2bc07a53f7f49497cfed975ced', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Source: consultants.md "Architecture — Findings — [Critical] No IPC socket server exists".', 'done', 'high', NULL, NULL, NULL, '2026-05-17 18:47:18', '2026-05-19 13:14:41', NULL, 'e4cc9c2bc07a53f7f49497cfed975ced', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM54DENVAR46RXCCQQM', 'task', '06FB0TNQM76Q97D8R01CRTTA9R', 'clide panel resize CLI verb (split from T-111)', 'Once T-99 lands an IPC dispatch path, register a ''panel.resize'' command that takes <slot> and <delta-or-absolute> args and calls LayoutArrangement.setSize / setEditorRatio. Keyboard parity already landed in T-111; this completes user/Claude parity per D-6.', 'done', 'low', NULL, NULL, NULL, '2026-05-18 07:43:50', '2026-05-20 07:00:06', NULL, 'a2f9dbe79dc509701c70c8615b0ccbbb', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM54DENVAR46RXCCQQM', 'task', '06FB0TNQM76Q97D8R01CRTTA9R', 'clide panel resize CLI verb (split from T-111)', 'Once T-99 lands an IPC dispatch path, register a ''panel.resize'' command that takes <slot> and <delta-or-absolute> args and calls LayoutArrangement.setSize / setEditorRatio. Keyboard parity already landed in T-111; this completes user/Claude parity per D-6.', 'done', 'low', NULL, NULL, NULL, '2026-05-18 07:43:50', '2026-05-20 07:00:06', NULL, 'a2f9dbe79dc509701c70c8615b0ccbbb', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM47ARMYK2H24KJ0DAG', 'task', '06FB0TNQM56CF9W94FSFDSBKGW', 'typed IPC command schema framework (split from T-104)', 'T-104 covered the spot-fixes (argv-injection rejection, size/count caps on specific commands). What remains is the framework piece: a typed schema per IPC command — branch/remote/path/etc. with regex/charset constraints — applied at DaemonDispatcher dispatch time rather than scattered through individual handlers.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM47ARMYK2H24KJ0DAG', 'task', '06FB0TNQM56CF9W94FSFDSBKGW', 'typed IPC command schema framework (split from T-104)', 'T-104 covered the spot-fixes (argv-injection rejection, size/count caps on specific commands). What remains is the framework piece: a typed schema per IPC command — branch/remote/path/etc. with regex/charset constraints — applied at DaemonDispatcher dispatch time rather than scattered through individual handlers.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -711,10 +711,10 @@ Acceptance:
|
|||||||
4. No third-party validation dep; no lint suppressions.
|
4. No third-party validation dep; no lint suppressions.
|
||||||
5. Tests cover: schema accept/reject per constraint kind, dispatcher-level rejection, and that an unschema-d command still dispatches.
|
5. Tests cover: schema accept/reject per constraint kind, dispatcher-level rejection, and that an unschema-d command still dispatches.
|
||||||
|
|
||||||
Source: consultants.md "Security — Findings — [Major]" item 1. Decision: D-74.', 'done', 'medium', NULL, NULL, NULL, '2026-05-18 07:53:08', '2026-05-20 16:02:35', NULL, '7fc0d11030586b40bb0645cf46d8564e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Source: consultants.md "Security — Findings — [Major]" item 1. Decision: D-74.', 'done', 'medium', NULL, NULL, NULL, '2026-05-18 07:53:08', '2026-05-20 16:02:35', NULL, '7fc0d11030586b40bb0645cf46d8564e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM56CF9W94FSFDSBKGW', 'epic', NULL, 'Address 2026-05-14 consultant review', 'Six-reviewer external assessment found four critical gaps (workspace RCE, IPC server unimplemented, keyboard not operable, onboarding docs describe a dissolved architecture) plus ten major items and a handful of quick wins. Source: consultants.md (committed alongside this epic). Children are filed individually so they can land independently.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM56CF9W94FSFDSBKGW', 'epic', NULL, 'Address 2026-05-14 consultant review', 'Six-reviewer external assessment found four critical gaps (workspace RCE, IPC server unimplemented, keyboard not operable, onboarding docs describe a dissolved architecture) plus ten major items and a handful of quick wins. Source: consultants.md (committed alongside this epic). Children are filed individually so they can land independently.
|
||||||
|
|
||||||
Acceptance: all critical findings resolved or formally rejected with a D-record; all major findings either shipped or moved to a follow-up epic with rationale; quick-win batches closed.', 'done', 'high', NULL, NULL, NULL, '2026-05-17 18:47:08', '2026-05-20 16:02:46', NULL, '9a79f6058c693d3ee4aa33901a0274a6', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Acceptance: all critical findings resolved or formally rejected with a D-record; all major findings either shipped or moved to a follow-up epic with rationale; quick-win batches closed.', 'done', 'high', NULL, NULL, NULL, '2026-05-17 18:47:08', '2026-05-20 16:02:46', NULL, '9a79f6058c693d3ee4aa33901a0274a6', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6TNXTJCQBH9VADC4M', 'epic', NULL, 'drive line coverage from 35% to 95%', '## OUTCOME (closed 2026-05-18)
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6TNXTJCQBH9VADC4M', 'epic', NULL, 'drive line coverage from 35% to 95%', '## OUTCOME (closed 2026-05-18)
|
||||||
|
|
||||||
Epic met. Final measured line coverage **95.27%** (9551 / 10025), floor `coverage_floor: 95` in `pubspec.yaml`, gate wired into `make push-check`.
|
Epic met. Final measured line coverage **95.27%** (9551 / 10025), floor `coverage_floor: 95` in `pubspec.yaml`, gate wired into `make push-check`.
|
||||||
@@ -786,7 +786,7 @@ The gate plumbing lands first so future test additions are visible as floor bump
|
|||||||
- `lib/test_app.dart` exclusion: verify in the gate child whether Dart''s coverage tooling already excludes it; if not, decide explicitly rather than carve it out silently.
|
- `lib/test_app.dart` exclusion: verify in the gate child whether Dart''s coverage tooling already excludes it; if not, decide explicitly rather than carve it out silently.
|
||||||
|
|
||||||
**Cross-references:** D-66 (this epic''s decision record), D-29 (pre-push gate scope), "Own the rendering stack" guardrail (CLAUDE.md).
|
**Cross-references:** D-66 (this epic''s decision record), D-29 (pre-push gate scope), "Own the rendering stack" guardrail (CLAUDE.md).
|
||||||
', 'done', 'high', NULL, NULL, 'D-66', '2026-05-06 20:36:42', '2026-05-22 13:37:46', NULL, '788cbb0e54e483350dfc40399ed383bf', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
', 'done', 'high', NULL, NULL, 'D-66', '2026-05-06 20:36:42', '2026-05-22 13:37:46', NULL, '788cbb0e54e483350dfc40399ed383bf', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4HGK6KR0314P2M32M', 'task', '06FB0TNQM6TNXTJCQBH9VADC4M', 'test sweep: drive lib/src/terminal/ to 95%', 'Second child of T-89. The dominant coverage hole — `lib/src/terminal/` is 12 / 3167 lines (0.4%), about 56% of the global gap.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4HGK6KR0314P2M32M', 'task', '06FB0TNQM6TNXTJCQBH9VADC4M', 'test sweep: drive lib/src/terminal/ to 95%', 'Second child of T-89. The dominant coverage hole — `lib/src/terminal/` is 12 / 3167 lines (0.4%), about 56% of the global gap.
|
||||||
|
|
||||||
**Today''s distribution within `lib/src/terminal/src/`:**
|
**Today''s distribution within `lib/src/terminal/src/`:**
|
||||||
@@ -831,8 +831,8 @@ Land tests in batches per sub-area (one commit per `core/buffer/`, `core/escape/
|
|||||||
- Mouse / keyboard *protocol* round-trips against real TUIs (that''s T-74 and integration work).
|
- Mouse / keyboard *protocol* round-trips against real TUIs (that''s T-74 and integration work).
|
||||||
|
|
||||||
**Cross-references:** D-66 (coverage gate), T-89 (epic), T-90 (gate plumbing).
|
**Cross-references:** D-66 (coverage gate), T-89 (epic), T-90 (gate plumbing).
|
||||||
', 'done', 'high', NULL, NULL, 'D-66', '2026-05-06 20:49:47', '2026-05-22 13:37:46', NULL, 'f107220fb3f72e619a9a0f6bf8843168', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
', 'done', 'high', NULL, NULL, 'D-66', '2026-05-06 20:49:47', '2026-05-22 13:37:46', NULL, 'f107220fb3f72e619a9a0f6bf8843168', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM54G017Y29APWJTCN0', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Author D-75: native transcript rendering + accepted CC-internals coupling', 'Author the D-75 architecture record (id already claimed via pql decisions claim): Claude is rendered natively from transcripts, not the terminal; accept isolated, version-pinned coupling to Claude Code internal contracts (transcript JSONL schema, ~/.claude/teams config, tmux control mode); terminal retained as a general IDE tool only. Record Claude-centric > CLI-first ordering with D-6 surfaces preserved. Acceptance: D-75 written in governance/decisions/architecture.md with Decision/Rationale/Cost/Cross-reference/Raised-by; governance README synced (pql decisions sync) + pql decisions validate ok; cited by T5/T7. Do early — frames the epic.', 'done', 'high', NULL, NULL, NULL, '2026-05-22 15:50:06', '2026-05-22 17:37:23', NULL, '0f4ad39a71e65ed066d5de55261e8323', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM54G017Y29APWJTCN0', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Author D-75: native transcript rendering + accepted CC-internals coupling', 'Author the D-75 architecture record (id already claimed via pql decisions claim): Claude is rendered natively from transcripts, not the terminal; accept isolated, version-pinned coupling to Claude Code internal contracts (transcript JSONL schema, ~/.claude/teams config, tmux control mode); terminal retained as a general IDE tool only. Record Claude-centric > CLI-first ordering with D-6 surfaces preserved. Acceptance: D-75 written in governance/decisions/architecture.md with Decision/Rationale/Cost/Cross-reference/Raised-by; governance README synced (pql decisions sync) + pql decisions validate ok; cited by T5/T7. Do early — frames the epic.', 'done', 'high', NULL, NULL, NULL, '2026-05-22 15:50:06', '2026-05-22 17:37:23', NULL, '0f4ad39a71e65ed066d5de55261e8323', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6SRMD12DMXCX6N7DM', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Native text-selection foundation (SelectionArea-compatible widgets)', 'Make clide''s native text widgets selectable so a SelectionArea can select across them. Change lib/widgets/src/clide_markdown.dart RichText (line ~68) -> Text.rich; same for lib/widgets/src/clide_code_block.dart; add a selectionBackground token to SurfaceTokens (lib/kernel/src/theme/tokens.dart + resolver + bundled theme YAMLs); verify copy via existing ClideClipboard (lib/kernel/src/clipboard.dart). Acceptance: a SelectionArea-wrapped column of markdown + code blocks supports select-across-blocks + Ctrl+C copy; widget tests; a11y unaffected; coverage >= floor. Reusable foundation. Blocks T5.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6SRMD12DMXCX6N7DM', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Native text-selection foundation (SelectionArea-compatible widgets)', 'Make clide''s native text widgets selectable so a SelectionArea can select across them. Change lib/widgets/src/clide_markdown.dart RichText (line ~68) -> Text.rich; same for lib/widgets/src/clide_code_block.dart; add a selectionBackground token to SurfaceTokens (lib/kernel/src/theme/tokens.dart + resolver + bundled theme YAMLs); verify copy via existing ClideClipboard (lib/kernel/src/clipboard.dart). Acceptance: a SelectionArea-wrapped column of markdown + code blocks supports select-across-blocks + Ctrl+C copy; widget tests; a11y unaffected; coverage >= floor. Reusable foundation. Blocks T5.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -842,7 +842,7 @@ Refinement (2026-05-22, refinement-agent review):
|
|||||||
- selectionBackground token: add to SurfaceTokens (field + TokenKeys + TokenKeys.all) + resolver.dart (_defaultSurfaceMap default + constructor). Bundled theme YAMLs do NOT need it (default map covers it); per-theme override only if the default reads wrong. Do NOT retune existing palettes (published themes are user contracts).
|
- selectionBackground token: add to SurfaceTokens (field + TokenKeys + TokenKeys.all) + resolver.dart (_defaultSurfaceMap default + constructor). Bundled theme YAMLs do NOT need it (default map covers it); per-theme override only if the default reads wrong. Do NOT retune existing palettes (published themes are user contracts).
|
||||||
- Add a selection contrast pair (globalForeground on selectionBackground) to lib/kernel/src/theme/contrast.dart canonicalPairs; re-run test/a11y. (Note: summer-night.yaml is missing from contrast_test bundledPaths -- pre-existing inconsistency, out of scope.)
|
- Add a selection contrast pair (globalForeground on selectionBackground) to lib/kernel/src/theme/contrast.dart canonicalPairs; re-run test/a11y. (Note: summer-night.yaml is missing from contrast_test bundledPaths -- pre-existing inconsistency, out of scope.)
|
||||||
- COPY PATH CORRECTION: SelectionArea Ctrl+C goes through Flutter services.Clipboard directly, NOT ClideClipboard. Test verifies Clipboard.getData returns the selection after copy.
|
- COPY PATH CORRECTION: SelectionArea Ctrl+C goes through Flutter services.Clipboard directly, NOT ClideClipboard. Test verifies Clipboard.getData returns the selection after copy.
|
||||||
- Coverage floor is 95%.', 'done', 'high', NULL, NULL, NULL, '2026-05-22 15:59:34', '2026-05-22 17:37:23', NULL, '5bc2b7bf7f348e6ed8da2f928dd47b79', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
- Coverage floor is 95%.', 'done', 'high', NULL, NULL, NULL, '2026-05-22 15:59:34', '2026-05-22 17:37:23', NULL, '5bc2b7bf7f348e6ed8da2f928dd47b79', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM54N0ZDJRS7G6MP1XC', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'TranscriptReader: tail + parse Claude transcript JSONL', 'New lib/builtin/claude/src/transcript_reader.dart. Resolve munged project path (/ -> -) + session-id; tail the append-only JSONL; parse records (type: user/assistant/attachment/tool; message; agentId; isSidechain) into ConversationItem models; drift-guard on the version field (log + degrade on unknown schema). Paths validated this session: ~/.claude/projects/<munged>/<sid>.jsonl (lead) and <sid>/subagents/agent-<id>.jsonl (teammates). Acceptance: unit tests against a snapshotted JSONL fixture (assistant text, tool_use, tool_result); appended lines stream in; unknown version degrades gracefully + logs. Blocks T5.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM54N0ZDJRS7G6MP1XC', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'TranscriptReader: tail + parse Claude transcript JSONL', 'New lib/builtin/claude/src/transcript_reader.dart. Resolve munged project path (/ -> -) + session-id; tail the append-only JSONL; parse records (type: user/assistant/attachment/tool; message; agentId; isSidechain) into ConversationItem models; drift-guard on the version field (log + degrade on unknown schema). Paths validated this session: ~/.claude/projects/<munged>/<sid>.jsonl (lead) and <sid>/subagents/agent-<id>.jsonl (teammates). Acceptance: unit tests against a snapshotted JSONL fixture (assistant text, tool_use, tool_result); appended lines stream in; unknown version degrades gracefully + logs. Blocks T5.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -852,7 +852,7 @@ Refinement (2026-05-22, refinement-agent review): READY. Verified against real t
|
|||||||
- SESSION-ID: claude does not expose its session UUID via argv/env (verified in claude_pane spawn). Approach: newest *.jsonl by mtime in ~/.claude/projects/<munged>/; poll mtime and switch the tail when a newer session appears.
|
- SESSION-ID: claude does not expose its session UUID via argv/env (verified in claude_pane spawn). Approach: newest *.jsonl by mtime in ~/.claude/projects/<munged>/; poll mtime and switch the tail when a newer session appears.
|
||||||
- Subagent transcripts: <munged>/<session-uuid>/subagents/agent-<id>.jsonl + sibling .meta.json ({agentType,description}); each record carries agentId.
|
- Subagent transcripts: <munged>/<session-uuid>/subagents/agent-<id>.jsonl + sibling .meta.json ({agentType,description}); each record carries agentId.
|
||||||
- Tail: dart:io File.openRead with a byte-position cursor (File.length + RandomAccessFile.setPosition on poll). Do NOT use lib/src/files/watcher.dart. Zero new deps.
|
- Tail: dart:io File.openRead with a byte-position cursor (File.length + RandomAccessFile.setPosition on poll). Do NOT use lib/src/files/watcher.dart. Zero new deps.
|
||||||
- Logger: lib/kernel/src/log.dart for the version drift-guard. Coverage floor 95%.', 'done', 'high', NULL, NULL, NULL, '2026-05-22 15:59:34', '2026-05-22 17:37:23', NULL, 'f78456fd152da1cd9eac8f7554313119', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
- Logger: lib/kernel/src/log.dart for the version drift-guard. Coverage floor 95%.', 'done', 'high', NULL, NULL, NULL, '2026-05-22 15:59:34', '2026-05-22 17:37:23', NULL, 'f78456fd152da1cd9eac8f7554313119', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4EQAERS4J9X9RAETR', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Spike: validate Claude Code team/transcript internals (pin a CC version)', 'Investigate empirically and write a findings note pinned to the current Claude Code version. 1) Team spawn inside tmux -L clide with CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 + teammateMode: tmux -> teammate panes (list-panes -a) + each teammate''s <sid>/subagents/agent-*.jsonl grows. 2) Lifecycle: tmux -L clide -C control-mode pane-add/pane-died events vs polling list-panes. 3) ~/.claude/teams/<team>/config.json layout: tmuxPaneId, agentId, agentType populate at spawn. 4) Image/file paste intake when driven via send-keys (path/@-ref vs clipboard-image vs unsupported). 5) Active session-id discovery (capture at spawn vs newest JSONL in munged dir). Already validated this session: transcript paths + schema (type/message/agentId/version) + subagent transcript location. Acceptance: findings note answering 1-5, CC version pinned. Blocks T6, T7.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4EQAERS4J9X9RAETR', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Spike: validate Claude Code team/transcript internals (pin a CC version)', 'Investigate empirically and write a findings note pinned to the current Claude Code version. 1) Team spawn inside tmux -L clide with CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 + teammateMode: tmux -> teammate panes (list-panes -a) + each teammate''s <sid>/subagents/agent-*.jsonl grows. 2) Lifecycle: tmux -L clide -C control-mode pane-add/pane-died events vs polling list-panes. 3) ~/.claude/teams/<team>/config.json layout: tmuxPaneId, agentId, agentType populate at spawn. 4) Image/file paste intake when driven via send-keys (path/@-ref vs clipboard-image vs unsupported). 5) Active session-id discovery (capture at spawn vs newest JSONL in munged dir). Already validated this session: transcript paths + schema (type/message/agentId/version) + subagent transcript location. Acceptance: findings note answering 1-5, CC version pinned. Blocks T6, T7.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -867,14 +867,14 @@ Refinement (2026-05-22, refinement-agent review):
|
|||||||
- Deliverable: findings note at docs/spikes/cc-team-internals-2.1.148.md (in-repo), feeding D-75 when authored (T-133). D-75 is claimed-but-unauthored (T-133''s job) -- the reference is forward-looking, not dangling.
|
- Deliverable: findings note at docs/spikes/cc-team-internals-2.1.148.md (in-repo), feeding D-75 when authored (T-133). D-75 is claimed-but-unauthored (T-133''s job) -- the reference is forward-looking, not dangling.
|
||||||
|
|
||||||
---
|
---
|
||||||
Findings (2026-05-22): docs/spikes/cc-team-internals-2.1.148.md. All 5 checks answered from real artifacts + tmux manual + synthetic control-mode test (no live run/quota). Key risk for T-139: pane->teammate->transcript identity joins only on agentType (config <-> .meta.json), ambiguous for same-type teammates -> needs joinedAt/mtime or lead-transcript tiebreaker. tmux 3.6a has no %pane-died; poll list-panes -a. Teammate transcripts at <munged>/<sid>/subagents/agent-<hex>.jsonl + .meta.json{agentType,description}.', 'done', 'high', NULL, NULL, NULL, '2026-05-22 15:59:34', '2026-05-22 17:55:11', NULL, 'fd761165a2bd6d554de00f51b4b776be', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Findings (2026-05-22): docs/spikes/cc-team-internals-2.1.148.md. All 5 checks answered from real artifacts + tmux manual + synthetic control-mode test (no live run/quota). Key risk for T-139: pane->teammate->transcript identity joins only on agentType (config <-> .meta.json), ambiguous for same-type teammates -> needs joinedAt/mtime or lead-transcript tiebreaker. tmux 3.6a has no %pane-died; poll list-panes -a. Teammate transcripts at <munged>/<sid>/subagents/agent-<hex>.jsonl + .meta.json{agentType,description}.', 'done', 'high', NULL, NULL, NULL, '2026-05-22 15:59:34', '2026-05-22 17:55:11', NULL, 'fd761165a2bd6d554de00f51b4b776be', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6E3X5WWRS09GCDGK8', 'story', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'ConversationView + replace the terminal in the Claude pane', 'New lib/builtin/claude/src/conversation_view.dart rendering user / assistant(markdown via ClideMarkdown) / tool-call card / tool-result+diff card; whole tree under one SelectionArea. Swap ClidePtyView -> ConversationView in lib/builtin/claude/src/claude_pane.dart (~line 287). Claude still runs in tmux (detached / output ignored) but content comes from the transcript (TranscriptReader). Keep the terminal builtin + ClidePtyView for general use. Surface conversation as events too (D-6). Cite D-75. Acceptance: make run shows the native Claude conversation from the live transcript; select+copy across cards works; no terminal in the Claude pane; terminal builtin still works; widget tests. Blocked by T3, T4.', 'done', 'high', NULL, NULL, NULL, '2026-05-22 15:59:34', '2026-05-22 18:14:32', NULL, 'c7907de905ec5dfff0c89ca2fad57b51', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6E3X5WWRS09GCDGK8', 'story', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'ConversationView + replace the terminal in the Claude pane', 'New lib/builtin/claude/src/conversation_view.dart rendering user / assistant(markdown via ClideMarkdown) / tool-call card / tool-result+diff card; whole tree under one SelectionArea. Swap ClidePtyView -> ConversationView in lib/builtin/claude/src/claude_pane.dart (~line 287). Claude still runs in tmux (detached / output ignored) but content comes from the transcript (TranscriptReader). Keep the terminal builtin + ClidePtyView for general use. Surface conversation as events too (D-6). Cite D-75. Acceptance: make run shows the native Claude conversation from the live transcript; select+copy across cards works; no terminal in the Claude pane; terminal builtin still works; widget tests. Blocked by T3, T4.', 'done', 'high', NULL, NULL, NULL, '2026-05-22 15:59:34', '2026-05-22 18:14:32', NULL, 'c7907de905ec5dfff0c89ca2fad57b51', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4V1PZ0EK6G60699EM', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Native composer + file/image paste', 'New lib/builtin/claude/src/claude_composer.dart: native text field -> tmux -L clide send-keys -t <pane> (Enter submit, Shift+Enter newline). Paste text inline; file/image per the T2 spike finding (likely temp-file + path/@-reference, since send-keys carries text only). Acceptance: typing in the composer reaches Claude; pasting a text file and an image both work via the validated mechanism. Blocked by T2, T5.', 'done', 'medium', NULL, NULL, NULL, '2026-05-22 15:59:34', '2026-05-22 21:49:09', NULL, '893e645c6a0d43d5ee47ec04fb1df52d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4V1PZ0EK6G60699EM', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Native composer + file/image paste', 'New lib/builtin/claude/src/claude_composer.dart: native text field -> tmux -L clide send-keys -t <pane> (Enter submit, Shift+Enter newline). Paste text inline; file/image per the T2 spike finding (likely temp-file + path/@-reference, since send-keys carries text only). Acceptance: typing in the composer reaches Claude; pasting a text file and an image both work via the validated mechanism. Blocked by T2, T5.', 'done', 'medium', NULL, NULL, NULL, '2026-05-22 15:59:34', '2026-05-22 21:49:09', NULL, '893e645c6a0d43d5ee47ec04fb1df52d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM427ZFSTWJ21EBK5FG', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Composer attachment chips (thumbnail/icon on paste)', 'Show pasted files/images as chips above the composer input instead of inserting the @path as text. Image chips render a thumbnail (Image.file of the cache/temp file); other types show a Phosphor file icon + basename; each chip has a remove ×. On submit, the typed text plus the chips'' @path tokens are assembled into the message sent via tmux.sendMessage, then text + chips clear. Typed @path text still works. resolveClipboardAttachment changes to return a list of attachment descriptors (path + isImage). No new package deps (Image.file + existing Phosphor icons). Builds on T-138.', 'done', 'medium', NULL, NULL, NULL, '2026-05-22 22:06:59', '2026-05-22 22:18:02', NULL, '1f97c9b10d740bbc4c27d87a1cc17eab', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM427ZFSTWJ21EBK5FG', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Composer attachment chips (thumbnail/icon on paste)', 'Show pasted files/images as chips above the composer input instead of inserting the @path as text. Image chips render a thumbnail (Image.file of the cache/temp file); other types show a Phosphor file icon + basename; each chip has a remove ×. On submit, the typed text plus the chips'' @path tokens are assembled into the message sent via tmux.sendMessage, then text + chips clear. Typed @path text still works. resolveClipboardAttachment changes to return a list of attachment descriptors (path + isImage). No new package deps (Image.file + existing Phosphor icons). Builds on T-138.', 'done', 'medium', NULL, NULL, NULL, '2026-05-22 22:06:59', '2026-05-22 22:18:02', NULL, '1f97c9b10d740bbc4c27d87a1cc17eab', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6YWAC8SSGQBK31T98', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Distinguish user message cards in the conversation', 'User messages render flat (label + text on the canvas) like Claude''s responses, so it''s hard to scan what you said vs what Claude said. Give UserMessage a distinct card: a filled background (globalBackground vs the panelBackground canvas), a left accent stripe (globalFocus), padding and rounded corners. Claude''s text responses stay flat markdown (better for long answers). conversation_view.dart _ConversationTurn.', 'done', 'low', NULL, NULL, NULL, '2026-05-22 22:31:22', '2026-05-22 22:36:09', NULL, '29cc73005b5c1574032b33a2da19469d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6YWAC8SSGQBK31T98', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Distinguish user message cards in the conversation', 'User messages render flat (label + text on the canvas) like Claude''s responses, so it''s hard to scan what you said vs what Claude said. Give UserMessage a distinct card: a filled background (globalBackground vs the panelBackground canvas), a left accent stripe (globalFocus), padding and rounded corners. Claude''s text responses stay flat markdown (better for long answers). conversation_view.dart _ConversationTurn.', 'done', 'low', NULL, NULL, NULL, '2026-05-22 22:31:22', '2026-05-22 22:36:09', NULL, '29cc73005b5c1574032b33a2da19469d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4BV0CXWCT04Z81EG0', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Claude message card with brand-orange accent', 'Extend the distinct-card treatment (T-143) to Claude''s text responses with a different accent: Claude''s brand coral-orange (#D97757), vs the user card''s focus-colour stripe. Refactor _userCard into a shared _messageCard(label, accent, body). conversation_view.dart.', 'done', 'low', NULL, NULL, NULL, '2026-05-22 22:40:42', '2026-05-22 22:43:45', NULL, '0f5df8bc9b99556647f168d9d60b20e6', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4BV0CXWCT04Z81EG0', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Claude message card with brand-orange accent', 'Extend the distinct-card treatment (T-143) to Claude''s text responses with a different accent: Claude''s brand coral-orange (#D97757), vs the user card''s focus-colour stripe. Refactor _userCard into a shared _messageCard(label, accent, body). conversation_view.dart.', 'done', 'low', NULL, NULL, NULL, '2026-05-22 22:40:42', '2026-05-22 22:43:45', NULL, '0f5df8bc9b99556647f168d9d60b20e6', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM653J6604KYDK6RT8R', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'tmux team observer (lifecycle + identity + per-teammate transcripts)', 'New lib/builtin/claude/src/team_observer.dart: detect teammate spawn/exit (control-mode or list-panes -a poll on -L clide), map pane->teammate via ~/.claude/teams config + agentId, spin a TranscriptReader per teammate, emit new TeamMemberBorn/TeamMemberDied ClideEvents (lib/kernel/src/events/types.dart). ALL fragile CC-internals parsing isolated here (single drift-containment point; key off the version field). Cite D-75. Acceptance: a real team run emits born/died with correct identity; per-teammate content streams. Blocked by T2, T4.', 'done', 'high', NULL, NULL, NULL, '2026-05-22 15:59:34', '2026-05-22 23:16:28', NULL, 'bdae2494e404fab83365166647dcba42', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM653J6604KYDK6RT8R', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'tmux team observer (lifecycle + identity + per-teammate transcripts)', 'New lib/builtin/claude/src/team_observer.dart: detect teammate spawn/exit (control-mode or list-panes -a poll on -L clide), map pane->teammate via ~/.claude/teams config + agentId, spin a TranscriptReader per teammate, emit new TeamMemberBorn/TeamMemberDied ClideEvents (lib/kernel/src/events/types.dart). ALL fragile CC-internals parsing isolated here (single drift-containment point; key off the version field). Cite D-75. Acceptance: a real team run emits born/died with correct identity; per-teammate content streams. Blocked by T2, T4.', 'done', 'high', NULL, NULL, NULL, '2026-05-22 15:59:34', '2026-05-22 23:16:28', NULL, 'bdae2494e404fab83365166647dcba42', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5AVSMKD15KBJYX48W', 'story', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Teammate tile grid (faithful tiling, responsive auto-wrap)', 'Tiling host: lead ConversationView (left, with composer) + teammate ConversationViews (right) in a responsive auto-wrap grid (1->2->3 columns by count); resizable lead/teammate split. Workspace currently only vertical-splits, so extend _WorkspaceSlot (lib/app.dart) or add team slots in lib/kernel/src/panels/layout_preset.dart; reuse DragResizeHandle (lib/kernel/src/panels/drag_resize.dart). Driven by TeamMemberBorn/Died from the observer. Acceptance: tiles appear/disappear with lifecycle; grid wraps 1->2->3 by count; split resizes; select-across-tiles works. Blocked by T5, T7.', 'done', 'medium', NULL, NULL, NULL, '2026-05-22 15:59:34', '2026-05-22 23:31:46', NULL, 'a862d2c4981582f6baa639f0c840ef40', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5AVSMKD15KBJYX48W', 'story', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Teammate tile grid (faithful tiling, responsive auto-wrap)', 'Tiling host: lead ConversationView (left, with composer) + teammate ConversationViews (right) in a responsive auto-wrap grid (1->2->3 columns by count); resizable lead/teammate split. Workspace currently only vertical-splits, so extend _WorkspaceSlot (lib/app.dart) or add team slots in lib/kernel/src/panels/layout_preset.dart; reuse DragResizeHandle (lib/kernel/src/panels/drag_resize.dart). Driven by TeamMemberBorn/Died from the observer. Acceptance: tiles appear/disappear with lifecycle; grid wraps 1->2->3 by count; split resizes; select-across-tiles works. Blocked by T5, T7.', 'done', 'medium', NULL, NULL, NULL, '2026-05-22 15:59:34', '2026-05-22 23:31:46', NULL, 'a862d2c4981582f6baa639f0c840ef40', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM558PCHET90BBSHGTC', 'bug', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Secondary Claude panes render the primary''s transcript', 'Regression from T-137: every Claude pane renders the newest .jsonl in the workspace''s munged dir, so concurrent sessions in one workspace (primary + secondaries) all converge on the same transcript — a secondary tab shows the primary''s conversation (and the primary follows whichever session is newest). The pre-T-137 terminal pane rendered each tab''s own PTY, so tabs were independent.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM558PCHET90BBSHGTC', 'bug', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Secondary Claude panes render the primary''s transcript', 'Regression from T-137: every Claude pane renders the newest .jsonl in the workspace''s munged dir, so concurrent sessions in one workspace (primary + secondaries) all converge on the same transcript — a secondary tab shows the primary''s conversation (and the primary follows whichever session is newest). The pre-T-137 terminal pane rendered each tab''s own PTY, so tabs were independent.
|
||||||
|
|
||||||
Fix: bind each pane to a specific Claude session id.
|
Fix: bind each pane to a specific Claude session id.
|
||||||
@@ -888,9 +888,9 @@ Migration caveat: an existing tmux session created by the OLD code (no --session
|
|||||||
Open question to validate live: whether `claude --session-id <existing-uuid>` resumes vs. errors when re-spawned after the tmux session was killed (display works either way since the file is <uuid>.jsonl, but worth confirming claude starts).
|
Open question to validate live: whether `claude --session-id <existing-uuid>` resumes vs. errors when re-spawned after the tmux session was killed (display works either way since the file is <uuid>.jsonl, but worth confirming claude starts).
|
||||||
|
|
||||||
Acceptance: a secondary tab shows its OWN fresh conversation, independent of the primary; the primary keeps its conversation; both update live. Regression of T-137; relates to D-41.
|
Acceptance: a secondary tab shows its OWN fresh conversation, independent of the primary; the primary keeps its conversation; both update live. Regression of T-137; relates to D-41.
|
||||||
', 'done', 'high', NULL, NULL, NULL, '2026-05-23 06:19:51', '2026-05-23 06:30:47', NULL, '146ac53bba08ab11c1e6d822e16e4699', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
', 'done', 'high', NULL, NULL, NULL, '2026-05-23 06:19:51', '2026-05-23 06:30:47', NULL, '146ac53bba08ab11c1e6d822e16e4699', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM47FEEMHPE8J5VVBKM', 'bug', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Claude pane gets stuck waiting on a stale/legacy session', 'When the bound transcript (<munged-cwd>/<session-id>.jsonl) never appears — e.g. attaching via new-session -A to a session created before --session-id binding (T-146), or any unconnectable session — the pane shows ''Waiting for Claude…'' forever. Fix: before spawning, if the bound transcript for our deterministic session id does not exist, kill the clide tmux session of that exact name so new-session creates a clean session with our --session-id. SAFETY (hard requirement): only ever kill clide-initiated sessions — by exact clide-claude-<slug> name, on the private -L clide socket (a user''s terminal claude is never on that socket); never delete any transcript file. Also makes clean-install/first-run robust. Live-verify the stuck primary self-heals on relaunch and a secondary still gets a fresh independent session.', 'done', 'high', NULL, NULL, NULL, '2026-05-23 07:03:18', '2026-05-23 07:06:54', NULL, '0e52f0983f071764a1cd2282c2b9bf9f', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM47FEEMHPE8J5VVBKM', 'bug', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Claude pane gets stuck waiting on a stale/legacy session', 'When the bound transcript (<munged-cwd>/<session-id>.jsonl) never appears — e.g. attaching via new-session -A to a session created before --session-id binding (T-146), or any unconnectable session — the pane shows ''Waiting for Claude…'' forever. Fix: before spawning, if the bound transcript for our deterministic session id does not exist, kill the clide tmux session of that exact name so new-session creates a clean session with our --session-id. SAFETY (hard requirement): only ever kill clide-initiated sessions — by exact clide-claude-<slug> name, on the private -L clide socket (a user''s terminal claude is never on that socket); never delete any transcript file. Also makes clean-install/first-run robust. Live-verify the stuck primary self-heals on relaunch and a secondary still gets a fresh independent session.', 'done', 'high', NULL, NULL, NULL, '2026-05-23 07:03:18', '2026-05-23 07:06:54', NULL, '0e52f0983f071764a1cd2282c2b9bf9f', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4GDS1R8H2TW12WX7G', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Native Claude pane startup banner (empty state)', 'Replace the bland ''Waiting for Claude…'' empty state with a native clide banner: clide logo, a Claude label (brand orange), the session role (primary/secondary N), the workspace path (home-collapsed), and the tmux session/status line, plus a ''warming up'' hint. Owned/native — no tmux capture-pane, no CC-internals coupling. ConversationView gains an optional emptyState widget; ClaudePane supplies a ClaudeBanner built from data it already has (repoRoot, statusLine, isPrimary).', 'done', 'low', NULL, NULL, NULL, '2026-05-23 07:14:36', '2026-05-23 07:27:32', NULL, 'b7112988f9ecc4dfab344d552f492287', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4GDS1R8H2TW12WX7G', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Native Claude pane startup banner (empty state)', 'Replace the bland ''Waiting for Claude…'' empty state with a native clide banner: clide logo, a Claude label (brand orange), the session role (primary/secondary N), the workspace path (home-collapsed), and the tmux session/status line, plus a ''warming up'' hint. Owned/native — no tmux capture-pane, no CC-internals coupling. ConversationView gains an optional emptyState widget; ClaudePane supplies a ClaudeBanner built from data it already has (repoRoot, statusLine, isPrimary).', 'done', 'low', NULL, NULL, NULL, '2026-05-23 07:14:36', '2026-05-23 07:27:32', NULL, 'b7112988f9ecc4dfab344d552f492287', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5KN50C7A723SEKZXG', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Per-session status strip: model / permission-mode / context%', 'A compact per-session status strip in the lead Claude pane header AND each teammate tile header (T-140), showing: current model, permission mode (accept-edits / plan / default / bypass), and context-window usage %.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5KN50C7A723SEKZXG', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Per-session status strip: model / permission-mode / context%', 'A compact per-session status strip in the lead Claude pane header AND each teammate tile header (T-140), showing: current model, permission mode (accept-edits / plan / default / bypass), and context-window usage %.
|
||||||
|
|
||||||
Shared status source (this ticket owns it): extract per-session status in the drift-contained reader/observer (D-75) — do NOT parse CC internals in the widgets.
|
Shared status source (this ticket owns it): extract per-session status in the drift-contained reader/observer (D-75) — do NOT parse CC internals in the widgets.
|
||||||
@@ -903,11 +903,11 @@ Delivery: emit a per-session status to the UI via the bus/events (e.g. a TeamMem
|
|||||||
Applies to the lead session and every teammate. Re-validate field names against a live team run / CC version bump (undocumented, per T-134).
|
Applies to the lead session and every teammate. Re-validate field names against a live team run / CC version bump (undocumented, per T-134).
|
||||||
|
|
||||||
Acceptance: lead pane header and each teammate tile header show current model + an accept-edits/plan-mode badge + a context-usage indicator, updating live from the transcript. Blocked by T-137 (done), T-140 (done).
|
Acceptance: lead pane header and each teammate tile header show current model + an accept-edits/plan-mode badge + a context-usage indicator, updating live from the transcript. Blocked by T-137 (done), T-140 (done).
|
||||||
', 'done', 'medium', NULL, NULL, NULL, '2026-05-23 06:07:59', '2026-05-23 08:43:19', NULL, 'dd8a218adfef6ab3bfeaa6897caf242a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
', 'done', 'medium', NULL, NULL, NULL, '2026-05-23 06:07:59', '2026-05-23 08:43:19', NULL, 'dd8a218adfef6ab3bfeaa6897caf242a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6F9XA7F2BX9P18BR4', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'ClidePane primitive + focus-driven status-bar slot', 'A behavior-only pane wrapper (no chrome) every pane uses, plus the plumbing to surface a pane status widget to the bottom status bar. FocusTracker gains: activeStatusWidget (the focused pane status widget), setStatusWidget(contributionId, widget) applied ONLY when that contribution is focused (background panes ignored; they keep content locally and re-convey on focus), and clears activeStatusWidget on focus change. ClidePane(contributionId, statusWidget, active, child): when it is the shown pane (active sub-tab AND its contribution focused) it conveys statusWidget on focus-gain and on content change. New status-bar item renders focus.activeStatusWidget in a fixed-height Container that marquee-scrolls on overflow (new ClideMarquee primitive, own-the-stack, no package). Claude adopts ClidePane (statusWidget = the model/mode/context line), replacing the bus-text slot from 06cf9f8. Disconnects slot plumbing from what a pane renders: text, icon, dropdown, animation, anything.', 'done', 'medium', NULL, NULL, NULL, '2026-05-23 09:04:40', '2026-05-23 09:33:03', NULL, 'fbf0c7bfe20c3fab8b8bea0ed2db8c69', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6F9XA7F2BX9P18BR4', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'ClidePane primitive + focus-driven status-bar slot', 'A behavior-only pane wrapper (no chrome) every pane uses, plus the plumbing to surface a pane status widget to the bottom status bar. FocusTracker gains: activeStatusWidget (the focused pane status widget), setStatusWidget(contributionId, widget) applied ONLY when that contribution is focused (background panes ignored; they keep content locally and re-convey on focus), and clears activeStatusWidget on focus change. ClidePane(contributionId, statusWidget, active, child): when it is the shown pane (active sub-tab AND its contribution focused) it conveys statusWidget on focus-gain and on content change. New status-bar item renders focus.activeStatusWidget in a fixed-height Container that marquee-scrolls on overflow (new ClideMarquee primitive, own-the-stack, no package). Claude adopts ClidePane (statusWidget = the model/mode/context line), replacing the bus-text slot from 06cf9f8. Disconnects slot plumbing from what a pane renders: text, icon, dropdown, animation, anything.', 'done', 'medium', NULL, NULL, NULL, '2026-05-23 09:04:40', '2026-05-23 09:33:03', NULL, 'fbf0c7bfe20c3fab8b8bea0ed2db8c69', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM77GWREHKA9K45P020', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'ClaudeConfig service: layered config + skills/commands + version-keyed slash probe', 'Builtin-owned (lib/builtin/claude/) app-wide source of truth for Claude Code''s environment per D-76. Loads and layers GLOBAL (~/.claude) as base with LOCAL (.claude) overriding: skills (skills/*/SKILL.md frontmatter name+description), custom slash commands (commands/*.md), settings.json, and permission rules (allow/deny/ask). Built-in slash commands (not on disk) come from a one-shot ''claude --output-format stream-json'' probe, cached keyed on the resolved claude version id so additions/deprecations re-capture on upgrade; a small static list is the fallback. FileWatcher (lib/src/files/watcher.dart) on both .claude dirs plus an explicit refresh; expose typed, listenable views. No kernel changes — builtin-owned (Claude is a non-disableable extension, but still an extension). Acceptance: empirically confirm the stream-json init message carries slash_commands for the pinned CC version (spike folded in here) before consumers rely on it; unit tests with fixture global+local .claude dirs covering layering, watcher-driven refresh, probe cache keyed on version, and static fallback; degrades gracefully on parse miss; coverage >= floor. Blocks the typeahead, command-aware send, and status-pane wiring.', 'done', 'high', NULL, NULL, 'D-76', '2026-05-23 09:52:14', '2026-05-23 10:20:12', NULL, 'a76dde29c433ca59418be60bbd454a69', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM77GWREHKA9K45P020', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'ClaudeConfig service: layered config + skills/commands + version-keyed slash probe', 'Builtin-owned (lib/builtin/claude/) app-wide source of truth for Claude Code''s environment per D-76. Loads and layers GLOBAL (~/.claude) as base with LOCAL (.claude) overriding: skills (skills/*/SKILL.md frontmatter name+description), custom slash commands (commands/*.md), settings.json, and permission rules (allow/deny/ask). Built-in slash commands (not on disk) come from a one-shot ''claude --output-format stream-json'' probe, cached keyed on the resolved claude version id so additions/deprecations re-capture on upgrade; a small static list is the fallback. FileWatcher (lib/src/files/watcher.dart) on both .claude dirs plus an explicit refresh; expose typed, listenable views. No kernel changes — builtin-owned (Claude is a non-disableable extension, but still an extension). Acceptance: empirically confirm the stream-json init message carries slash_commands for the pinned CC version (spike folded in here) before consumers rely on it; unit tests with fixture global+local .claude dirs covering layering, watcher-driven refresh, probe cache keyed on version, and static fallback; degrades gracefully on parse miss; coverage >= floor. Blocks the typeahead, command-aware send, and status-pane wiring.', 'done', 'high', NULL, NULL, 'D-76', '2026-05-23 09:52:14', '2026-05-23 10:20:12', NULL, 'a76dde29c433ca59418be60bbd454a69', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7BJS5E1JJGSJ9XHG0', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Command-aware send: bypass bracketed-paste for valid slash commands', 'Fix the delivery mismatch where slash commands behave differently in clide than the CLI. tmux.sendMessage (lib/builtin/claude/src/tmux_session.dart) always uses paste-buffer -p (bracketed paste), and Claude''s TUI deliberately does not run slash-command parsing on bracketed-pasted content — so /cmd and /skill arrive as literal prompt text instead of invoking. Fix: when the submitted input is a valid slash command (per ClaudeConfig, T-151) — or single-line input generally — deliver it typed via tmux send-keys -l -- <text> then Enter, so the TUI parses it like the CLI; keep paste-buffer -p only for multi-line content (mirrors encodeClaudeInput''s existing single-vs-multiline logic on the PTY fallback path). Acceptance: a typed or typeahead-selected slash command actually invokes the skill/command in a real make-run session (parity with the CLI); multi-line messages still arrive as one block, not a stream of submits; unit tests on the send-encoding branches (single-line vs multi-line vs recognized-command); coverage >= floor. Blocked by T-151.', 'done', 'medium', NULL, NULL, 'D-76', '2026-05-23 09:52:27', '2026-05-23 10:35:56', NULL, 'aa6834831d4423fd3c0718d6b167da38', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7BJS5E1JJGSJ9XHG0', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Command-aware send: bypass bracketed-paste for valid slash commands', 'Fix the delivery mismatch where slash commands behave differently in clide than the CLI. tmux.sendMessage (lib/builtin/claude/src/tmux_session.dart) always uses paste-buffer -p (bracketed paste), and Claude''s TUI deliberately does not run slash-command parsing on bracketed-pasted content — so /cmd and /skill arrive as literal prompt text instead of invoking. Fix: when the submitted input is a valid slash command (per ClaudeConfig, T-151) — or single-line input generally — deliver it typed via tmux send-keys -l -- <text> then Enter, so the TUI parses it like the CLI; keep paste-buffer -p only for multi-line content (mirrors encodeClaudeInput''s existing single-vs-multiline logic on the PTY fallback path). Acceptance: a typed or typeahead-selected slash command actually invokes the skill/command in a real make-run session (parity with the CLI); multi-line messages still arrive as one block, not a stream of submits; unit tests on the send-encoding branches (single-line vs multi-line vs recognized-command); coverage >= floor. Blocked by T-151.', 'done', 'medium', NULL, NULL, 'D-76', '2026-05-23 09:52:27', '2026-05-23 10:35:56', NULL, 'aa6834831d4423fd3c0718d6b167da38', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6YSQYCE096R2SFRXG', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Composer slash-command typeahead (inline detection, CLI-style)', 'Make ClaudeComposer (lib/builtin/claude/src/claude_composer.dart) slash-aware. Detect a /token at the cursor ANYWHERE in the text — inline mid-sentence, not only at position 0 (user requirement) — and show a typeahead popup listing matching slash commands + skills sourced from ClaudeConfig (T-151), filtering as the token grows. Keyboard nav: Up/Down to move, Tab/Enter to complete, Esc to dismiss; reuse ClidePalette interaction patterns. Completing inserts the command token at the cursor. Never re-scans the filesystem — reads from ClaudeConfig and refreshes when it changes. Acceptance: typing / opens the list; an inline / after existing text also opens it; arrow/Tab/Enter/Esc behave; the list reflects ClaudeConfig (skills + custom commands + built-ins); widget tests; a11y (focusable, labelled, contrast). Blocked by T-151.', 'done', 'medium', NULL, NULL, 'D-76', '2026-05-23 09:52:20', '2026-05-23 10:43:52', NULL, '266c657f7d1be0299a20414bfad4ddab', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6YSQYCE096R2SFRXG', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Composer slash-command typeahead (inline detection, CLI-style)', 'Make ClaudeComposer (lib/builtin/claude/src/claude_composer.dart) slash-aware. Detect a /token at the cursor ANYWHERE in the text — inline mid-sentence, not only at position 0 (user requirement) — and show a typeahead popup listing matching slash commands + skills sourced from ClaudeConfig (T-151), filtering as the token grows. Keyboard nav: Up/Down to move, Tab/Enter to complete, Esc to dismiss; reuse ClidePalette interaction patterns. Completing inserts the command token at the cursor. Never re-scans the filesystem — reads from ClaudeConfig and refreshes when it changes. Acceptance: typing / opens the list; an inline / after existing text also opens it; arrow/Tab/Enter/Esc behave; the list reflects ClaudeConfig (skills + custom commands + built-ins); widget tests; a11y (focusable, labelled, contrast). Blocked by T-151.', 'done', 'medium', NULL, NULL, 'D-76', '2026-05-23 09:52:20', '2026-05-23 10:43:52', NULL, '266c657f7d1be0299a20414bfad4ddab', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5B47G9GG22N9KBNEG', 'bug', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Claude pane doesn''t follow session switches (/clear, /compact) — interaction wedges', 'Now that T-153 makes slash commands actually fire, session-mutating commands wedge the Claude pane. /clear makes Claude Code start a NEW session-id (a fresh <uuid>.jsonl). The composer''s keystrokes still reach the same tmux/claude process, but clide''s TranscriptReader is pinned to the spawn --session-id file (claude_pane binds the reader to a fixed transcriptFile; transcript_reader.dart has zero session-change handling). After /clear: the old transcript freezes, Claude writes to the new session file, and clide keeps tailing the dead file — no responses appear and the pane looks completely broken. Affects /clear and likely /compact, /resume, --fork-session.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5B47G9GG22N9KBNEG', 'bug', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Claude pane doesn''t follow session switches (/clear, /compact) — interaction wedges', 'Now that T-153 makes slash commands actually fire, session-mutating commands wedge the Claude pane. /clear makes Claude Code start a NEW session-id (a fresh <uuid>.jsonl). The composer''s keystrokes still reach the same tmux/claude process, but clide''s TranscriptReader is pinned to the spawn --session-id file (claude_pane binds the reader to a fixed transcriptFile; transcript_reader.dart has zero session-change handling). After /clear: the old transcript freezes, Claude writes to the new session file, and clide keeps tailing the dead file — no responses appear and the pane looks completely broken. Affects /clear and likely /compact, /resume, --fork-session.
|
||||||
|
|
||||||
Observed (2026-05-23): a new <uuid>.jsonl (8b21f12b…) appeared at 13:11 while the prior froze at 13:07, matching a /clear at that time. Pre-T-153 this was hidden because slash commands were pasted as literal text (no-op).
|
Observed (2026-05-23): a new <uuid>.jsonl (8b21f12b…) appeared at 13:11 while the prior froze at 13:07, matching a /clear at that time. Pre-T-153 this was hidden because slash commands were pasted as literal text (no-op).
|
||||||
@@ -916,14 +916,14 @@ Tension to respect: T-146 deliberately pinned each pane to its own --session-id
|
|||||||
|
|
||||||
Direction (needs a small decision/spike): detect when Claude switches the active session for a pane and re-bind the TranscriptReader to the new session-id without re-introducing the T-146 cross-pane bug — e.g. via the transcript''s session lineage (parentUuid/leaf, or a session-change marker), or by querying the active session for the pane''s tmux session. Near-term safety to weigh: detect session-mutating commands (/clear, /compact, /resume) and handle/warn rather than silently wedging. Immediate user workaround: restart clide (primary re-binds + --resume to the pre-clear session).
|
Direction (needs a small decision/spike): detect when Claude switches the active session for a pane and re-bind the TranscriptReader to the new session-id without re-introducing the T-146 cross-pane bug — e.g. via the transcript''s session lineage (parentUuid/leaf, or a session-change marker), or by querying the active session for the pane''s tmux session. Near-term safety to weigh: detect session-mutating commands (/clear, /compact, /resume) and handle/warn rather than silently wedging. Immediate user workaround: restart clide (primary re-binds + --resume to the pre-clear session).
|
||||||
|
|
||||||
Acceptance: after a /clear in a Claude pane, clide follows to the new session and continues to show prompts + responses; secondaries still bind only to their own session (T-146 not regressed); tests cover a simulated session switch re-binding the reader; coverage >= floor.', 'done', 'high', NULL, NULL, 'D-75', '2026-05-23 11:15:08', '2026-05-23 12:05:19', NULL, '75443abc3658418fb215098d1e12a2d3', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Acceptance: after a /clear in a Claude pane, clide follows to the new session and continues to show prompts + responses; secondaries still bind only to their own session (T-146 not regressed); tests cover a simulated session switch re-binding the reader; coverage >= floor.', 'done', 'high', NULL, NULL, 'D-75', '2026-05-23 11:15:08', '2026-05-23 12:05:19', NULL, '75443abc3658418fb215098d1e12a2d3', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5R9Q3T7CBMTHM2GFR', 'task', NULL, 'Finish i18n catalog plumbing: auto-load extension namespaces, kill ''namespace not registered'' warnings', 'Five builtins (tickets, decisions, git, pql, problems) declare titleKey: ''tab.title'' + i18nNamespace on their TabContribution but ship NO catalog file (lib/kernel/src/i18n/catalog/ has only the 8 tier-0 namespaces) and aren''t in the hand-maintained _tier0Namespaces preload list (lib/main.dart). Result: every boot logs ''i18n: namespace not registered: builtin.X (key: tab.title)'' for each. Tabs still render correctly via the placeholder fallback, so it''s cosmetic console noise — but it recurs for every new builtin because the preload list is maintained by hand.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5R9Q3T7CBMTHM2GFR', 'task', NULL, 'Finish i18n catalog plumbing: auto-load extension namespaces, kill ''namespace not registered'' warnings', 'Five builtins (tickets, decisions, git, pql, problems) declare titleKey: ''tab.title'' + i18nNamespace on their TabContribution but ship NO catalog file (lib/kernel/src/i18n/catalog/ has only the 8 tier-0 namespaces) and aren''t in the hand-maintained _tier0Namespaces preload list (lib/main.dart). Result: every boot logs ''i18n: namespace not registered: builtin.X (key: tab.title)'' for each. Tabs still render correctly via the placeholder fallback, so it''s cosmetic console noise — but it recurs for every new builtin because the preload list is maintained by hand.
|
||||||
|
|
||||||
Proper fix: when an extension activates, auto-load the i18nNamespace(s) declared by its contributions via i18n.ensureNamespaceLoaded — removing the manual _tier0Namespaces list and the drift it causes. AssetCatalogLoader.load returns empty for a missing file, so auto-preloading alone would just shift the warning to ''missing key tab.title'' — so the missing catalogs must also be created: builtin.{tickets,decisions,git,pql,problems}_en_us.json with at least tab.title plus any other keys those extensions look up.
|
Proper fix: when an extension activates, auto-load the i18nNamespace(s) declared by its contributions via i18n.ensureNamespaceLoaded — removing the manual _tier0Namespaces list and the drift it causes. AssetCatalogLoader.load returns empty for a missing file, so auto-preloading alone would just shift the warning to ''missing key tab.title'' — so the missing catalogs must also be created: builtin.{tickets,decisions,git,pql,problems}_en_us.json with at least tab.title plus any other keys those extensions look up.
|
||||||
|
|
||||||
Acceptance: clean boot with all builtins active logs zero i18n warnings; a new builtin that declares a titleKey gets its namespace loaded automatically with no manual list edit; the five catalog files exist; tests cover the auto-load-on-activate path and the missing-catalog case; coverage >= floor.', 'done', 'low', NULL, NULL, NULL, '2026-05-23 11:06:50', '2026-05-23 14:50:17', NULL, '0d925bbfd51d32f40da97318d3125428', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Acceptance: clean boot with all builtins active logs zero i18n warnings; a new builtin that declares a titleKey gets its namespace loaded automatically with no manual list edit; the five catalog files exist; tests cover the auto-load-on-activate path and the missing-catalog case; coverage >= floor.', 'done', 'low', NULL, NULL, NULL, '2026-05-23 11:06:50', '2026-05-23 14:50:17', NULL, '0d925bbfd51d32f40da97318d3125428', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4XM8EY708NAM1JK00', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Surface ClaudeConfig in the Claude status pane', 'The status surface shows LIVE model / permission-mode / context-tokens from the active transcript (T-145, T-150). Complement it with the CONFIGURED side from ClaudeConfig (T-151): available-skills count and/or configured permission/model defaults — static environment state alongside live session state. Reads from ClaudeConfig, not the filesystem; updates when config changes. Acceptance: the status surface reflects ClaudeConfig values, refreshes on config change, and keeps the live transcript-driven fields working; widget test; coverage >= floor. Blocked by T-151.', 'done', 'low', NULL, NULL, 'D-76', '2026-05-23 09:52:32', '2026-05-23 14:50:17', NULL, '57770b6e8e5b27a8f99c501892f8518a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4XM8EY708NAM1JK00', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Surface ClaudeConfig in the Claude status pane', 'The status surface shows LIVE model / permission-mode / context-tokens from the active transcript (T-145, T-150). Complement it with the CONFIGURED side from ClaudeConfig (T-151): available-skills count and/or configured permission/model defaults — static environment state alongside live session state. Reads from ClaudeConfig, not the filesystem; updates when config changes. Acceptance: the status surface reflects ClaudeConfig values, refreshes on config change, and keeps the live transcript-driven fields working; widget test; coverage >= floor. Blocked by T-151.', 'done', 'low', NULL, NULL, 'D-76', '2026-05-23 09:52:32', '2026-05-23 14:50:17', NULL, '57770b6e8e5b27a8f99c501892f8518a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6CYT7NW4WE8ZP1TXR', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Claude transcript disk-usage indicator + cleanup button', 'Surface transcript/session disk usage in the Claude panel with a cleanup affordance so the user can pick and choose what to remove. Per-session sizes (the <munged-cwd>/*.jsonl files + subagents/), a total, and a button to delete selected sessions'' transcripts. User-driven only — clide never auto-deletes transcript content. Future/''at some point'' per user. Relates to T-146 (session ids) and D-75.', 'done', 'low', NULL, NULL, NULL, '2026-05-23 07:03:18', '2026-05-23 15:05:29', NULL, '705f6fd98660484bc44f941fe453fc6a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6CYT7NW4WE8ZP1TXR', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Claude transcript disk-usage indicator + cleanup button', 'Surface transcript/session disk usage in the Claude panel with a cleanup affordance so the user can pick and choose what to remove. Per-session sizes (the <munged-cwd>/*.jsonl files + subagents/), a total, and a button to delete selected sessions'' transcripts. User-driven only — clide never auto-deletes transcript content. Future/''at some point'' per user. Relates to T-146 (session ids) and D-75.', 'done', 'low', NULL, NULL, NULL, '2026-05-23 07:03:18', '2026-05-23 15:05:29', NULL, '705f6fd98660484bc44f941fe453fc6a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5V9RNW2BGT5GHRTRG', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Team-meta sidebar (roster + token budget)', 'New sidebar panel (contributed to Slots.sidebar), visible only in team mode: a roster row per team member that MIRRORS the per-session status surfaced by T-145, plus team-wide meta.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5V9RNW2BGT5GHRTRG', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Team-meta sidebar (roster + token budget)', 'New sidebar panel (contributed to Slots.sidebar), visible only in team mode: a roster row per team member that MIRRORS the per-session status surfaced by T-145, plus team-wide meta.
|
||||||
|
|
||||||
Per-member row:
|
Per-member row:
|
||||||
@@ -935,9 +935,9 @@ Team-wide:
|
|||||||
- Team/account token budget pulled from the Anthropic usage API on a timer (distinct from per-conversation context above).
|
- Team/account token budget pulled from the Anthropic usage API on a timer (distinct from per-conversation context above).
|
||||||
|
|
||||||
Acceptance: roster matches list-panes/config; each row mirrors the member''s model + accept-edits/plan badge + context-usage; status verb and token deltas update live; account budget refreshes on its timer; panel appears only when a team is active. Depends on T-145 (status source) + T-139 (done).
|
Acceptance: roster matches list-panes/config; each row mirrors the member''s model + accept-edits/plan badge + context-usage; status verb and token deltas update live; account budget refreshes on its timer; panel appears only when a team is active. Depends on T-145 (status source) + T-139 (done).
|
||||||
', 'done', 'medium', NULL, NULL, NULL, '2026-05-22 15:59:34', '2026-05-23 20:49:44', NULL, '80f1fda6faec5f6aa86b6d212d2b5a8f', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
', 'done', 'medium', NULL, NULL, NULL, '2026-05-22 15:59:34', '2026-05-23 20:49:44', NULL, '80f1fda6faec5f6aa86b6d212d2b5a8f', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4QZ3JJF1704AV5JCW', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Team sidebar: live per-member status (mode + context)', 'Extend the Claude meta sidebar (T-141) roster rows with each teammate''s LIVE status — permission-mode badge (default/accept-edits/plan/bypass) and context-token usage — mirroring the per-session strip (T-145/T-150). The data exists: TeamObserver creates a TranscriptPublisher per teammate whose statusStream emits SessionStatus, but it is NEVER published to the MessageBus. Wire it: in team_observer _joined, subscribe to the publisher''s statusStream and publish {agentId, model, permissionMode, contextTokens} to a new ClaudeConversation.memberStatusChannel; cancel on _left. The sidebar subscribes to that channel and updates the matching roster row. Do NOT re-tail transcripts (D-75) — reuse the existing stream. Acceptance: a running team shows each member''s mode badge + context tokens, updating live; module is the single status-forwarding point; tests; coverage >= floor.', 'done', 'low', NULL, NULL, NULL, '2026-05-23 20:48:31', '2026-05-23 20:57:07', NULL, '7fb8f4a122c58cc57287ebf8fa36b141', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4QZ3JJF1704AV5JCW', 'task', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Team sidebar: live per-member status (mode + context)', 'Extend the Claude meta sidebar (T-141) roster rows with each teammate''s LIVE status — permission-mode badge (default/accept-edits/plan/bypass) and context-token usage — mirroring the per-session strip (T-145/T-150). The data exists: TeamObserver creates a TranscriptPublisher per teammate whose statusStream emits SessionStatus, but it is NEVER published to the MessageBus. Wire it: in team_observer _joined, subscribe to the publisher''s statusStream and publish {agentId, model, permissionMode, contextTokens} to a new ClaudeConversation.memberStatusChannel; cancel on _left. The sidebar subscribes to that channel and updates the matching roster row. Do NOT re-tail transcripts (D-75) — reuse the existing stream. Acceptance: a running team shows each member''s mode badge + context tokens, updating live; module is the single status-forwarding point; tests; coverage >= floor.', 'done', 'low', NULL, NULL, NULL, '2026-05-23 20:48:31', '2026-05-23 20:57:07', NULL, '7fb8f4a122c58cc57287ebf8fa36b141', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6KD2DKTGHC6CF1MJ4', 'bug', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'ClidePane convey notifies focus listeners during build (markNeedsBuild crash)', 'Found via make run (2026-05-24). ClidePane.didChangeDependencies/didUpdateWidget run during the build phase and call FocusTracker.setStatusWidget -> notifyListeners() synchronously, which rebuilds the focus-listening status-bar item (PaneContextStatusItem''s ListenableBuilder) mid-build -> ''setState()/markNeedsBuild() called during build'' (thrown repeatedly each frame). Introduced by T-150; the T-150 widget tests missed it because no focus listener was in their tree. Fix: ClidePane defers the convey to a post-frame callback when schedulerPhase == persistentCallbacks (mid-build), re-checking focus then; immediate otherwise. Regression test added with a PaneContextStatusItem in the tree while a ClidePane mounts focused.', 'done', 'high', NULL, NULL, NULL, '2026-05-24 08:53:13', '2026-05-24 08:54:30', NULL, '8e4e5178c3f40d111ee8e038cbc9e9f3', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6KD2DKTGHC6CF1MJ4', 'bug', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'ClidePane convey notifies focus listeners during build (markNeedsBuild crash)', 'Found via make run (2026-05-24). ClidePane.didChangeDependencies/didUpdateWidget run during the build phase and call FocusTracker.setStatusWidget -> notifyListeners() synchronously, which rebuilds the focus-listening status-bar item (PaneContextStatusItem''s ListenableBuilder) mid-build -> ''setState()/markNeedsBuild() called during build'' (thrown repeatedly each frame). Introduced by T-150; the T-150 widget tests missed it because no focus listener was in their tree. Fix: ClidePane defers the convey to a post-frame callback when schedulerPhase == persistentCallbacks (mid-build), re-checking focus then; immediate otherwise. Regression test added with a PaneContextStatusItem in the tree while a ClidePane mounts focused.', 'done', 'high', NULL, NULL, NULL, '2026-05-24 08:53:13', '2026-05-24 08:54:30', NULL, '8e4e5178c3f40d111ee8e038cbc9e9f3', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7SPRJZ519RZK1ZPAW', 'bug', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Typed input reaches no live Claude after respawn — pane renders transcript only', 'Observed via make run (2026-05-24). After using /clear and /resume (which appear to work), regular typed messages produce no response and never appear in the conversation stream.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7SPRJZ519RZK1ZPAW', 'bug', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Typed input reaches no live Claude after respawn — pane renders transcript only', 'Observed via make run (2026-05-24). After using /clear and /resume (which appear to work), regular typed messages produce no response and never appear in the conversation stream.
|
||||||
|
|
||||||
Diagnosis (live process inspection): the clide app (PID 77023) had ZERO child processes; ''tmux -L clide list-sessions'' reported ''no server running''. clide spawns pane processes (tmux client / claude) via posix_spawn as its own children, so no children + no -L clide server = NO live Claude backing the pane. The two stray ''claude'' procs were the user''s other sessions (an agent + a game-coding session), not clide''s. The conversation still renders because TranscriptReader tails the transcript FILE — so /clear and /resume only re-point the reader at a different file; there is no live session behind them.
|
Diagnosis (live process inspection): the clide app (PID 77023) had ZERO child processes; ''tmux -L clide list-sessions'' reported ''no server running''. clide spawns pane processes (tmux client / claude) via posix_spawn as its own children, so no children + no -L clide server = NO live Claude backing the pane. The two stray ''claude'' procs were the user''s other sessions (an agent + a game-coding session), not clide''s. The conversation still renders because TranscriptReader tails the transcript FILE — so /clear and /resume only re-point the reader at a different file; there is no live session behind them.
|
||||||
@@ -946,7 +946,7 @@ Leading hypothesis: T-156''s _respawnWithSession (/clear, /resume) kills the tmu
|
|||||||
|
|
||||||
To localise: does a BRAND-NEW Claude tab (fresh spawn, no respawn) accept input and respond? If yes, the respawn path is the culprit; if no, the spawn path itself regressed. Also check the make-run console for pane.spawn errors / ''session exited''.
|
To localise: does a BRAND-NEW Claude tab (fresh spawn, no respawn) accept input and respond? If yes, the respawn path is the culprit; if no, the spawn path itself regressed. Also check the make-run console for pane.spawn errors / ''session exited''.
|
||||||
|
|
||||||
Acceptance: after /clear and /resume, a live tmux session (or no-tmux PTY) exists and typed input reaches Claude and streams a response; clide''s _usingTmux/_paneId/_sessionName stay consistent with the actual spawned process; regression test or a documented manual verification. Relates to T-156, T-147 (self-heal), D-41.', 'done', 'high', NULL, NULL, NULL, '2026-05-24 09:24:02', '2026-05-24 09:45:07', NULL, '5955ed0881de7620205a7b8a2a5721eb', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Acceptance: after /clear and /resume, a live tmux session (or no-tmux PTY) exists and typed input reaches Claude and streams a response; clide''s _usingTmux/_paneId/_sessionName stay consistent with the actual spawned process; regression test or a documented manual verification. Relates to T-156, T-147 (self-heal), D-41.', 'done', 'high', NULL, NULL, NULL, '2026-05-24 09:24:02', '2026-05-24 09:45:07', NULL, '5955ed0881de7620205a7b8a2a5721eb', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5932T486Z1F1M6X6W', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'Conversation message-card primitive: hover copy + collapse/expand, extensible base', 'Replace the three ad-hoc card shapes in conversation_view.dart (_messageCard stripe / _labelled / _card bordered) with ONE base primitive every turn renders through, with hover affordances wired into the base so all message types (now + future) get them consistently.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5932T486Z1F1M6X6W', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'Conversation message-card primitive: hover copy + collapse/expand, extensible base', 'Replace the three ad-hoc card shapes in conversation_view.dart (_messageCard stripe / _labelled / _card bordered) with ONE base primitive every turn renders through, with hover affordances wired into the base so all message types (now + future) get them consistently.
|
||||||
|
|
||||||
PRIMITIVE — ConversationCard (lib/builtin/claude/src/conversation_card.dart):
|
PRIMITIVE — ConversationCard (lib/builtin/claude/src/conversation_card.dart):
|
||||||
@@ -962,16 +962,16 @@ FUTURE-PROOFING (the point):
|
|||||||
|
|
||||||
MIGRATION: route the existing switch in _ConversationTurn through the primitive; the three shapes become variants. Lands independently of the stream-json transport (works on the current conversation_view) but is the base T-168 builds on.
|
MIGRATION: route the existing switch in _ConversationTurn through the primitive; the three shapes become variants. Lands independently of the stream-json transport (works on the current conversation_view) but is the base T-168 builds on.
|
||||||
|
|
||||||
Acceptance: every turn type renders through the one primitive; hover-copy yields the right raw text per type; collapsible types expand/collapse (tool-result/thinking default-collapsed); actions are keyboard-focusable + Semantics-labelled (a11y); widget tests for copy, collapse, each variant, and an injected custom action; coverage >= floor. Feeds T-168.', 'done', 'medium', NULL, NULL, 'D-77', '2026-05-24 16:45:40', '2026-05-24 17:10:07', NULL, '551b0d25926bf71997a92a70ab3516ef', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Acceptance: every turn type renders through the one primitive; hover-copy yields the right raw text per type; collapsible types expand/collapse (tool-result/thinking default-collapsed); actions are keyboard-focusable + Semantics-labelled (a11y); widget tests for copy, collapse, each variant, and an injected custom action; coverage >= floor. Feeds T-168.', 'done', 'medium', NULL, NULL, 'D-77', '2026-05-24 16:45:40', '2026-05-24 17:10:07', NULL, '551b0d25926bf71997a92a70ab3516ef', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4AHSN3BXZFFWS0EPM', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'P1: stream-json transport — drive the Claude pane via the control protocol', 'Spawn the Claude pane as ''claude --input-format stream-json --output-format stream-json --verbose'' (+ --include-partial-messages later) instead of an interactive TUI in tmux. Multiplex its stdin/stdout; parse the event stream (system/init, assistant, tool_use, tool_result, result, rate_limit_event); feed the existing ConversationController/MessageBus from events rather than tailing the transcript JSONL. Isolate the protocol behind one module (the drift-containment point, like the transcript reader). Acceptance: a Claude pane converses end-to-end over stream-json (send a prompt, stream the reply) with no tmux session; events drive the native conversation view; unit tests against canned event fixtures. Blocks the rest of phase 1. Evolves D-75 (rendering now sourced from events).', 'done', 'high', NULL, NULL, 'D-77', '2026-05-24 16:26:15', '2026-05-25 06:29:25', NULL, '34c4aab735c6b8d761cf79683110fd37', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4AHSN3BXZFFWS0EPM', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'P1: stream-json transport — drive the Claude pane via the control protocol', 'Spawn the Claude pane as ''claude --input-format stream-json --output-format stream-json --verbose'' (+ --include-partial-messages later) instead of an interactive TUI in tmux. Multiplex its stdin/stdout; parse the event stream (system/init, assistant, tool_use, tool_result, result, rate_limit_event); feed the existing ConversationController/MessageBus from events rather than tailing the transcript JSONL. Isolate the protocol behind one module (the drift-containment point, like the transcript reader). Acceptance: a Claude pane converses end-to-end over stream-json (send a prompt, stream the reply) with no tmux session; events drive the native conversation view; unit tests against canned event fixtures. Blocks the rest of phase 1. Evolves D-75 (rendering now sourced from events).', 'done', 'high', NULL, NULL, 'D-77', '2026-05-24 16:26:15', '2026-05-25 06:29:25', NULL, '34c4aab735c6b8d761cf79683110fd37', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7KA37YDBJ89GJ27H4', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'P1: native permission + AskUserQuestion prompts via canUseTool', 'Handle interactive prompts that the TUI model couldn''t surface. Wire Claude''s permission requests and the AskUserQuestion tool through the control mechanism (--permission-prompt-tool / SDK-style canUseTool: toolName + input, return allow/deny or the chosen answers). Render NATIVE prompt cards in the Claude pane — allow/deny for permissions, an option picker (matching AskUserQuestion''s questions/options) for AskUserQuestion — and return the user''s choice over the protocol. Acceptance: asking Claude for an AskUserQuestion shows selectable options inline and the selection is delivered; a tool needing permission shows allow/deny and the decision flows back; widget tests for the prompt cards + a fake control channel. Closes the prompt gap that motivated D-77. Blocked by T-165.', 'done', 'high', NULL, NULL, 'D-77', '2026-05-24 16:26:23', '2026-05-25 06:31:08', NULL, 'a85bf25a70c97c958f65b1fba8c258c8', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7KA37YDBJ89GJ27H4', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'P1: native permission + AskUserQuestion prompts via canUseTool', 'Handle interactive prompts that the TUI model couldn''t surface. Wire Claude''s permission requests and the AskUserQuestion tool through the control mechanism (--permission-prompt-tool / SDK-style canUseTool: toolName + input, return allow/deny or the chosen answers). Render NATIVE prompt cards in the Claude pane — allow/deny for permissions, an option picker (matching AskUserQuestion''s questions/options) for AskUserQuestion — and return the user''s choice over the protocol. Acceptance: asking Claude for an AskUserQuestion shows selectable options inline and the selection is delivered; a tool needing permission shows allow/deny and the decision flows back; widget tests for the prompt cards + a fake control channel. Closes the prompt gap that motivated D-77. Blocked by T-165.', 'done', 'high', NULL, NULL, 'D-77', '2026-05-24 16:26:23', '2026-05-25 06:31:08', NULL, 'a85bf25a70c97c958f65b1fba8c258c8', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6RP0Q312AZJ8S1Y6R', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'Conversation cards: collapse tool_use/tool_result only when multi-line', 'tool_use and tool_result conversation cards start collapsed ONLY when their body is multi-line; single-line bodies render inline (collapse bulk, not chrome - if it fits on one line, just show it). Collapsed header shows a one-line summary (tool_use: tool + key arg, e.g. Write /tmp/x; tool_result: first line or byte size). thinking already collapses; user/assistant text stay expanded. Acceptance: a one-line result renders inline with no caret; a multi-line result starts collapsed with a summary header; widget tests. Relates to T-173 (ConversationCard primitive).', 'done', 'medium', NULL, NULL, 'D-78', '2026-05-25 07:11:22', '2026-05-25 07:25:02', NULL, '7f1cab9ef21c3686c0de7ada8383c104', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6RP0Q312AZJ8S1Y6R', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'Conversation cards: collapse tool_use/tool_result only when multi-line', 'tool_use and tool_result conversation cards start collapsed ONLY when their body is multi-line; single-line bodies render inline (collapse bulk, not chrome - if it fits on one line, just show it). Collapsed header shows a one-line summary (tool_use: tool + key arg, e.g. Write /tmp/x; tool_result: first line or byte size). thinking already collapses; user/assistant text stay expanded. Acceptance: a one-line result renders inline with no caret; a multi-line result starts collapsed with a summary header; widget tests. Relates to T-173 (ConversationCard primitive).', 'done', 'medium', NULL, NULL, 'D-78', '2026-05-25 07:11:22', '2026-05-25 07:25:02', NULL, '7f1cab9ef21c3686c0de7ada8383c104', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7K30Y9WAYZ3D330YR', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'Permission prompt: Allow / Allow-and-remember / Deny+note', 'Bottom-zone permission card (prompt_card.dart): replace binary Allow/Deny with three options. (1) Allow -> allow{updatedInput}. (2) Allow and do not ask again -> shown only when the can_use_tool request carries a permission_suggestions entry (session/localSettings destination); returns allow{updatedInput, updatedPermissions:[suggestion]}. AllowTool gains an optional updatedPermissions field; ToolPrompt + StreamJsonSession carry the request permission_suggestions through. (3) Deny -> reveals an optional note field -> deny{message}. Plus allow-with-note: clide sends the typed note as a follow-up user message right after allowing (protocol has no allow-with-message per D-78; closest faithful approximation). Acceptance: three options render (option 2 only when a suggestion exists); allow / deny / updatedPermissions / deny-note all flow over the control channel; allow+note sends a follow-up; widget + transport tests. Wireframe: docs/design/wireframes/claude-prompts/04-permission.png', 'done', 'high', NULL, NULL, 'D-78', '2026-05-25 07:11:09', '2026-05-25 07:25:02', NULL, '8815658122b516758d178eb83384a179', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7K30Y9WAYZ3D330YR', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'Permission prompt: Allow / Allow-and-remember / Deny+note', 'Bottom-zone permission card (prompt_card.dart): replace binary Allow/Deny with three options. (1) Allow -> allow{updatedInput}. (2) Allow and do not ask again -> shown only when the can_use_tool request carries a permission_suggestions entry (session/localSettings destination); returns allow{updatedInput, updatedPermissions:[suggestion]}. AllowTool gains an optional updatedPermissions field; ToolPrompt + StreamJsonSession carry the request permission_suggestions through. (3) Deny -> reveals an optional note field -> deny{message}. Plus allow-with-note: clide sends the typed note as a follow-up user message right after allowing (protocol has no allow-with-message per D-78; closest faithful approximation). Acceptance: three options render (option 2 only when a suggestion exists); allow / deny / updatedPermissions / deny-note all flow over the control channel; allow+note sends a follow-up; widget + transport tests. Wireframe: docs/design/wireframes/claude-prompts/04-permission.png', 'done', 'high', NULL, NULL, 'D-78', '2026-05-25 07:11:09', '2026-05-25 07:25:02', NULL, '8815658122b516758d178eb83384a179', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7AXEWDKD4VQNQCACM', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'AskUserQuestion native picker: stepper + review, Other, per-choice note', 'Overhaul the AskUserQuestion bottom-zone card (prompt_card.dart). Single question -> no stepper, bare question + options. Multiple (2-4) -> stepper: top nav showing "N - Header" per step (check on answered, box on current) + prev/next arrows, one question at a time with Back/Next, then a Review screen (question -> answer, Back / Submit answers). Each question: numbered option buttons (1-4) + an Other choice that reveals a free-text field (typed text becomes the answer value, not the word Other) + a +note affordance on a picked option (answer becomes Label - note). multiSelect toggles and comma-joins labels. A chat-instead escape denies the prompt (message: user chose to chat instead) and refocuses the composer. On submit -> allow{updatedInput:{questions, answers}} -> card closes -> clide appends a compact answered echo item to the conversation log. Acceptance: single vs multi layouts; Other + note produce correct answer strings; review step; chat-instead denies + refocuses; widget tests. Wireframes: docs/design/wireframes/claude-prompts/ (01 single, 02 stepper, 03 review).', 'done', 'high', NULL, NULL, 'D-78', '2026-05-25 07:11:16', '2026-05-25 07:27:57', NULL, '63d4bf37ad7c9d165089b11fbdc210e8', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7AXEWDKD4VQNQCACM', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'AskUserQuestion native picker: stepper + review, Other, per-choice note', 'Overhaul the AskUserQuestion bottom-zone card (prompt_card.dart). Single question -> no stepper, bare question + options. Multiple (2-4) -> stepper: top nav showing "N - Header" per step (check on answered, box on current) + prev/next arrows, one question at a time with Back/Next, then a Review screen (question -> answer, Back / Submit answers). Each question: numbered option buttons (1-4) + an Other choice that reveals a free-text field (typed text becomes the answer value, not the word Other) + a +note affordance on a picked option (answer becomes Label - note). multiSelect toggles and comma-joins labels. A chat-instead escape denies the prompt (message: user chose to chat instead) and refocuses the composer. On submit -> allow{updatedInput:{questions, answers}} -> card closes -> clide appends a compact answered echo item to the conversation log. Acceptance: single vs multi layouts; Other + note produce correct answer strings; review step; chat-instead denies + refocuses; widget tests. Wireframes: docs/design/wireframes/claude-prompts/ (01 single, 02 stepper, 03 review).', 'done', 'high', NULL, NULL, 'D-78', '2026-05-25 07:11:16', '2026-05-25 07:27:57', NULL, '63d4bf37ad7c9d165089b11fbdc210e8', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4VNVEAEYBX3S9Z8Q8', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'De-emphasize harness-injected user messages (skill/command injects)', 'When a skill or slash-command is invoked, Claude injects its content as a user-role message (e.g. skill text begins "Base directory for this skill:", commands wrap content in <command-name>/<command-message>/<command-args>, system reminders in <system-reminder>). These are NOT typed by the user but render as a normal blue "you" card. Detect injected user messages (content markers; also isMeta when present) and render them de-emphasized: a collapsed, muted "context" card (bare variant), NOT the blue "you" accent. UserMessage gains an injected flag set in parseTranscriptChunk; conversation_view renders injected user messages collapsed/muted. Acceptance: a skill-inject user message renders collapsed + muted + not labelled "you"; a normal typed message still renders as "you"; widget + parser tests.', 'done', 'medium', NULL, NULL, 'D-78', '2026-05-25 08:10:10', '2026-05-25 08:21:46', NULL, 'bbc992a36a3daa1109c920a15f3e2c67', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4VNVEAEYBX3S9Z8Q8', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'De-emphasize harness-injected user messages (skill/command injects)', 'When a skill or slash-command is invoked, Claude injects its content as a user-role message (e.g. skill text begins "Base directory for this skill:", commands wrap content in <command-name>/<command-message>/<command-args>, system reminders in <system-reminder>). These are NOT typed by the user but render as a normal blue "you" card. Detect injected user messages (content markers; also isMeta when present) and render them de-emphasized: a collapsed, muted "context" card (bare variant), NOT the blue "you" accent. UserMessage gains an injected flag set in parseTranscriptChunk; conversation_view renders injected user messages collapsed/muted. Acceptance: a skill-inject user message renders collapsed + muted + not labelled "you"; a normal typed message still renders as "you"; widget + parser tests.', 'done', 'medium', NULL, NULL, 'D-78', '2026-05-25 08:10:10', '2026-05-25 08:21:46', NULL, 'bbc992a36a3daa1109c920a15f3e2c67', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4DTGYPAB29MRDN000', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'Permission prompt shows the command; resolved tool-use collapses with green/red border', 'Two parts. (1) The permission prompt UI must show what is being permitted: render the tool input (e.g. the Bash command / Write content) in the prompt card as a collapsible, trimmed code block, so the user can see what they approve. (2) Replace the current full-hide of a permission-prompted tool-use card: while the prompt is open, keep the payload in the prompt (hidden from the log); after resolution, show a COLLAPSED one-line summary in the log with a green border when approved and a red border when denied. Requires the session to track per-tool_use_id outcome (pending/allow/deny) and expose it; the conversation view renders prompted tool-use cards collapsed + colour-bordered by outcome (and keeps the result). Acceptance: prompt shows the command (collapsible); after allow the tool-use shows collapsed with a green border, after deny a red border; widget tests.', 'done', 'medium', NULL, NULL, 'D-78', '2026-05-25 08:10:18', '2026-05-25 08:26:21', NULL, '6f23be887ee48cc2272301e79c386c72', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4DTGYPAB29MRDN000', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'Permission prompt shows the command; resolved tool-use collapses with green/red border', 'Two parts. (1) The permission prompt UI must show what is being permitted: render the tool input (e.g. the Bash command / Write content) in the prompt card as a collapsible, trimmed code block, so the user can see what they approve. (2) Replace the current full-hide of a permission-prompted tool-use card: while the prompt is open, keep the payload in the prompt (hidden from the log); after resolution, show a COLLAPSED one-line summary in the log with a green border when approved and a red border when denied. Requires the session to track per-tool_use_id outcome (pending/allow/deny) and expose it; the conversation view renders prompted tool-use cards collapsed + colour-bordered by outcome (and keeps the result). Acceptance: prompt shows the command (collapsible); after allow the tool-use shows collapsed with a green border, after deny a red border; widget tests.', 'done', 'medium', NULL, NULL, 'D-78', '2026-05-25 08:10:18', '2026-05-25 08:26:21', NULL, '6f23be887ee48cc2272301e79c386c72', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM48P8T23ZPR0BRK6PR', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'P2: session orchestrator — one managed-session primitive (spawn/show/hide)', 'Generalize the Claude pane into a clide-managed SESSION primitive: clide spawns/owns each stream-json Claude process; a pane is just a view on a session; teammate / secondary tab / forked branch / inline subagent are all the same thing. Provide spawn / show / hide / close over the set of live sessions; visibility is a UI toggle, not a lifecycle change (sessions stay live when hidden). Re-point the T-139 TeamObserver from observing a Claude tmux team to ORCHESTRATING clide-managed sessions; the T-140 tiles render whatever sessions are shown. Acceptance: multiple managed sessions run concurrently; each can be shown/hidden as a pane from a roster without tearing down its process; tests for the orchestrator lifecycle. Blocked by T-165 (phase 1 transport).', 'done', 'medium', NULL, NULL, 'D-77', '2026-05-24 16:26:49', '2026-05-25 12:12:29', NULL, '4be6357fef2273610e8ca601b4f4116e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM48P8T23ZPR0BRK6PR', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'P2: session orchestrator — one managed-session primitive (spawn/show/hide)', 'Generalize the Claude pane into a clide-managed SESSION primitive: clide spawns/owns each stream-json Claude process; a pane is just a view on a session; teammate / secondary tab / forked branch / inline subagent are all the same thing. Provide spawn / show / hide / close over the set of live sessions; visibility is a UI toggle, not a lifecycle change (sessions stay live when hidden). Re-point the T-139 TeamObserver from observing a Claude tmux team to ORCHESTRATING clide-managed sessions; the T-140 tiles render whatever sessions are shown. Acceptance: multiple managed sessions run concurrently; each can be shown/hidden as a pane from a roster without tearing down its process; tests for the orchestrator lifecycle. Blocked by T-165 (phase 1 transport).', 'done', 'medium', NULL, NULL, 'D-77', '2026-05-24 16:26:49', '2026-05-25 12:12:29', NULL, '4be6357fef2273610e8ca601b4f4116e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM654XV2TG4K0RVV1CW', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'P2: clide-hosted MCP coordination broker + team-awareness injection', 'Give clide-managed sessions team behavior that Claude''s tmux mode provided (and that is undocumented + headless-unavailable). clide hosts a small MCP server (attached to each agent via --mcp-config) exposing team tools: send_message(to,text), broadcast(text), list_teammates(), inbox(), and a shared claim_task/task_status. clide is the BROKER — a tool call from agent A is delivered into agent B''s next turn on B''s stream-json stdin; clide owns routing/ordering. Inject team-awareness into each agent via --append-system-prompt (roster + role) and/or --agents. Acceptance: two managed agents exchange messages through the broker and see a shared task list; a lead can address one teammate by name; tests for the broker routing + the MCP tool surface. Blocked by T-169.', 'done', 'medium', NULL, NULL, 'D-77', '2026-05-24 16:27:01', '2026-05-25 19:38:16', NULL, '2c6b2f64ed0a270fc421c85bc2be8a1d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM654XV2TG4K0RVV1CW', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'P2: clide-hosted MCP coordination broker + team-awareness injection', 'Give clide-managed sessions team behavior that Claude''s tmux mode provided (and that is undocumented + headless-unavailable). clide hosts a small MCP server (attached to each agent via --mcp-config) exposing team tools: send_message(to,text), broadcast(text), list_teammates(), inbox(), and a shared claim_task/task_status. clide is the BROKER — a tool call from agent A is delivered into agent B''s next turn on B''s stream-json stdin; clide owns routing/ordering. Inject team-awareness into each agent via --append-system-prompt (roster + role) and/or --agents. Acceptance: two managed agents exchange messages through the broker and see a shared task list; a lead can address one teammate by name; tests for the broker routing + the MCP tool surface. Blocked by T-169.', 'done', 'medium', NULL, NULL, 'D-77', '2026-05-24 16:27:01', '2026-05-25 19:38:16', NULL, '2c6b2f64ed0a270fc421c85bc2be8a1d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4R8YY69YAARCVE4AC', 'bug', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Status bar overflows instead of marquee-scrolling the in-pane slot', 'Observed via make run (2026-05-24): the bottom status bar shows a RenderFlex ''overflowed by 77 PIXELS'' stripe after the in-pane context line (opus 4.7 · default · 21k ctx · 10 skills); the ClideMarquee never engages.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4R8YY69YAARCVE4AC', 'bug', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Status bar overflows instead of marquee-scrolling the in-pane slot', 'Observed via make run (2026-05-24): the bottom status bar shows a RenderFlex ''overflowed by 77 PIXELS'' stripe after the in-pane context line (opus 4.7 · default · 21k ctx · 10 skills); the ClideMarquee never engages.
|
||||||
|
|
||||||
Cause: StatusbarHost (lib/app.dart ~1143) lays items in a Row [left items..., Spacer(), right items...], each at INTRINSIC width with no Flexible. PaneContextStatusItem wraps its text in ConstrainedBox(maxWidth:360) + ClideMarquee, but because the text (~280px) is under 360 the slot takes content width, so the marquee''s viewport == its content and it never scrolls. T-154 appended ''· N skills'', lengthening the line enough that git-branch + context slot + right items exceed the bar width -> the Row overflows (~77px) instead of the slot shrinking + marquee scrolling.
|
Cause: StatusbarHost (lib/app.dart ~1143) lays items in a Row [left items..., Spacer(), right items...], each at INTRINSIC width with no Flexible. PaneContextStatusItem wraps its text in ConstrainedBox(maxWidth:360) + ClideMarquee, but because the text (~280px) is under 360 the slot takes content width, so the marquee''s viewport == its content and it never scrolls. T-154 appended ''· N skills'', lengthening the line enough that git-branch + context slot + right items exceed the bar width -> the Row overflows (~77px) instead of the slot shrinking + marquee scrolling.
|
||||||
@@ -979,8 +979,8 @@ Cause: StatusbarHost (lib/app.dart ~1143) lays items in a Row [left items..., Sp
|
|||||||
Fix direction: give the in-pane context slot a flexible/bounded width in the status bar (e.g. wrap it in Flexible(fit: loose), or have the bar allot it a shrinkable share) so it yields width when the bar is tight and ClideMarquee scrolls within the allotted width. Verify the interaction with the Spacer and the right-aligned items (priority>=100), and reconsider the fixed maxWidth:360. Acceptance: at narrow widths the in-pane slot marquee-scrolls and the status bar never shows an overflow stripe; widget test at a constrained width. Introduced by T-150 (marquee) + T-154 (longer line).
|
Fix direction: give the in-pane context slot a flexible/bounded width in the status bar (e.g. wrap it in Flexible(fit: loose), or have the bar allot it a shrinkable share) so it yields width when the bar is tight and ClideMarquee scrolls within the allotted width. Verify the interaction with the Spacer and the right-aligned items (priority>=100), and reconsider the fixed maxWidth:360. Acceptance: at narrow widths the in-pane slot marquee-scrolls and the status bar never shows an overflow stripe; widget test at a constrained width. Introduced by T-150 (marquee) + T-154 (longer line).
|
||||||
|
|
||||||
---
|
---
|
||||||
Refinement (2026-05-30, /whats-next): pulled into the T-167/T-168 batch and sequenced FIRST. T-168 adds live cost / permission-mode / context / rate-limit to this same in-pane status slot; the Flexible/marquee fix here must land before T-168 lengthens the line. After this fix, T-168 can safely add fields to the slot.', 'done', 'medium', NULL, NULL, NULL, '2026-05-24 09:13:42', '2026-05-30 11:05:56', NULL, '5a35baef15f92d9e04731cd307b5365e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Refinement (2026-05-30, /whats-next): pulled into the T-167/T-168 batch and sequenced FIRST. T-168 adds live cost / permission-mode / context / rate-limit to this same in-pane status slot; the Flexible/marquee fix here must land before T-168 lengthens the line. After this fix, T-168 can safely add fields to the slot.', 'done', 'medium', NULL, NULL, NULL, '2026-05-24 09:13:42', '2026-05-30 11:05:56', NULL, '5a35baef15f92d9e04731cd307b5365e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7G7MK8MP3BGQC36HG', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'P1: session persistence + /clear + /resume on stream-json (--resume)', 'Move session lifecycle onto the stream-json model. New session: --session-id <uuid>; resume an existing one: --resume <id> (T-161 confirmed --session-id refuses an existing id). Re-implement the clide-owned commands on this model: /clear = new fresh session, /resume = picker then resume the picked id. Retire the tmux session lifecycle for Claude (kill/hasSession/reap, new-session -A) and the --session-id-in-use handling once the transport no longer uses tmux. Acceptance: restart resumes the primary''s session; /clear starts empty; /resume switches to a picked session; all without tmux; tests for the new/resume argv selection and the command flows. Supersedes the mechanics of T-156/T-161. Blocked by T-165. Amends D-41 (tmux persistence → --resume).', 'done', 'high', NULL, NULL, 'D-77', '2026-05-24 16:26:30', '2026-05-30 11:05:56', NULL, 'af6188c78b5ff7df9e797dd4d7af0f7c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7G7MK8MP3BGQC36HG', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'P1: session persistence + /clear + /resume on stream-json (--resume)', 'Move session lifecycle onto the stream-json model. New session: --session-id <uuid>; resume an existing one: --resume <id> (T-161 confirmed --session-id refuses an existing id). Re-implement the clide-owned commands on this model: /clear = new fresh session, /resume = picker then resume the picked id. Retire the tmux session lifecycle for Claude (kill/hasSession/reap, new-session -A) and the --session-id-in-use handling once the transport no longer uses tmux. Acceptance: restart resumes the primary''s session; /clear starts empty; /resume switches to a picked session; all without tmux; tests for the new/resume argv selection and the command flows. Supersedes the mechanics of T-156/T-161. Blocked by T-165. Amends D-41 (tmux persistence → --resume).', 'done', 'high', NULL, NULL, 'D-77', '2026-05-24 16:26:30', '2026-05-30 11:05:56', NULL, 'af6188c78b5ff7df9e797dd4d7af0f7c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM78W48QX3JZP0QYAVW', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'P1: native rendering leveled up — typed event cards + streaming + live status', 'Exploit the structured stream the transcript-tail never cleanly gave. Per-tool cards from tool_use input (Edit/Write → diff, Bash → command+output, Read/Grep → file/query); pair each tool_result to its tool_use (with is_error) so diffs/failures render in place; stream assistant text + thinking blocks token-by-token via --include-partial-messages; surface live model / permission-mode / context-tokens / cost and rate_limit_event straight off the init + result events (retires the ClaudeConfig probe + status-bar guessing for the active pane); render structured errors as events. Acceptance: a session with edits/bash/reads shows the right card per tool with paired results; replies stream; the status line reflects live model/mode/context/cost from events; widget + fixture tests. Blocked by T-165.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM78W48QX3JZP0QYAVW', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'P1: native rendering leveled up — typed event cards + streaming + live status', 'Exploit the structured stream the transcript-tail never cleanly gave. Per-tool cards from tool_use input (Edit/Write → diff, Bash → command+output, Read/Grep → file/query); pair each tool_result to its tool_use (with is_error) so diffs/failures render in place; stream assistant text + thinking blocks token-by-token via --include-partial-messages; surface live model / permission-mode / context-tokens / cost and rate_limit_event straight off the init + result events (retires the ClaudeConfig probe + status-bar guessing for the active pane); render structured errors as events. Acceptance: a session with edits/bash/reads shows the right card per tool with paired results; replies stream; the status line reflects live model/mode/context/cost from events; widget + fixture tests. Blocked by T-165.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -998,21 +998,21 @@ Refinement (2026-05-30, /whats-next) — five seam decisions resolved:
|
|||||||
|
|
||||||
Files an implementer touches: conversation_view.dart, conversation_controller.dart, transcript_reader.dart, stream_json_session.dart, claude_pane.dart, plus test/builtin/claude/*. Commit the in-flight prompt_card.dart change first (disjoint surface — permission-card Write-description dedup).
|
Files an implementer touches: conversation_view.dart, conversation_controller.dart, transcript_reader.dart, stream_json_session.dart, claude_pane.dart, plus test/builtin/claude/*. Commit the in-flight prompt_card.dart change first (disjoint surface — permission-card Write-description dedup).
|
||||||
|
|
||||||
Sequencing within the batch: T-160 → T-168.', 'done', 'medium', NULL, NULL, 'D-77', '2026-05-24 16:26:39', '2026-05-30 11:44:28', NULL, '08c65c3f0a3b1642252fb715f1d7f4e0', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Sequencing within the batch: T-160 → T-168.', 'done', 'medium', NULL, NULL, 'D-77', '2026-05-24 16:26:39', '2026-05-30 11:44:28', NULL, '08c65c3f0a3b1642252fb715f1d7f4e0', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7ZB63YYNFXM9DQNRR', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'ConversationCard actions: keyboard-focusable + always-reachable (not hover-only)', 'Follow-up split out of T-173. The ConversationCard action bar (copy button + custom MessageActions) currently renders only while the card is hovered (lib/builtin/claude/src/conversation_card.dart, _header: ''if (_hover) ..._actions''). The collapse/expand caret is always visible, but the action buttons are not keyboard/AT reachable when not hovering.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7ZB63YYNFXM9DQNRR', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'ConversationCard actions: keyboard-focusable + always-reachable (not hover-only)', 'Follow-up split out of T-173. The ConversationCard action bar (copy button + custom MessageActions) currently renders only while the card is hovered (lib/builtin/claude/src/conversation_card.dart, _header: ''if (_hover) ..._actions''). The collapse/expand caret is always visible, but the action buttons are not keyboard/AT reachable when not hovering.
|
||||||
|
|
||||||
Make the actions always reachable per T-173''s acceptance: keep them in the tree always (reveal visually on hover OR focus via opacity), add Semantics onTap so assistive tech can activate them, and wire keyboard focus traversal + Enter/Space activation through clide''s keyboard-operability framework (the _tap helper uses a bare GestureDetector today, which is mouse/AT-tap only, not focus-traversable). Applies to both the action buttons and the caret.
|
Make the actions always reachable per T-173''s acceptance: keep them in the tree always (reveal visually on hover OR focus via opacity), add Semantics onTap so assistive tech can activate them, and wire keyboard focus traversal + Enter/Space activation through clide''s keyboard-operability framework (the _tap helper uses a bare GestureDetector today, which is mouse/AT-tap only, not focus-traversable). Applies to both the action buttons and the caret.
|
||||||
|
|
||||||
Acceptance: copy + custom actions are reachable and activatable by keyboard alone (Tab to focus, Enter/Space to invoke) with no mouse; Semantics button labels present; widget test drives a copy via focus+activation (no hover); a11y gate green.', 'done', 'medium', NULL, NULL, 'D-77', '2026-05-24 17:11:17', '2026-05-30 21:11:26', NULL, '7fab4b20b3a0970593130b0f110ce80d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Acceptance: copy + custom actions are reachable and activatable by keyboard alone (Tab to focus, Enter/Space to invoke) with no mouse; Semantics button labels present; widget test drives a copy via focus+activation (no hover); a11y gate green.', 'done', 'medium', NULL, NULL, 'D-77', '2026-05-24 17:11:17', '2026-05-30 21:11:26', NULL, '7fab4b20b3a0970593130b0f110ce80d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6FMAHXM1XAHHCQC60', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'P2: sidebar cockpit — task list + messages + roster controls', 'Evolve the Claude meta sidebar (T-141/T-157) from a read-only roster into the CONTROL surface for clide-managed agents. Because clide owns the broker, the task list and inter-agent messages are local data — so the sidebar both shows them live and lets the user ACT: spawn / show / hide / mute an agent, reassign a task, inject or redirect a message. Roster rows keep the live per-member status (T-157) but gain controls. Acceptance: from the sidebar the user can spawn/show/hide an agent, watch the shared task list update, see the message flow, and intervene (reassign/inject); widget tests for the controls wired to the orchestrator + broker. Blocked by T-169 (orchestrator) and T-170 (broker).', 'done', 'medium', NULL, NULL, 'D-77', '2026-05-24 16:27:09', '2026-05-30 21:11:26', NULL, 'cbd95c04b6003ab75929a3864a1ea5cc', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6FMAHXM1XAHHCQC60', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'P2: sidebar cockpit — task list + messages + roster controls', 'Evolve the Claude meta sidebar (T-141/T-157) from a read-only roster into the CONTROL surface for clide-managed agents. Because clide owns the broker, the task list and inter-agent messages are local data — so the sidebar both shows them live and lets the user ACT: spawn / show / hide / mute an agent, reassign a task, inject or redirect a message. Roster rows keep the live per-member status (T-157) but gain controls. Acceptance: from the sidebar the user can spawn/show/hide an agent, watch the shared task list update, see the message flow, and intervene (reassign/inject); widget tests for the controls wired to the orchestrator + broker. Blocked by T-169 (orchestrator) and T-170 (broker).', 'done', 'medium', NULL, NULL, 'D-77', '2026-05-24 16:27:09', '2026-05-30 21:11:26', NULL, 'cbd95c04b6003ab75929a3864a1ea5cc', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM71N3YMS82BAYD3M9R', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'P2: fork-into-a-pane (--fork-session)', 'Branch a conversation into a new managed session/pane, reusing the orchestrator''s spawn plumbing. ''Fork'' = spawn a managed session seeded from another session''s context via --resume + --fork-session (resume the source, but create a new session-id so the branch diverges without touching the original). Surface it as a slash action and a sidebar/roster button on a session. Acceptance: forking an active session opens a new pane continuing from its context, independent thereafter; the original is unaffected; tests for the fork argv + the new managed session appearing in the roster. Blocked by T-169 (orchestrator).
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM71N3YMS82BAYD3M9R', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'P2: fork-into-a-pane (--fork-session)', 'Branch a conversation into a new managed session/pane, reusing the orchestrator''s spawn plumbing. ''Fork'' = spawn a managed session seeded from another session''s context via --resume + --fork-session (resume the source, but create a new session-id so the branch diverges without touching the original). Surface it as a slash action and a sidebar/roster button on a session. Acceptance: forking an active session opens a new pane continuing from its context, independent thereafter; the original is unaffected; tests for the fork argv + the new managed session appearing in the roster. Blocked by T-169 (orchestrator).
|
||||||
|
|
||||||
---
|
---
|
||||||
Refinement (2026-05-30, /whats-next): --fork-session CONFIRMED against the live binary (claude --help: "When resuming, create a new session ID instead of reusing the original (use with --resume or --continue)"). Fork argv = [''--resume'', <sourceSessionId>, ''--fork-session''] (no --session-id; the new branch gets its own id from the init event). Add forkSourceSessionId to SpawnSpec (session_orchestrator.dart); build argv via a forkSessionArgs helper in session_naming.dart; add ''fork'' to kClideOwnedCommands + a case in claude_pane._send; add a fork button to _memberRow in claude_meta_sidebar.dart. SEQUENCE AFTER T-171 (shares _memberRow + orchestrator).', 'done', 'low', NULL, NULL, 'D-77', '2026-05-24 16:27:16', '2026-05-30 21:34:56', NULL, '7b902e0081c0ce980ba594c767edeb3e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Refinement (2026-05-30, /whats-next): --fork-session CONFIRMED against the live binary (claude --help: "When resuming, create a new session ID instead of reusing the original (use with --resume or --continue)"). Fork argv = [''--resume'', <sourceSessionId>, ''--fork-session''] (no --session-id; the new branch gets its own id from the init event). Add forkSourceSessionId to SpawnSpec (session_orchestrator.dart); build argv via a forkSessionArgs helper in session_naming.dart; add ''fork'' to kClideOwnedCommands + a case in claude_pane._send; add a fork button to _memberRow in claude_meta_sidebar.dart. SEQUENCE AFTER T-171 (shares _memberRow + orchestrator).', 'done', 'low', NULL, NULL, 'D-77', '2026-05-24 16:27:16', '2026-05-30 21:34:56', NULL, '7b902e0081c0ce980ba594c767edeb3e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6V6TKRPA106D5SMMM', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'Team message inbox — broker chat (sidebar widget + poppable pane)', 'A team chat / message inbox: render the clide broker traffic as a chat-client timeline and make the user a first-class participant. (1) Timeline: every inter-agent message (send_message/broadcast) shown as chat rows with a colour-coded sender chip (tyre/gestalt/lead/you/...). (2) User as a broker participant: extend the T-170 broker so send_message(to: user) delivers into the inbox, and the team-awareness roster injected into each agent lists "you" as addressable; the user can post into the channel. (3) @-routing from the user: a recipient picker / @name parses to a broker route, @team (or no tag) broadcasts; reuse the slash-typeahead machinery for @-completion. (4) Interrupt tickbox on the composer: unchecked queues the message into the target next turn (normal broker delivery); checked sends an interrupt control_request to the target session (cancels its current turn) then delivers; default OFF. (5) One chat model, two surfaces: a compact sidebar widget in the cockpit (live feed + quick @-post) that pops out into a full chat pane. Wireframes: docs/design/wireframes/claude-prompts/05-team-cockpit-sidebar.png (widget) + 06-team-chat-pane.png (pane). Acceptance: broker messages render as chat; user posts route by @tag (one agent) or broadcast; interrupt tickbox cancels+delivers vs queues; widget and pane share one model; tests for routing + interrupt + render. Resolves the user-participation gaps from the team-mode screen analysis. Blocked by T-170 (broker).', 'done', 'medium', NULL, NULL, 'D-77', '2026-05-25 09:15:58', '2026-05-31 08:49:07', NULL, '806fbf94bf043e95c44e353cae0847ee', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6V6TKRPA106D5SMMM', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'Team message inbox — broker chat (sidebar widget + poppable pane)', 'A team chat / message inbox: render the clide broker traffic as a chat-client timeline and make the user a first-class participant. (1) Timeline: every inter-agent message (send_message/broadcast) shown as chat rows with a colour-coded sender chip (tyre/gestalt/lead/you/...). (2) User as a broker participant: extend the T-170 broker so send_message(to: user) delivers into the inbox, and the team-awareness roster injected into each agent lists "you" as addressable; the user can post into the channel. (3) @-routing from the user: a recipient picker / @name parses to a broker route, @team (or no tag) broadcasts; reuse the slash-typeahead machinery for @-completion. (4) Interrupt tickbox on the composer: unchecked queues the message into the target next turn (normal broker delivery); checked sends an interrupt control_request to the target session (cancels its current turn) then delivers; default OFF. (5) One chat model, two surfaces: a compact sidebar widget in the cockpit (live feed + quick @-post) that pops out into a full chat pane. Wireframes: docs/design/wireframes/claude-prompts/05-team-cockpit-sidebar.png (widget) + 06-team-chat-pane.png (pane). Acceptance: broker messages render as chat; user posts route by @tag (one agent) or broadcast; interrupt tickbox cancels+delivers vs queues; widget and pane share one model; tests for routing + interrupt + render. Resolves the user-participation gaps from the team-mode screen analysis. Blocked by T-170 (broker).', 'done', 'medium', NULL, NULL, 'D-77', '2026-05-25 09:15:58', '2026-05-31 08:49:07', NULL, '806fbf94bf043e95c44e353cae0847ee', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7WE0SD9N4HCP9BB64', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'Claude Config sidebar tab — skills/agents/commands/settings/permissions/hooks/MCP', 'The Config sub-tab (T-182): a browsable view of the Claude environment over ClaudeConfig (D-76 / T-151 — skills, commands, settings, permissions from ~/.claude + .claude, layered, local wins) plus the stream-json init/initialize payloads (agents, output styles, MCP servers, models, plugins). Layout: SETTINGS is a FIXED key->value table pinned at the top (not collapsible) — model, output style, permission mode, source. Everything variable-length is an EXPANDABLE accordion section showing the FULL list when expanded, never truncated (truncating to first-N + ellipsis falsely prioritises the first entries and makes the list pointless): SKILLS, AGENTS, COMMANDS, HOOKS, PERMISSIONS (grouped allow/ask/deny, colour-coded, each rule on its own line), MCP SERVERS — each with a count. File-backed entries are CLICKABLE: a skill (SKILL.md), agent (.claude/agents/*.md), or command (.claude/commands/*.md) — clicking fires an open-file action into the right-side markdown reader/editor pane (reusing the existing file-open plumbing, D-6 parity) to show what it says. Watched/live on .claude changes. Acceptance: settings render as a top table; every variable section expands to its complete list (no ellipsis); clicking a file-backed item opens its .md in the reader; permissions colour-coded by kind; widget tests for table + expand + click-to-open. Wireframe: docs/design/wireframes/claude-prompts/09-sidebar-config-tab.png. Blocked by T-182.', 'done', 'medium', NULL, NULL, 'D-76', '2026-05-25 09:26:40', '2026-05-31 09:30:11', NULL, '91685d0b5a2b70f90746cd126ec023f1', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM7WE0SD9N4HCP9BB64', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'Claude Config sidebar tab — skills/agents/commands/settings/permissions/hooks/MCP', 'The Config sub-tab (T-182): a browsable view of the Claude environment over ClaudeConfig (D-76 / T-151 — skills, commands, settings, permissions from ~/.claude + .claude, layered, local wins) plus the stream-json init/initialize payloads (agents, output styles, MCP servers, models, plugins). Layout: SETTINGS is a FIXED key->value table pinned at the top (not collapsible) — model, output style, permission mode, source. Everything variable-length is an EXPANDABLE accordion section showing the FULL list when expanded, never truncated (truncating to first-N + ellipsis falsely prioritises the first entries and makes the list pointless): SKILLS, AGENTS, COMMANDS, HOOKS, PERMISSIONS (grouped allow/ask/deny, colour-coded, each rule on its own line), MCP SERVERS — each with a count. File-backed entries are CLICKABLE: a skill (SKILL.md), agent (.claude/agents/*.md), or command (.claude/commands/*.md) — clicking fires an open-file action into the right-side markdown reader/editor pane (reusing the existing file-open plumbing, D-6 parity) to show what it says. Watched/live on .claude changes. Acceptance: settings render as a top table; every variable section expands to its complete list (no ellipsis); clicking a file-backed item opens its .md in the reader; permissions colour-coded by kind; widget tests for table + expand + click-to-open. Wireframe: docs/design/wireframes/claude-prompts/09-sidebar-config-tab.png. Blocked by T-182.', 'done', 'medium', NULL, NULL, 'D-76', '2026-05-25 09:26:40', '2026-05-31 09:30:11', NULL, '91685d0b5a2b70f90746cd126ec023f1', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM55DZN2RFEVP6CG48G', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'Validate partial-message wire shape from --include-partial-messages against a live capture', 'T-168 follow-up. T-168 wired --include-partial-messages into the interactive stream-json session (stream_json_session.dart) and added a partial-streaming handler that ASSUMES claude emits incremental assistant events carrying partial:true sharing one message.id. That shape is UNVERIFIED: the 2.1.150 spike (docs/spikes/cc-stream-json-control-protocol-2.1.150.md) only documents non-partial assistant events (one per content block, no partial flag), and the flag''s --help says it ''only works with --print'' while clide runs the interactive control protocol (--input-format/--output-format stream-json, not --print). The handler degrades gracefully (unmatched shapes fall through to parseTranscriptChunk and are ignored — token streaming is inert but nothing breaks), and the T-168 fixtures are synthetic so they pass regardless of reality. Do: capture a real claude turn over the interactive stream-json transport with --include-partial-messages and record the actual partial event envelope (likely a stream_event content_block_delta, not assistant+partial:true). Then either (a) fix the handler in stream_json_session.dart::_onLine to match the real shape and add a fixture from the live capture, or (b) if the flag is a true no-op in the interactive (non-print) mode, drop --include-partial-messages from the argv and the dead partial-handler branch, and pin the finding in the spike doc. Either way, update the UNVERIFIED-WIRE-SHAPE comment in stream_json_session.dart and the spike. Acceptance: the partial path is validated against a live capture, the handler matches the real shape (or is removed), a fixture derived from the capture covers it, and the spike + code comment reflect the confirmed shape.', 'done', 'medium', NULL, NULL, 'D-77', '2026-05-30 11:42:53', '2026-05-31 10:17:09', NULL, '460a2c17c6509d145b8ee8870347ec23', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM55DZN2RFEVP6CG48G', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'Validate partial-message wire shape from --include-partial-messages against a live capture', 'T-168 follow-up. T-168 wired --include-partial-messages into the interactive stream-json session (stream_json_session.dart) and added a partial-streaming handler that ASSUMES claude emits incremental assistant events carrying partial:true sharing one message.id. That shape is UNVERIFIED: the 2.1.150 spike (docs/spikes/cc-stream-json-control-protocol-2.1.150.md) only documents non-partial assistant events (one per content block, no partial flag), and the flag''s --help says it ''only works with --print'' while clide runs the interactive control protocol (--input-format/--output-format stream-json, not --print). The handler degrades gracefully (unmatched shapes fall through to parseTranscriptChunk and are ignored — token streaming is inert but nothing breaks), and the T-168 fixtures are synthetic so they pass regardless of reality. Do: capture a real claude turn over the interactive stream-json transport with --include-partial-messages and record the actual partial event envelope (likely a stream_event content_block_delta, not assistant+partial:true). Then either (a) fix the handler in stream_json_session.dart::_onLine to match the real shape and add a fixture from the live capture, or (b) if the flag is a true no-op in the interactive (non-print) mode, drop --include-partial-messages from the argv and the dead partial-handler branch, and pin the finding in the spike doc. Either way, update the UNVERIFIED-WIRE-SHAPE comment in stream_json_session.dart and the spike. Acceptance: the partial path is validated against a live capture, the handler matches the real shape (or is removed), a fixture derived from the capture covers it, and the spike + code comment reflect the confirmed shape.', 'done', 'medium', NULL, NULL, 'D-77', '2026-05-30 11:42:53', '2026-05-31 10:17:09', NULL, '460a2c17c6509d145b8ee8870347ec23', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM52PRNJM86A1DZTQ1C', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'Capture the forked session''s real claude session-id from its init event', 'T-172 follow-up. A forked session is spawned with --resume <source> --fork-session and no --session-id, so claude assigns the branch a NEW session-id that only arrives in the stream-json init event. Today ManagedSession.sessionId for a fork holds a placeholder UUID (the orchestrator key), and the real claude session-id is never captured back. Consequence: the fork can''t itself be resumed/forked by id later, and any UI showing the session-id is wrong for forks. Do: capture session_id from the init/system event (StreamJsonSession already parses init for status — surface the session_id) and update the ManagedSession (make sessionId mutable or store a separate claudeSessionId that the orchestrator fills on init). Acceptance: after a fork''s first init event, the ManagedSession exposes the branch''s real claude session-id; a test drives an init event through a fake process and asserts the captured id. Surfaced by T-172; the fork argv/spawn/roster/original-unaffected behaviour already works without it.', 'done', 'low', NULL, NULL, 'D-77', '2026-05-30 21:34:26', '2026-05-31 10:22:02', NULL, '3286b15f285b1297144a350967eca43c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM52PRNJM86A1DZTQ1C', 'task', '06FB0TNQM5HM3N07VB3RPFJCFM', 'Capture the forked session''s real claude session-id from its init event', 'T-172 follow-up. A forked session is spawned with --resume <source> --fork-session and no --session-id, so claude assigns the branch a NEW session-id that only arrives in the stream-json init event. Today ManagedSession.sessionId for a fork holds a placeholder UUID (the orchestrator key), and the real claude session-id is never captured back. Consequence: the fork can''t itself be resumed/forked by id later, and any UI showing the session-id is wrong for forks. Do: capture session_id from the init/system event (StreamJsonSession already parses init for status — surface the session_id) and update the ManagedSession (make sessionId mutable or store a separate claudeSessionId that the orchestrator fills on init). Acceptance: after a fork''s first init event, the ManagedSession exposes the branch''s real claude session-id; a test drives an init event through a fake process and asserts the captured id. Surfaced by T-172; the fork argv/spawn/roster/original-unaffected behaviour already works without it.', 'done', 'low', NULL, NULL, 'D-77', '2026-05-30 21:34:26', '2026-05-31 10:22:02', NULL, '3286b15f285b1297144a350967eca43c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5HM3N07VB3RPFJCFM', 'epic', NULL, 'Claude via stream-json + unified clide-managed agent/session model', 'Per D-77: pivot the Claude pane from the interactive tmux TUI to Claude Code''s stream-json control protocol, and build a unified clide-managed agent/session model on top.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5HM3N07VB3RPFJCFM', 'epic', NULL, 'Claude via stream-json + unified clide-managed agent/session model', 'Per D-77: pivot the Claude pane from the interactive tmux TUI to Claude Code''s stream-json control protocol, and build a unified clide-managed agent/session model on top.
|
||||||
|
|
||||||
Why: the interactive TUI can''t surface AskUserQuestion / permission prompts (they never reach the transcript), transcript-file tailing is lossy + caused the session-fork/--session-id bug class, and Claude''s agent-team mode is tmux/interactive-only. stream-json fixes all three: structured events, native canUseTool prompt handling, --resume persistence — and lets clide OWN orchestration (teammate / secondary tab / forked branch / inline subagent all collapse into one primitive: a clide-managed session rendered as a pane; the sidebar becomes its cockpit).
|
Why: the interactive TUI can''t surface AskUserQuestion / permission prompts (they never reach the transcript), transcript-file tailing is lossy + caused the session-fork/--session-id bug class, and Claude''s agent-team mode is tmux/interactive-only. stream-json fixes all three: structured events, native canUseTool prompt handling, --resume persistence — and lets clide OWN orchestration (teammate / secondary tab / forked branch / inline subagent all collapse into one primitive: a clide-managed session rendered as a pane; the sidebar becomes its cockpit).
|
||||||
@@ -1020,7 +1020,7 @@ Why: the interactive TUI can''t surface AskUserQuestion / permission prompts (th
|
|||||||
Phase 1 (single-agent, ships the prompt-gap + lifecycle fix): stream-json transport, native permission/AskUserQuestion UI, --resume persistence, leveled-up native rendering.
|
Phase 1 (single-agent, ships the prompt-gap + lifecycle fix): stream-json transport, native permission/AskUserQuestion UI, --resume persistence, leveled-up native rendering.
|
||||||
Phase 2 (unified model): session orchestrator (spawn/show/hide), clide-hosted MCP coordination broker + injected team-awareness, sidebar cockpit (tasks + messages + roster controls), fork-into-a-pane.
|
Phase 2 (unified model): session orchestrator (spawn/show/hide), clide-hosted MCP coordination broker + injected team-awareness, sidebar cockpit (tasks + messages + roster controls), fork-into-a-pane.
|
||||||
|
|
||||||
Supersedes the transcript-tail + observe-tmux-team approach of epic T-132. Acceptance: Claude runs over stream-json with native prompts + --resume; teams are clide-orchestrated managed sessions controlled from the sidebar; the tmux dependency for Claude is gone (terminal builtin retained for general shell).', 'done', 'high', NULL, NULL, 'D-77', '2026-05-24 16:26:05', '2026-05-31 10:22:03', NULL, 'aeda893b3e33e74a3f68444835957b45', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Supersedes the transcript-tail + observe-tmux-team approach of epic T-132. Acceptance: Claude runs over stream-json with native prompts + --resume; teams are clide-orchestrated managed sessions controlled from the sidebar; the tmux dependency for Claude is gone (terminal builtin retained for general shell).', 'done', 'high', NULL, NULL, 'D-77', '2026-05-24 16:26:05', '2026-05-31 10:22:03', NULL, 'aeda893b3e33e74a3f68444835957b45', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4TDSA2PDCV814E3YW', 'bug', NULL, 'TerminalGestureHandler tertiary-tap wired to secondary; middle-button mis-typed', '**File:** `lib/src/terminal/src/ui/gesture/gesture_handler.dart` (build wiring + state-method body) + `lib/src/terminal/src/ui/gesture/gesture_detector.dart` (dead public API).
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4TDSA2PDCV814E3YW', 'bug', NULL, 'TerminalGestureHandler tertiary-tap wired to secondary; middle-button mis-typed', '**File:** `lib/src/terminal/src/ui/gesture/gesture_handler.dart` (build wiring + state-method body) + `lib/src/terminal/src/ui/gesture/gesture_detector.dart` (dead public API).
|
||||||
|
|
||||||
**Bug:** Middle-clicks ("tertiary tap") are routed through the wrong handler chain, and even the unreachable target carries a button-enum typo. Same shape as T-93 but on a different gesture pair.
|
**Bug:** Middle-clicks ("tertiary tap") are routed through the wrong handler chain, and even the unreachable target carries a button-enum typo. Same shape as T-93 but on a different gesture pair.
|
||||||
@@ -1071,19 +1071,19 @@ The `PanGestureRecognizer` in `TerminalGestureDetector` is registered with `supp
|
|||||||
**Surfaced from:** T-91 ui/ gesture sweep. The `onTertiaryTap*` lines (gesture_handler.dart:147-152) showed as uncovered in the lcov diff — the gestures sweep skipped writing tests for them because they''re unreachable production code.
|
**Surfaced from:** T-91 ui/ gesture sweep. The `onTertiaryTap*` lines (gesture_handler.dart:147-152) showed as uncovered in the lcov diff — the gestures sweep skipped writing tests for them because they''re unreachable production code.
|
||||||
|
|
||||||
**Cross-references:** T-91 (epic parent), T-93 (same shape on `onTapUp`), T-89 (coverage epic).
|
**Cross-references:** T-91 (epic parent), T-93 (same shape on `onTapUp`), T-89 (coverage epic).
|
||||||
', 'done', 'medium', NULL, NULL, NULL, '2026-05-08 10:48:59', '2026-05-31 11:20:21', NULL, '6b80c66853b9ba73dff37b608e0a62bb', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
', 'done', 'medium', NULL, NULL, NULL, '2026-05-08 10:48:59', '2026-05-31 11:20:21', NULL, '6b80c66853b9ba73dff37b608e0a62bb', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM514YJBF8AY8Q4N7Q4', 'bug', '06FB0TNQM6S7FDAXQX32JNCSFG', 'Decision reader no longer opens on click', 'Clicking a decision (in the decisions list, or a D-ref from a ticket/markdown) no longer opens it in the decision reader. The channels are CORRECT — publishers emit (''builtin.decisions'',''selection'') and DecisionDetailView subscribes to the same (decision_detail_view.dart ~line 26). Suspected cause (confirm at fix time): DecisionsExtension.activate (decisions/src/extension.dart ~23-37) tears down and re-contributes the decisions.detail tab on EVERY selection (uncontribute then contribute with initialId), and the context-panel slot may not be surfaced (setVisible/setCollapsed not always succeeding) — unlike the still-working ticket panel, which uses a STATIC tab + activateTab + load (ticket_detail_controller.dart). Fix direction: align the decision reader with the ticket panel pattern (static tab; activateTab + load on selection; no per-click re-contribution) and ensure the context panel is revealed. Acceptance: clicking a decision anywhere reliably opens it in the decision reader, including same-decision-twice and rapid-sequential clicks; widget test.', 'done', 'high', NULL, NULL, NULL, '2026-05-31 11:38:28', '2026-05-31 14:17:22', NULL, '9b578034685a5745837ef90a1463e874', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM514YJBF8AY8Q4N7Q4', 'bug', '06FB0TNQM6S7FDAXQX32JNCSFG', 'Decision reader no longer opens on click', 'Clicking a decision (in the decisions list, or a D-ref from a ticket/markdown) no longer opens it in the decision reader. The channels are CORRECT — publishers emit (''builtin.decisions'',''selection'') and DecisionDetailView subscribes to the same (decision_detail_view.dart ~line 26). Suspected cause (confirm at fix time): DecisionsExtension.activate (decisions/src/extension.dart ~23-37) tears down and re-contributes the decisions.detail tab on EVERY selection (uncontribute then contribute with initialId), and the context-panel slot may not be surfaced (setVisible/setCollapsed not always succeeding) — unlike the still-working ticket panel, which uses a STATIC tab + activateTab + load (ticket_detail_controller.dart). Fix direction: align the decision reader with the ticket panel pattern (static tab; activateTab + load on selection; no per-click re-contribution) and ensure the context panel is revealed. Acceptance: clicking a decision anywhere reliably opens it in the decision reader, including same-decision-twice and rapid-sequential clicks; widget test.', 'done', 'high', NULL, NULL, NULL, '2026-05-31 11:38:28', '2026-05-31 14:17:22', NULL, '9b578034685a5745837ef90a1463e874', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5316HVGDYD2W0DC50', 'bug', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Slash typeahead omits clide-owned commands (/resume)', '/resume works when typed but doesn''t appear in the composer slash typeahead. Cause: the typeahead sources its command list from activeClaudeConfig.slashCommands (the CLI stream-json probe), which does not include ''resume'' (it''s not an in-session slash command the CLI advertises; clide owns/intercepts it). /clear appears because ''clear'' IS in the probe list. Fix: union kClideOwnedCommands (slash_commands.dart) into the typeahead''s command source — e.g. in ClaudeComposer''s default slashCommandsResolver return {...?activeClaudeConfig?.slashCommands, ...kClideOwnedCommands}. Acceptance: typing /res suggests /resume; /clear still suggested; widget test asserting clide-owned commands appear even when absent from the probe list. Follow-up to T-152/T-156.', 'done', 'low', NULL, NULL, NULL, '2026-05-24 09:29:07', '2026-05-31 14:17:22', NULL, 'db998b28efb4e9facbe279d05db65277', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM5316HVGDYD2W0DC50', 'bug', '06FB0TNQM7W0NPAEG3KWNFY9DR', 'Slash typeahead omits clide-owned commands (/resume)', '/resume works when typed but doesn''t appear in the composer slash typeahead. Cause: the typeahead sources its command list from activeClaudeConfig.slashCommands (the CLI stream-json probe), which does not include ''resume'' (it''s not an in-session slash command the CLI advertises; clide owns/intercepts it). /clear appears because ''clear'' IS in the probe list. Fix: union kClideOwnedCommands (slash_commands.dart) into the typeahead''s command source — e.g. in ClaudeComposer''s default slashCommandsResolver return {...?activeClaudeConfig?.slashCommands, ...kClideOwnedCommands}. Acceptance: typing /res suggests /resume; /clear still suggested; widget test asserting clide-owned commands appear even when absent from the probe list. Follow-up to T-152/T-156.', 'done', 'low', NULL, NULL, NULL, '2026-05-24 09:29:07', '2026-05-31 14:17:22', NULL, 'db998b28efb4e9facbe279d05db65277', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4GVWHMRTMQYRTRKD4', 'bug', '06FB0TNQM6S7FDAXQX32JNCSFG', 'Markdown reader no longer opens on click (files panel, Claude Config tab, wiki links)', 'Clicking a .md no longer opens it in the right-side markdown reader; only the pql markdown tab still works (it is the one surface that correctly publishes (''builtin.markdown'',''selection'')). Broken surfaces: the files panel (file_tree_view.dart _openFile / _FilteredFileRow, ~lines 213-222 and 284-285) and the Claude Config tab (claude_meta_sidebar.dart _configFileRow, ~553-556, shipped in T-183) both call ipc.request(''editor.open'',...) which targets the EDITOR, not the reader; the in-markdown wiki-link handler (markdown_viewer.dart _navigateToRecord) does not handle .md links; and a dead fallback subscribes to DaemonEvent kind ''editor.buffer_activated'' which the EditorRegistry never emits (it emits ''editor.active-changed''). Working pattern: publish (''builtin.markdown'',''selection'') -> the markdown extension activates the context-panel tab and bridges to channel ''load'' after mount -> MarkdownViewer renders. Fix: route .md clicks from the files panel, the Claude Config tab, and .md wiki links to publish (''builtin.markdown'',''selection''); fix or remove the dead editor-event fallback. Design note: per the reporter, clicking a .md should open the READER (non-.md files stay in the editor). Regression: files panel at 681ce3b (2026-04-22); Config tab born-broken at 494a6f1 (T-183). Acceptance: clicking a .md in the files panel, the Claude Config tab, and a wiki .md link each open it in the markdown reader; the dead fallback is gone; widget tests.', 'done', 'high', NULL, NULL, NULL, '2026-05-31 11:38:20', '2026-05-31 14:17:22', NULL, 'f47a85905c0df0b4b26b0ee1606fad27', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4GVWHMRTMQYRTRKD4', 'bug', '06FB0TNQM6S7FDAXQX32JNCSFG', 'Markdown reader no longer opens on click (files panel, Claude Config tab, wiki links)', 'Clicking a .md no longer opens it in the right-side markdown reader; only the pql markdown tab still works (it is the one surface that correctly publishes (''builtin.markdown'',''selection'')). Broken surfaces: the files panel (file_tree_view.dart _openFile / _FilteredFileRow, ~lines 213-222 and 284-285) and the Claude Config tab (claude_meta_sidebar.dart _configFileRow, ~553-556, shipped in T-183) both call ipc.request(''editor.open'',...) which targets the EDITOR, not the reader; the in-markdown wiki-link handler (markdown_viewer.dart _navigateToRecord) does not handle .md links; and a dead fallback subscribes to DaemonEvent kind ''editor.buffer_activated'' which the EditorRegistry never emits (it emits ''editor.active-changed''). Working pattern: publish (''builtin.markdown'',''selection'') -> the markdown extension activates the context-panel tab and bridges to channel ''load'' after mount -> MarkdownViewer renders. Fix: route .md clicks from the files panel, the Claude Config tab, and .md wiki links to publish (''builtin.markdown'',''selection''); fix or remove the dead editor-event fallback. Design note: per the reporter, clicking a .md should open the READER (non-.md files stay in the editor). Regression: files panel at 681ce3b (2026-04-22); Config tab born-broken at 494a6f1 (T-183). Acceptance: clicking a .md in the files panel, the Claude Config tab, and a wiki .md link each open it in the markdown reader; the dead fallback is gone; widget tests.', 'done', 'high', NULL, NULL, NULL, '2026-05-31 11:38:20', '2026-05-31 14:17:22', NULL, 'f47a85905c0df0b4b26b0ee1606fad27', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4DAQ2CEFESG9JGMZ8', 'task', NULL, 'Speed up the test gate: dedupe the a11y run + decouple coverage from the dev loop', 'The pre-push gate (make push-check) and the inner-loop make test are slow; cost is dominated by ''flutter test --coverage --exclude-tags pty'' running the whole flutter suite WITH coverage instrumentation (ci/test.sh). Two concrete levers found by reading the pipeline: (1) FREE WIN — a11y tests run TWICE in push-check: the coverage run in ci/test.sh has no path filter so it already includes test/a11y/, then ci/test_a11y.sh (''flutter test test/a11y/'') runs them again in a separate flutter invocation, chained AFTER test (so not even fast-fail). Drop test-a11y from the push-check chain (keep ''make test-a11y'' as a standalone dev target) to remove a whole redundant flutter compile+boot+run; same tests still execute under test. (2) Coverage is on the dev inner loop — make test always runs --coverage, which is only needed where coverage-gate reads lcov (push-check/CI). Split a fast no-coverage ''make test'' for the edit loop from a coverage run used by push-check/CI; the script even claims <60s warm but coverage blows past that. MEASURE FIRST (cheap): time each ci/*.sh step, check ''flutter test --concurrency'' vs nproc, and look at per-file timing for golden/alchemist tests before further changes. Acceptance: dev ''make test'' runs without coverage and is meaningfully faster; push-check no longer double-runs the a11y suite; coverage is still gated (coverage-gate unchanged, floor 95); all gates stay green; the fast-vs-coverage split is documented in the Makefile/CONTRIBUTING. Domain: tooling/CI. Raised 2026-05-31 while the push gate kept interrupting flow.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4DAQ2CEFESG9JGMZ8', 'task', NULL, 'Speed up the test gate: dedupe the a11y run + decouple coverage from the dev loop', 'The pre-push gate (make push-check) and the inner-loop make test are slow; cost is dominated by ''flutter test --coverage --exclude-tags pty'' running the whole flutter suite WITH coverage instrumentation (ci/test.sh). Two concrete levers found by reading the pipeline: (1) FREE WIN — a11y tests run TWICE in push-check: the coverage run in ci/test.sh has no path filter so it already includes test/a11y/, then ci/test_a11y.sh (''flutter test test/a11y/'') runs them again in a separate flutter invocation, chained AFTER test (so not even fast-fail). Drop test-a11y from the push-check chain (keep ''make test-a11y'' as a standalone dev target) to remove a whole redundant flutter compile+boot+run; same tests still execute under test. (2) Coverage is on the dev inner loop — make test always runs --coverage, which is only needed where coverage-gate reads lcov (push-check/CI). Split a fast no-coverage ''make test'' for the edit loop from a coverage run used by push-check/CI; the script even claims <60s warm but coverage blows past that. MEASURE FIRST (cheap): time each ci/*.sh step, check ''flutter test --concurrency'' vs nproc, and look at per-file timing for golden/alchemist tests before further changes. Acceptance: dev ''make test'' runs without coverage and is meaningfully faster; push-check no longer double-runs the a11y suite; coverage is still gated (coverage-gate unchanged, floor 95); all gates stay green; the fast-vs-coverage split is documented in the Makefile/CONTRIBUTING. Domain: tooling/CI. Raised 2026-05-31 while the push gate kept interrupting flow.
|
||||||
|
|
||||||
Add a per-test timeout to the gate''s flutter test (e.g. ci/test.sh: ''flutter test --coverage --timeout 60s''). Motivation discovered 2026-05-31: a hung pumpAndSettle has a 10-MINUTE default timeout, so a few hanging widget tests wedge make push-check for 30+ minutes — which is almost certainly why a MacBook session resorted to ''git push --no-verify'' (the gate never returned; it was not disabled, it was hung). A tight per-test timeout makes any future hang fail fast (60s) instead of wedging a pre-push, so the gate stays usable and nobody is tempted to bypass it. Pair with: keep writing pump()-bounded tests instead of pumpAndSettle() where a view has overlapping async loads (see the T-188 decision_reader_test hang).
|
Add a per-test timeout to the gate''s flutter test (e.g. ci/test.sh: ''flutter test --coverage --timeout 60s''). Motivation discovered 2026-05-31: a hung pumpAndSettle has a 10-MINUTE default timeout, so a few hanging widget tests wedge make push-check for 30+ minutes — which is almost certainly why a MacBook session resorted to ''git push --no-verify'' (the gate never returned; it was not disabled, it was hung). A tight per-test timeout makes any future hang fail fast (60s) instead of wedging a pre-push, so the gate stays usable and nobody is tempted to bypass it. Pair with: keep writing pump()-bounded tests instead of pumpAndSettle() where a view has overlapping async loads (see the T-188 decision_reader_test hang).
|
||||||
|
|
||||||
Measured 2026-05-31 (16-core box, warm cache, full flutter suite --exclude-tags pty): coverage default-concurrency = ~36s; coverage --concurrency=12 = ~37s (NO improvement — coverage runs are concurrency-insensitive, the instrumentation/collection dominates); NO-coverage --concurrency=12 = ~21s. Conclusions: (1) Concurrency only helps the NON-coverage path — do NOT bother adding --concurrency to the coverage gate, it buys nothing. (2) The dev inner-loop win is concrete: a no-coverage ''make test'' with --concurrency=12 runs ~21s vs ~36s today (~40% faster) — this is how we ''beat 40s'' for the edit loop. (3) The push-check coverage run is floored at ~36s by coverage itself; getting below that needs a different coverage approach (package:coverage via VM service, or coverage-on-changed-files) — out of scope for the quick win. So the actionable set is unchanged: no-coverage+concurrency dev target, coverage-only-in-push, drop the redundant a11y pass, add a per-test --timeout for hang-safety.', 'backlog', 'medium', NULL, NULL, NULL, '2026-05-31 12:08:42', '2026-05-31 14:46:39', NULL, '650abf0ff970502eb94e4780b6d69158', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Measured 2026-05-31 (16-core box, warm cache, full flutter suite --exclude-tags pty): coverage default-concurrency = ~36s; coverage --concurrency=12 = ~37s (NO improvement — coverage runs are concurrency-insensitive, the instrumentation/collection dominates); NO-coverage --concurrency=12 = ~21s. Conclusions: (1) Concurrency only helps the NON-coverage path — do NOT bother adding --concurrency to the coverage gate, it buys nothing. (2) The dev inner-loop win is concrete: a no-coverage ''make test'' with --concurrency=12 runs ~21s vs ~36s today (~40% faster) — this is how we ''beat 40s'' for the edit loop. (3) The push-check coverage run is floored at ~36s by coverage itself; getting below that needs a different coverage approach (package:coverage via VM service, or coverage-on-changed-files) — out of scope for the quick win. So the actionable set is unchanged: no-coverage+concurrency dev target, coverage-only-in-push, drop the redundant a11y pass, add a per-test --timeout for hang-safety.', 'backlog', 'medium', NULL, NULL, NULL, '2026-05-31 12:08:42', '2026-05-31 14:46:39', NULL, '650abf0ff970502eb94e4780b6d69158', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6S7FDAXQX32JNCSFG', 'epic', NULL, 'Sidebar readers: fix message-bus open + add back/forward + pin', 'The right-side sidebar READERS — the markdown reader (builtin.markdown, lib/builtin/markdown/src/markdown_viewer.dart) and the decision reader (builtin.decisions, lib/builtin/decisions/src/decision_detail_view.dart) — are separate from the editor and open via the kernel MessageBus, the same pattern as the still-working ticket panel (lib/builtin/tickets): a click publishes (publisher, channel ''selection''); an extension activates the context-panel tab; the reader widget subscribes and renders. Two open paths are currently broken and we also want reading-navigation (back/forward) plus a single-slot pin on BOTH readers. Grouped as one set because all four tickets touch the same two reader widgets. Root-cause investigation done 2026-05-31 (see child tickets).', 'done', 'high', NULL, NULL, NULL, '2026-05-31 11:37:34', '2026-05-31 16:40:19', NULL, '642752efce8c4d5223236fc6f0e68116', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6S7FDAXQX32JNCSFG', 'epic', NULL, 'Sidebar readers: fix message-bus open + add back/forward + pin', 'The right-side sidebar READERS — the markdown reader (builtin.markdown, lib/builtin/markdown/src/markdown_viewer.dart) and the decision reader (builtin.decisions, lib/builtin/decisions/src/decision_detail_view.dart) — are separate from the editor and open via the kernel MessageBus, the same pattern as the still-working ticket panel (lib/builtin/tickets): a click publishes (publisher, channel ''selection''); an extension activates the context-panel tab; the reader widget subscribes and renders. Two open paths are currently broken and we also want reading-navigation (back/forward) plus a single-slot pin on BOTH readers. Grouped as one set because all four tickets touch the same two reader widgets. Root-cause investigation done 2026-05-31 (see child tickets).', 'done', 'high', NULL, NULL, NULL, '2026-05-31 11:37:34', '2026-05-31 16:40:19', NULL, '642752efce8c4d5223236fc6f0e68116', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM709YPWECH1E66XXD4', 'bug', NULL, 'Flaky: transcript_publisher_test ''republishes reader items onto the bus'' fails under the full parallel run', 'test/builtin/claude/transcript_publisher_test.dart ''TranscriptPublisher republishes reader items onto the bus (lead channel + item key)'' fails intermittently during ''make test-coverage'' / push-check (the full parallel flutter test run) but PASSES reliably in isolation (flutter test <file> = 3/3 green). Observed 2026-05-31 — one run failed it, the immediately-preceding agent run passed all 2221. Not caused by T-192 (the coverage path uses default concurrency, unchanged) — it''s a pre-existing timing/ordering flake, likely a MessageBus delivery race: the test asserts a republished item arrived on the lead channel, and under concurrent load the broadcast-stream delivery may not have been awaited deterministically. Fix: make the test await delivery deterministically (pump/await the bus microtask, or expectLater on the stream) rather than relying on timing; check TranscriptPublisher for any real ordering bug too. Impact: intermittently red push-check → tempts --no-verify (see T-192). Acceptance: the test passes deterministically across repeated full-suite runs; root cause (test-only vs a real publisher race) identified.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM709YPWECH1E66XXD4', 'bug', NULL, 'Flaky: transcript_publisher_test ''republishes reader items onto the bus'' fails under the full parallel run', 'test/builtin/claude/transcript_publisher_test.dart ''TranscriptPublisher republishes reader items onto the bus (lead channel + item key)'' fails intermittently during ''make test-coverage'' / push-check (the full parallel flutter test run) but PASSES reliably in isolation (flutter test <file> = 3/3 green). Observed 2026-05-31 — one run failed it, the immediately-preceding agent run passed all 2221. Not caused by T-192 (the coverage path uses default concurrency, unchanged) — it''s a pre-existing timing/ordering flake, likely a MessageBus delivery race: the test asserts a republished item arrived on the lead channel, and under concurrent load the broadcast-stream delivery may not have been awaited deterministically. Fix: make the test await delivery deterministically (pump/await the bus microtask, or expectLater on the stream) rather than relying on timing; check TranscriptPublisher for any real ordering bug too. Impact: intermittently red push-check → tempts --no-verify (see T-192). Acceptance: the test passes deterministically across repeated full-suite runs; root cause (test-only vs a real publisher race) identified.
|
||||||
|
|
||||||
MECHANISM (the systemic answer, per discussion): tests are parallel by default (--concurrency global = invisible parallel=true); express ''parallel=false'' for a vulnerable test via a TAG + a serial pass. The ''pty'' tag is the half-built precedent: it splits PTY tests into a separate ''dart test'' pass but did NOT serialize it (and leaned on retry:2). DONE 2026-05-31: that pty pass now runs --concurrency=1 and the retry:2 band-aids are removed — PTY/registry flake verified stable 4/4 runs. REMAINING: generalize to a ''serial'' tag for FLUTTER-side vulnerable tests (transcript_publisher''s ''republishes reader items onto the bus''): declare ''serial'' in dart_test.yaml; the parallel flutter run adds --exclude-tags serial; add a serial flutter pass (flutter test --tags serial --concurrency=1). WRINKLE for the gate: two flutter --coverage passes can''t just concatenate lcov (duplicate SF records double-count) — must real-merge (package:coverage format_coverage / lcov -a), OR run the serial pass without coverage if those tests'' source lines are covered elsewhere (check transcript_publisher.dart coverage from other tests first). ALTERNATIVE for the single transcript_publisher case: fix its await to be deterministic (await the bus delivery / expectLater on the stream) rather than quarantine — cheaper if it''s a test-timing bug vs a real bus race. Acceptance: no flaky test runs in the parallel pool; vulnerable tests are tagged + run serially; gate is deterministic across repeated full runs.', 'done', 'medium', NULL, NULL, NULL, '2026-05-31 16:12:42', '2026-05-31 17:26:25', NULL, '90c3ac0bae00567816b15cf6a2c54167', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
MECHANISM (the systemic answer, per discussion): tests are parallel by default (--concurrency global = invisible parallel=true); express ''parallel=false'' for a vulnerable test via a TAG + a serial pass. The ''pty'' tag is the half-built precedent: it splits PTY tests into a separate ''dart test'' pass but did NOT serialize it (and leaned on retry:2). DONE 2026-05-31: that pty pass now runs --concurrency=1 and the retry:2 band-aids are removed — PTY/registry flake verified stable 4/4 runs. REMAINING: generalize to a ''serial'' tag for FLUTTER-side vulnerable tests (transcript_publisher''s ''republishes reader items onto the bus''): declare ''serial'' in dart_test.yaml; the parallel flutter run adds --exclude-tags serial; add a serial flutter pass (flutter test --tags serial --concurrency=1). WRINKLE for the gate: two flutter --coverage passes can''t just concatenate lcov (duplicate SF records double-count) — must real-merge (package:coverage format_coverage / lcov -a), OR run the serial pass without coverage if those tests'' source lines are covered elsewhere (check transcript_publisher.dart coverage from other tests first). ALTERNATIVE for the single transcript_publisher case: fix its await to be deterministic (await the bus delivery / expectLater on the stream) rather than quarantine — cheaper if it''s a test-timing bug vs a real bus race. Acceptance: no flaky test runs in the parallel pool; vulnerable tests are tagged + run serially; gate is deterministic across repeated full runs.', 'done', 'medium', NULL, NULL, NULL, '2026-05-31 16:12:42', '2026-05-31 17:26:25', NULL, '90c3ac0bae00567816b15cf6a2c54167', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4QPGVP54EKJPCNQQM', 'story', NULL, 'quick file open (Ctrl+P)', 'Fuzzy file finder overlay, separate from the command palette. Wired to pql files with debounced input. Shows file path with match highlighting. Enter opens in editor or markdown viewer depending on file type. Recent files shown when input is empty.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM4QPGVP54EKJPCNQQM', 'story', NULL, 'quick file open (Ctrl+P)', 'Fuzzy file finder overlay, separate from the command palette. Wired to pql files with debounced input. Shows file path with match highlighting. Enter opens in editor or markdown viewer depending on file type. Recent files shown when input is empty.
|
||||||
|
|
||||||
Refinement (2026-05-31):
|
Refinement (2026-05-31):
|
||||||
@@ -1096,7 +1096,7 @@ Recent files — none exists today (ProjectManager.recents tracks projects, not
|
|||||||
|
|
||||||
Overlay mirrors the ClidePalette chrome and reuses the 200ms-debounced ClideFilterBox. New QuickOpenIntent bound to ctrl+p / meta+p, guarded so it does not fire while the command palette is open (when: !palette.open — verify the keymap when-parser supports negation; otherwise pick a non-conflicting default). ctrl+p is currently palette.selectPrevious.
|
Overlay mirrors the ClidePalette chrome and reuses the 200ms-debounced ClideFilterBox. New QuickOpenIntent bound to ctrl+p / meta+p, guarded so it does not fire while the command palette is open (when: !palette.open — verify the keymap when-parser supports negation; otherwise pick a non-conflicting default). ctrl+p is currently palette.selectPrevious.
|
||||||
|
|
||||||
Files: new lib/builtin/files/src/quick_open_overlay.dart + extension registration; new lib/kernel/src/recent_files.dart; files_commands.dart (files.walk); keymap intents + default.yaml; app.dart Stack mount alongside ClidePalette.', 'done', 'medium', NULL, NULL, NULL, '2026-04-23 20:32:06', '2026-05-31 18:54:02', NULL, '318afbcd201a6a6fd559afd2174044e6', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Files: new lib/builtin/files/src/quick_open_overlay.dart + extension registration; new lib/kernel/src/recent_files.dart; files_commands.dart (files.walk); keymap intents + default.yaml; app.dart Stack mount alongside ClidePalette.', 'done', 'medium', NULL, NULL, NULL, '2026-04-23 20:32:06', '2026-05-31 18:54:02', NULL, '318afbcd201a6a6fd559afd2174044e6', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6YYG4X5R1GX97TJB4', 'story', NULL, 'find in files (Ctrl+Shift+F)', 'Workspace-wide text search via ripgrep or grep fallback. Sidebar panel with search input, match-in-context results, clickable to open file at line. Supports regex toggle, case sensitivity toggle, include/exclude glob filters.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM6YYG4X5R1GX97TJB4', 'story', NULL, 'find in files (Ctrl+Shift+F)', 'Workspace-wide text search via ripgrep or grep fallback. Sidebar panel with search input, match-in-context results, clickable to open file at line. Supports regex toggle, case sensitivity toggle, include/exclude glob filters.
|
||||||
|
|
||||||
Refinement (2026-05-31) — see D-79:
|
Refinement (2026-05-31) — see D-79:
|
||||||
@@ -1113,7 +1113,7 @@ Open-at-line — editor.open takes only {path} today. Extend it with an optional
|
|||||||
|
|
||||||
Sidebar panel follows the files/git/decisions TabContribution(slot: Slots.sidebar) pattern; custom widgets, no Material/Cupertino.
|
Sidebar panel follows the files/git/decisions TabContribution(slot: Slots.sidebar) pattern; custom widgets, no Material/Cupertino.
|
||||||
|
|
||||||
Files: new lib/builtin/search/{extension,search_controller,search_panel_view}.dart; new lib/src/daemon/search_commands.dart (search.grep + isolate pool); lib/src/files ignore layering; editor_commands.dart + registry.dart (line param); IPC schema + dispatcher registration; CLI `clide search grep` verb.', 'done', 'medium', NULL, NULL, NULL, '2026-04-23 20:32:06', '2026-05-31 18:54:02', NULL, '49267e45bcfbbd443fbb1c969ceef890', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Files: new lib/builtin/search/{extension,search_controller,search_panel_view}.dart; new lib/src/daemon/search_commands.dart (search.grep + isolate pool); lib/src/files ignore layering; editor_commands.dart + registry.dart (line param); IPC schema + dispatcher registration; CLI `clide search grep` verb.', 'done', 'medium', NULL, NULL, NULL, '2026-04-23 20:32:06', '2026-05-31 18:54:02', NULL, '49267e45bcfbbd443fbb1c969ceef890', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM452XPSG99PA60ZZ48', 'story', NULL, 'search and replace across files', 'Companion to find-in-files. Preview all replacements before applying. Support regex capture groups in replacement. Respects ignore patterns from pql config.
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNQM452XPSG99PA60ZZ48', 'story', NULL, 'search and replace across files', 'Companion to find-in-files. Preview all replacements before applying. Support regex capture groups in replacement. Respects ignore patterns from pql config.
|
||||||
|
|
||||||
Refinement (2026-05-31):
|
Refinement (2026-05-31):
|
||||||
@@ -1130,4 +1130,4 @@ Safety (user decision) — REQUIRE A CLEAN GIT WORKING TREE before apply: refuse
|
|||||||
|
|
||||||
Ignore — same full ignore_files: layering as T-52 (D-4).
|
Ignore — same full ignore_files: layering as T-52 (D-4).
|
||||||
|
|
||||||
Files: lib/src/daemon/files_commands.dart (files.write); new replacement-preview controller/view under lib/builtin/search/; reuse path_safety + diff render primitives; DialogRouter confirm; IPC schema + CLI parity verbs.', 'done', 'medium', NULL, NULL, NULL, '2026-04-23 20:32:06', '2026-05-31 19:41:13', NULL, '4180fad513063f05c53b8724d045e1e2', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
Files: lib/src/daemon/files_commands.dart (files.write); new replacement-preview controller/view under lib/builtin/search/; reuse path_safety + diff render primitives; DialogRouter confirm; IPC schema + CLI parity verbs.', 'done', 'medium', NULL, NULL, NULL, '2026-04-23 20:32:06', '2026-05-31 19:41:13', NULL, '4180fad513063f05c53b8724d045e1e2', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
|
|||||||
+7779
-304
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,101 @@
|
|||||||
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2G2KHKT5CJYR0TK1WQGMD0', 'story', '06FHAX7FV5KWGZQ31617R63W94', 'Tier-5 graph view (builtin.graph)', 'Tier-5 graph VIEW, absorbed from the former T-7 into the unified canvas epic (T-317). Force-directed layout of the vault (or a filtered subset): nodes are notes, edges are wikilinks. Hover highlights the connected subgraph; click opens the note in the editor. Filter pane: tag include/exclude, file glob, depth-from-active. pql provides the link data (pql backlinks / pql outlinks); rendering is owned in-app (CustomPaint, own-the-rendering-stack). Lives in its own slot per D-47 (context panel), uses MultitabPane (T-83). DISTINCT from the in-card graph TEMPLATE (T-321): T-321 renders a graph passed into the conversation drawing card; this is the full interactive graph pane over the whole vault. Relates to the core renderer (T-318) but has its own force-directed layout.
|
||||||
|
|
||||||
|
PROGRESS (2026-06-29): force-directed layout SOLVER built + tested (lib/src/graph/force_layout.dart, 6 dart-test cases, commit bcef3a6f) — deterministic Fruchterman-Reingold, Flutter-free. REMAINING (the bulk, multi-session): graph data model from pql backlinks/outlinks over the vault; CustomPaint rendering (nodes+edges); pan/zoom; hover-highlight-subgraph; click-opens-note; filter pane (tag/glob/depth); MultitabPane + context-panel slot (D-47) wiring; widget/golden tests. This is a full interactive Tier-5 pane, a fresh-session undertaking — only its solver core is done.
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02): the graph rendering + interaction foundation is BUILT + tested (4 slices, all committed). (1) force-directed solver — force_layout.dart (bcef3a6f). (2) link-graph model — vault_graph.dart: VaultGraph.fromOutlinks, neighborhood, edgePairs (084bf842). (3) CustomPaint renderer — graph_painter.dart: edges/nodes/labels, hover-dim, fit transform (6bea1723). (4) interactive GraphView — graph_view.dart: hover-highlight + click-to-open, shared GraphViewport hit-testing (c529703b). The graph is a fully working WIDGET (renders + hover + click). REMAINING = the app-integration phase: pql link-data wiring (pql outlinks over the vault -> the file->outlinks map -> VaultGraph), the pane shell (async load + filter: tag/glob/depth + pan/zoom), and MultitabPane + context-panel slot (D-47) + GraphExtension registration.', 'in_progress', 'medium', NULL, NULL, NULL, '2026-06-10 11:17:23', '2026-07-02 06:35:03.555', NULL, 'a46ad64b03bc1b4126e9882ed7b81a3a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2G2KHKT5CJYR0TK1WQGMD0', 'story', '06FHAX7FV5KWGZQ31617R63W94', 'Tier-5 graph view (builtin.graph)', 'Tier-5 graph VIEW, absorbed from the former T-7 into the unified canvas epic (T-317). Force-directed layout of the vault (or a filtered subset): nodes are notes, edges are wikilinks. Hover highlights the connected subgraph; click opens the note in the editor. Filter pane: tag include/exclude, file glob, depth-from-active. pql provides the link data (pql backlinks / pql outlinks); rendering is owned in-app (CustomPaint, own-the-rendering-stack). Lives in its own slot per D-47 (context panel), uses MultitabPane (T-83). DISTINCT from the in-card graph TEMPLATE (T-321): T-321 renders a graph passed into the conversation drawing card; this is the full interactive graph pane over the whole vault. Relates to the core renderer (T-318) but has its own force-directed layout.
|
||||||
|
|
||||||
|
PROGRESS (2026-06-29): force-directed layout SOLVER built + tested (lib/src/graph/force_layout.dart, 6 dart-test cases, commit bcef3a6f) — deterministic Fruchterman-Reingold, Flutter-free. REMAINING (the bulk, multi-session): graph data model from pql backlinks/outlinks over the vault; CustomPaint rendering (nodes+edges); pan/zoom; hover-highlight-subgraph; click-opens-note; filter pane (tag/glob/depth); MultitabPane + context-panel slot (D-47) wiring; widget/golden tests. This is a full interactive Tier-5 pane, a fresh-session undertaking — only its solver core is done.
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02): the graph rendering + interaction foundation is BUILT + tested (4 slices, all committed). (1) force-directed solver — force_layout.dart (bcef3a6f). (2) link-graph model — vault_graph.dart: VaultGraph.fromOutlinks, neighborhood, edgePairs (084bf842). (3) CustomPaint renderer — graph_painter.dart: edges/nodes/labels, hover-dim, fit transform (6bea1723). (4) interactive GraphView — graph_view.dart: hover-highlight + click-to-open, shared GraphViewport hit-testing (c529703b). The graph is a fully working WIDGET (renders + hover + click). REMAINING = the app-integration phase: pql link-data wiring (pql outlinks over the vault -> the file->outlinks map -> VaultGraph), the pane shell (async load + filter: tag/glob/depth + pan/zoom), and MultitabPane + context-panel slot (D-47) + GraphExtension registration.
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02, session 2): app-integration phase — 3 slices committed. (1) GraphController (graph_controller.dart, 3b67725b) — pql.files + per-file pql.outlinks over the vault -> VaultGraph; loading/error state; debounced files.changed refresh; 6 tests. (2) GraphPanel shell (graph_panel.dart, 6fae1bc4) — loading/empty/error states + GraphView + click-to-open via editor.open; 5 widget tests. (3) GraphExtension registration (extension.dart + builtin.graph i18n, a5acb6ac) — graph.view context-panel tab (D-47), activates after builtin.pql dep; 4 tests; CHANGELOG entry. The graph is now REACHABLE end-to-end (21 graph tests green). REMAINING (T-323 enrichment): pan/zoom on the view; filter controls (tag include/exclude, glob, depth-from-active).', 'in_progress', 'medium', NULL, NULL, NULL, '2026-06-10 11:17:23', '2026-07-02 08:33:27.518', NULL, 'dc254ed9b53362c45d11ac23f600b57d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FJ4D0GAXM1FN42PJKG7FE34G', 'task', NULL, 'Skill cleanup: apply 2026-07-02 estate-review fixes to clide repo + user scope', 'Apply verified findings from the estate-wide skill review: delete commit/penpot-login/clean-house(project copy) skills; centralize d2-diagram/frame0-wireframe/skill-create to user scope de-contaminated; repoint whats-next (governance/, gh, dead links, step 3a); fix git-commit heredoc guidance + stale sidecar/ADR refs; fix clide skill dock slot + description trim; testmode terminal category; ui-design phosphor glyph reference post-T-314; rewrite skills README index.', 'backlog', 'medium', NULL, NULL, NULL, '2026-07-02 09:41:05.239', '2026-07-02 09:41:05.239', NULL, 'c5ddebbb4ffe8611329732087dd1cebb', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FJ4D1M6ESSSQ1ZERTH4V9YN4', 'task', NULL, 'Distribute the clide skill per-workspace with an install marker', 'Estate review 2026-07-02: the clide skill is repo-agnostic and hand-copied into other repos (settled-reach), drifting. Long-term story: clide installs the skill into each workspace''s .claude/skills/ with a .pql-install.json-style marker (version + sha256) so staleness is detectable, following pql''s clean-house precedent. Until then the canonical copy lives in the clide repo.', 'backlog', 'medium', NULL, NULL, NULL, '2026-07-02 09:41:14.420', '2026-07-02 09:41:14.420', NULL, '698b529e4ea8e4417ddb3b9846b30c13', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FJ4D0GAXM1FN42PJKG7FE34G', 'task', NULL, 'Skill cleanup: apply 2026-07-02 estate-review fixes to clide repo + user scope', 'Apply verified findings from the estate-wide skill review: delete commit/penpot-login/clean-house(project copy) skills; centralize d2-diagram/frame0-wireframe/skill-create to user scope de-contaminated; repoint whats-next (governance/, gh, dead links, step 3a); fix git-commit heredoc guidance + stale sidecar/ADR refs; fix clide skill dock slot + description trim; testmode terminal category; ui-design phosphor glyph reference post-T-314; rewrite skills README index.', 'done', 'medium', NULL, NULL, NULL, '2026-07-02 09:41:05.239', '2026-07-02 09:55:52.109', NULL, '7470547f02b1269981faefe053aa4ae3', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2G2KHKT5CJYR0TK1WQGMD0', 'story', '06FHAX7FV5KWGZQ31617R63W94', 'Tier-5 graph view (builtin.graph)', 'Tier-5 graph VIEW, absorbed from the former T-7 into the unified canvas epic (T-317). Force-directed layout of the vault (or a filtered subset): nodes are notes, edges are wikilinks. Hover highlights the connected subgraph; click opens the note in the editor. Filter pane: tag include/exclude, file glob, depth-from-active. pql provides the link data (pql backlinks / pql outlinks); rendering is owned in-app (CustomPaint, own-the-rendering-stack). Lives in its own slot per D-47 (context panel), uses MultitabPane (T-83). DISTINCT from the in-card graph TEMPLATE (T-321): T-321 renders a graph passed into the conversation drawing card; this is the full interactive graph pane over the whole vault. Relates to the core renderer (T-318) but has its own force-directed layout.
|
||||||
|
|
||||||
|
PROGRESS (2026-06-29): force-directed layout SOLVER built + tested (lib/src/graph/force_layout.dart, 6 dart-test cases, commit bcef3a6f) — deterministic Fruchterman-Reingold, Flutter-free. REMAINING (the bulk, multi-session): graph data model from pql backlinks/outlinks over the vault; CustomPaint rendering (nodes+edges); pan/zoom; hover-highlight-subgraph; click-opens-note; filter pane (tag/glob/depth); MultitabPane + context-panel slot (D-47) wiring; widget/golden tests. This is a full interactive Tier-5 pane, a fresh-session undertaking — only its solver core is done.
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02): the graph rendering + interaction foundation is BUILT + tested (4 slices, all committed). (1) force-directed solver — force_layout.dart (bcef3a6f). (2) link-graph model — vault_graph.dart: VaultGraph.fromOutlinks, neighborhood, edgePairs (084bf842). (3) CustomPaint renderer — graph_painter.dart: edges/nodes/labels, hover-dim, fit transform (6bea1723). (4) interactive GraphView — graph_view.dart: hover-highlight + click-to-open, shared GraphViewport hit-testing (c529703b). The graph is a fully working WIDGET (renders + hover + click). REMAINING = the app-integration phase: pql link-data wiring (pql outlinks over the vault -> the file->outlinks map -> VaultGraph), the pane shell (async load + filter: tag/glob/depth + pan/zoom), and MultitabPane + context-panel slot (D-47) + GraphExtension registration.
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02, session 2): app-integration phase — 3 slices committed. (1) GraphController (graph_controller.dart, 3b67725b) — pql.files + per-file pql.outlinks over the vault -> VaultGraph; loading/error state; debounced files.changed refresh; 6 tests. (2) GraphPanel shell (graph_panel.dart, 6fae1bc4) — loading/empty/error states + GraphView + click-to-open via editor.open; 5 widget tests. (3) GraphExtension registration (extension.dart + builtin.graph i18n, a5acb6ac) — graph.view context-panel tab (D-47), activates after builtin.pql dep; 4 tests; CHANGELOG entry. The graph is now REACHABLE end-to-end (21 graph tests green). REMAINING (T-323 enrichment): pan/zoom on the view; filter controls (tag include/exclude, glob, depth-from-active).
|
||||||
|
|
||||||
|
COMPLETE (2026-07-02, session 2). All scope delivered + tested (56 graph tests, make test green, real-boot verified via testmode). Slices this session: GraphController (3b67725b), pane shell (6fae1bc4), extension+i18n registration (a5acb6ac), pan+zoom (e6556401), testmode coverage (46d9b403), filter model (f859173b), filter bar (aabec87d). Final feature: force-directed vault graph in the context panel (graph.view, D-47) — hover-highlight, click-to-open, scroll-zoom, drag-pan, and filters (path glob re-queries pql; depth-from-active local graph; tri-state tag include/exclude). Controller uses pql.meta (outlinks+tags in one call) and strips #heading fragments so heading links connect. NOTE: pql data load is 1 files + N meta calls (sequential); batching is a future optimisation if large vaults feel slow.', 'in_progress', 'medium', NULL, NULL, NULL, '2026-06-10 11:17:23', '2026-07-02 19:47:37.694', NULL, '6ef9144fd880038d5db1d318925a9afd', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2G2KHKT5CJYR0TK1WQGMD0', 'story', '06FHAX7FV5KWGZQ31617R63W94', 'Tier-5 graph view (builtin.graph)', 'Tier-5 graph VIEW, absorbed from the former T-7 into the unified canvas epic (T-317). Force-directed layout of the vault (or a filtered subset): nodes are notes, edges are wikilinks. Hover highlights the connected subgraph; click opens the note in the editor. Filter pane: tag include/exclude, file glob, depth-from-active. pql provides the link data (pql backlinks / pql outlinks); rendering is owned in-app (CustomPaint, own-the-rendering-stack). Lives in its own slot per D-47 (context panel), uses MultitabPane (T-83). DISTINCT from the in-card graph TEMPLATE (T-321): T-321 renders a graph passed into the conversation drawing card; this is the full interactive graph pane over the whole vault. Relates to the core renderer (T-318) but has its own force-directed layout.
|
||||||
|
|
||||||
|
PROGRESS (2026-06-29): force-directed layout SOLVER built + tested (lib/src/graph/force_layout.dart, 6 dart-test cases, commit bcef3a6f) — deterministic Fruchterman-Reingold, Flutter-free. REMAINING (the bulk, multi-session): graph data model from pql backlinks/outlinks over the vault; CustomPaint rendering (nodes+edges); pan/zoom; hover-highlight-subgraph; click-opens-note; filter pane (tag/glob/depth); MultitabPane + context-panel slot (D-47) wiring; widget/golden tests. This is a full interactive Tier-5 pane, a fresh-session undertaking — only its solver core is done.
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02): the graph rendering + interaction foundation is BUILT + tested (4 slices, all committed). (1) force-directed solver — force_layout.dart (bcef3a6f). (2) link-graph model — vault_graph.dart: VaultGraph.fromOutlinks, neighborhood, edgePairs (084bf842). (3) CustomPaint renderer — graph_painter.dart: edges/nodes/labels, hover-dim, fit transform (6bea1723). (4) interactive GraphView — graph_view.dart: hover-highlight + click-to-open, shared GraphViewport hit-testing (c529703b). The graph is a fully working WIDGET (renders + hover + click). REMAINING = the app-integration phase: pql link-data wiring (pql outlinks over the vault -> the file->outlinks map -> VaultGraph), the pane shell (async load + filter: tag/glob/depth + pan/zoom), and MultitabPane + context-panel slot (D-47) + GraphExtension registration.
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02, session 2): app-integration phase — 3 slices committed. (1) GraphController (graph_controller.dart, 3b67725b) — pql.files + per-file pql.outlinks over the vault -> VaultGraph; loading/error state; debounced files.changed refresh; 6 tests. (2) GraphPanel shell (graph_panel.dart, 6fae1bc4) — loading/empty/error states + GraphView + click-to-open via editor.open; 5 widget tests. (3) GraphExtension registration (extension.dart + builtin.graph i18n, a5acb6ac) — graph.view context-panel tab (D-47), activates after builtin.pql dep; 4 tests; CHANGELOG entry. The graph is now REACHABLE end-to-end (21 graph tests green). REMAINING (T-323 enrichment): pan/zoom on the view; filter controls (tag include/exclude, glob, depth-from-active).
|
||||||
|
|
||||||
|
COMPLETE (2026-07-02, session 2). All scope delivered + tested (56 graph tests, make test green, real-boot verified via testmode). Slices this session: GraphController (3b67725b), pane shell (6fae1bc4), extension+i18n registration (a5acb6ac), pan+zoom (e6556401), testmode coverage (46d9b403), filter model (f859173b), filter bar (aabec87d). Final feature: force-directed vault graph in the context panel (graph.view, D-47) — hover-highlight, click-to-open, scroll-zoom, drag-pan, and filters (path glob re-queries pql; depth-from-active local graph; tri-state tag include/exclude). Controller uses pql.meta (outlinks+tags in one call) and strips #heading fragments so heading links connect. NOTE: pql data load is 1 files + N meta calls (sequential); batching is a future optimisation if large vaults feel slow.', 'done', 'medium', NULL, NULL, NULL, '2026-06-10 11:17:23', '2026-07-02 19:47:44.357', NULL, '4d534c5ebbc8245ac9cdf1c41ddfca06', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2G1WD1839Z90AQ5C0BHNV4', 'story', '06FHAX7FV5KWGZQ31617R63W94', 'Tier-5 canvas pane (builtin.canvas)', 'Tier-5 canvas PANE, absorbed from the former T-7 into the unified canvas epic (T-317, decision D-91). A full workspace pane that renders .canvas files by CONVERTING them into the drawing-card JSON (per D-91: .canvas is an import format, not a native schema) and painting via the shared canvas renderer (T-318). Scope: nodes (note, text, group, image) + edges + layout state; pan/zoom; node selection, drag, resize; edit affordances (add note from file picker, add text node, draw edge between nodes); persist layout back to the .canvas file on disk. Uses MultitabPane (T-83) for tabs and its own slot per D-47; panels are extension-shaped (D-17). Depends on the core renderer (T-318). NOTE: unlike the conversation drawing card (display-only, D-78), this pane is interactive/editable — it is a pane, not a conversation widget.
|
||||||
|
|
||||||
|
SCOPE NOTE (2026-06-29): currently a 17-line stub. This is a from-scratch interactive Tier-5 pane (parse .canvas -> drawing-card JSON, CustomPaint render, pan/zoom, node select/drag/resize, edit affordances, persist .canvas) — a multi-session feature, NOT template-class work. The drawing-card TEMPLATE half of epic T-317 is now complete (svg/d2/image/icon/compare/graph + stdin).
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02): two foundation slices built + tested (from the 17-line stub). (1) JSONCanvas parser/model — lib/src/canvas/json_canvas.dart (2eb5d0f1): typed CanvasDoc (text/file/link/group nodes + edges with sides/ends/color/label), parse + toJson round-trip, skips unknown/malformed; pure Dart, 8 dart-test cases. (2) CustomPaint renderer — lib/builtin/canvas/src/canvas_painter.dart (035a37a1): CanvasBounds + pan/zoom CanvasViewport, group frames + edges (arrowheads) + node cards; node colours from the file (Obsidian presets/hex, NOT clide tokens per arbitrary-content rule), chrome themed; 7 tests (pixel-probe + viewport + colour). DECISION NOTE: the interactive pane paints the CanvasDoc model directly via CustomPaint (hit-testable, cheap re-paint) rather than re-lowering to SVG each frame — the ticket''s ''convert to drawing-card JSON'' path (D-91 SVG substrate) is for the display-only viewer; an editable pane needs direct model painting. Mirrors the graph pane. REMAINING (multi-session): interactive CanvasView (hit-test nodes + pan/zoom + click-select), pane shell (load .canvas from disk, workspace slot D-47, MultitabPane), CanvasExtension registration + open-.canvas routing, then edit affordances (add node/edge, drag, resize) + persist back to disk.', 'backlog', 'medium', NULL, NULL, NULL, '2026-06-10 11:17:17', '2026-07-02 20:27:03.493', NULL, '163772c5b568c9fb0b69715648555c30', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FJ91RYFXBJH99HJ18QTHY2B0', 'bug', '06FB0TNQM5TWC00GW0P3X02HZW', 'Model switch + effort toggle: unclear UI feedback', NULL, 'backlog', 'medium', NULL, NULL, NULL, '2026-07-02 20:31:02.783', '2026-07-02 20:31:02.783', NULL, '931821336de8bd9ca5e77cd62f3ca1d3', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FJ91RYFXBJH99HJ18QTHY2B0', 'bug', '06FB0TNQM5TWC00GW0P3X02HZW', 'Model switch + effort toggle: unclear UI feedback', 'REPORTED (2026-07-02, Jeroen): can''t trust that the model switch and the effort toggle actually took effect when used — the UI feedback + positioning leave it uncertain whether the change applied. INVESTIGATE: what confirmation (if any) fires today when the model or effort is changed, and where it surfaces relative to the control. Likely-related surfaces: the Config tab controls (T-414), /effort ownership (T-412), account/model settings control. IMPROVE: give an unmistakable, well-positioned confirmation that the change landed — e.g. the control reflects the new value immediately (selected state), and/or a brief toast/inline acknowledgement near the control, not somewhere the eye isn''t. Goal: after a switch, the user is certain which model/effort is now active.', 'backlog', 'medium', NULL, NULL, NULL, '2026-07-02 20:31:02.783', '2026-07-02 20:31:02.806', NULL, 'b4e300bee467ba284a30772cb7a186bb', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2G1WD1839Z90AQ5C0BHNV4', 'story', '06FHAX7FV5KWGZQ31617R63W94', 'Tier-5 canvas pane (builtin.canvas)', 'Tier-5 canvas PANE, absorbed from the former T-7 into the unified canvas epic (T-317, decision D-91). A full workspace pane that renders .canvas files by CONVERTING them into the drawing-card JSON (per D-91: .canvas is an import format, not a native schema) and painting via the shared canvas renderer (T-318). Scope: nodes (note, text, group, image) + edges + layout state; pan/zoom; node selection, drag, resize; edit affordances (add note from file picker, add text node, draw edge between nodes); persist layout back to the .canvas file on disk. Uses MultitabPane (T-83) for tabs and its own slot per D-47; panels are extension-shaped (D-17). Depends on the core renderer (T-318). NOTE: unlike the conversation drawing card (display-only, D-78), this pane is interactive/editable — it is a pane, not a conversation widget.
|
||||||
|
|
||||||
|
SCOPE NOTE (2026-06-29): currently a 17-line stub. This is a from-scratch interactive Tier-5 pane (parse .canvas -> drawing-card JSON, CustomPaint render, pan/zoom, node select/drag/resize, edit affordances, persist .canvas) — a multi-session feature, NOT template-class work. The drawing-card TEMPLATE half of epic T-317 is now complete (svg/d2/image/icon/compare/graph + stdin).
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02): two foundation slices built + tested (from the 17-line stub). (1) JSONCanvas parser/model — lib/src/canvas/json_canvas.dart (2eb5d0f1): typed CanvasDoc (text/file/link/group nodes + edges with sides/ends/color/label), parse + toJson round-trip, skips unknown/malformed; pure Dart, 8 dart-test cases. (2) CustomPaint renderer — lib/builtin/canvas/src/canvas_painter.dart (035a37a1): CanvasBounds + pan/zoom CanvasViewport, group frames + edges (arrowheads) + node cards; node colours from the file (Obsidian presets/hex, NOT clide tokens per arbitrary-content rule), chrome themed; 7 tests (pixel-probe + viewport + colour). DECISION NOTE: the interactive pane paints the CanvasDoc model directly via CustomPaint (hit-testable, cheap re-paint) rather than re-lowering to SVG each frame — the ticket''s ''convert to drawing-card JSON'' path (D-91 SVG substrate) is for the display-only viewer; an editable pane needs direct model painting. Mirrors the graph pane. REMAINING (multi-session): interactive CanvasView (hit-test nodes + pan/zoom + click-select), pane shell (load .canvas from disk, workspace slot D-47, MultitabPane), CanvasExtension registration + open-.canvas routing, then edit affordances (add node/edge, drag, resize) + persist back to disk.', 'in_progress', 'medium', NULL, NULL, NULL, '2026-06-10 11:17:17', '2026-07-02 20:35:12.739', NULL, '3e2c84564d3b6cf59f8c8f0e8af1b0b5', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FJ91RYFXBJH99HJ18QTHY2B0', 'bug', '06FB0TNQM5TWC00GW0P3X02HZW', 'Model switch + effort toggle: unclear UI feedback', 'REPORTED (2026-07-02, Jeroen): can''t trust that the model switch and the effort toggle actually took effect when used — the UI feedback + positioning leave it uncertain whether the change applied. INVESTIGATE: what confirmation (if any) fires today when the model or effort is changed, and where it surfaces relative to the control. Likely-related surfaces: the Config tab controls (T-414), /effort ownership (T-412), account/model settings control. IMPROVE: give an unmistakable, well-positioned confirmation that the change landed — e.g. the control reflects the new value immediately (selected state), and/or a brief toast/inline acknowledgement near the control, not somewhere the eye isn''t. Goal: after a switch, the user is certain which model/effort is now active.
|
||||||
|
|
||||||
|
EVIDENCE + ROOT CAUSE (2026-07-02, from a /model screenshot). The confirmation renders as a raw, unstyled line: literally ''<local-command-stdout>Set model to claude-fable-5[1m] (claude-fable-5)</local-command-stdout>'', shown under the ''you'' (user) speaker stripe. Three distinct defects in that one line: (a) the CLI''s <local-command-stdout> wrapper tag is displayed verbatim instead of being unwrapped; (b) an ANSI SGR bold code leaks through as literal ''[1m]'' (a \x1b[1m) — slash-command stdout is not ANSI-stripped; (c) it is attributed to the USER speaker, so a system/command acknowledgement masquerades as something the user typed. ROOT CAUSE: clide has NO handling for local-command-stdout at all (grep in lib/ = zero hits) — the slash-command result falls through and is rendered as plain user prose. ENTRY POINTS for the fix: inbound message parse / role attribution in lib/builtin/claude/src/transcript_reader.dart; existing ANSI-strip refs in transcript_reader.dart + claude_composer.dart. IMPROVE: detect local-command-stdout content, unwrap the tag + strip ANSI, and render it as a distinct, clearly-positioned system/command-acknowledgement (NOT the user stripe) so a /model or /effort change is an unmistakable confirmation. Affects all slash-command stdout (model, effort, etc.), so fix at the render/parse path, not per-command.', 'backlog', 'medium', NULL, NULL, NULL, '2026-07-02 20:31:02.783', '2026-07-02 20:39:06.684', NULL, '8678946b438ae5cbdff677bb73949374', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FJ91RYFXBJH99HJ18QTHY2B0', 'bug', '06FB0TNQM5TWC00GW0P3X02HZW', 'Model switch + effort toggle: unclear UI feedback', 'REPORTED (2026-07-02, Jeroen): can''t trust that the model switch and the effort toggle actually took effect when used — the UI feedback + positioning leave it uncertain whether the change applied. INVESTIGATE: what confirmation (if any) fires today when the model or effort is changed, and where it surfaces relative to the control. Likely-related surfaces: the Config tab controls (T-414), /effort ownership (T-412), account/model settings control. IMPROVE: give an unmistakable, well-positioned confirmation that the change landed — e.g. the control reflects the new value immediately (selected state), and/or a brief toast/inline acknowledgement near the control, not somewhere the eye isn''t. Goal: after a switch, the user is certain which model/effort is now active.
|
||||||
|
|
||||||
|
EVIDENCE + ROOT CAUSE (2026-07-02, from a /model screenshot). The confirmation renders as a raw, unstyled line: literally ''<local-command-stdout>Set model to claude-fable-5[1m] (claude-fable-5)</local-command-stdout>'', shown under the ''you'' (user) speaker stripe. Three distinct defects in that one line: (a) the CLI''s <local-command-stdout> wrapper tag is displayed verbatim instead of being unwrapped; (b) an ANSI SGR bold code leaks through as literal ''[1m]'' (a \x1b[1m) — slash-command stdout is not ANSI-stripped; (c) it is attributed to the USER speaker, so a system/command acknowledgement masquerades as something the user typed. ROOT CAUSE: clide has NO handling for local-command-stdout at all (grep in lib/ = zero hits) — the slash-command result falls through and is rendered as plain user prose. ENTRY POINTS for the fix: inbound message parse / role attribution in lib/builtin/claude/src/transcript_reader.dart; existing ANSI-strip refs in transcript_reader.dart + claude_composer.dart. IMPROVE: detect local-command-stdout content, unwrap the tag + strip ANSI, and render it as a distinct, clearly-positioned system/command-acknowledgement (NOT the user stripe) so a /model or /effort change is an unmistakable confirmation. Affects all slash-command stdout (model, effort, etc.), so fix at the render/parse path, not per-command.
|
||||||
|
|
||||||
|
SCOPE (do not narrow): the local-command-stdout rendering defect above is ONE symptom, not the whole ticket. The core problem is that after switching model or effort the user has no reliable, well-placed signal that it took effect — so this stays a broad investigate-and-improve of the switch/toggle trust UX, with the render bug as just the first concrete instance. Other symptoms/questions to investigate (non-exhaustive): does the control itself (Config tab picker / effort control / any menu) visibly update to the NEW active value after a switch, or does it look unchanged? is there ANY acknowledgement at the point of interaction, or only (mangled) output buried in the transcript far from where the user clicked? do model vs effort behave consistently, or differently? can clide''s shown ''active'' value drift from what actually took effect (e.g. a switch that silently no-ops)? is the confirmation positioned where the eye already is? The deliverable is: across all these controls, a consistent and unmistakable ''this is now active'' — fixing the render path is necessary but not sufficient. Enumerate the full symptom set during investigation before designing the fix.', 'backlog', 'medium', NULL, NULL, NULL, '2026-07-02 20:31:02.783', '2026-07-02 20:41:13.402', NULL, '9c7b3632bd0846533a1b65cc12b8145a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2G1WD1839Z90AQ5C0BHNV4', 'story', '06FHAX7FV5KWGZQ31617R63W94', 'Tier-5 canvas pane (builtin.canvas)', 'Tier-5 canvas PANE, absorbed from the former T-7 into the unified canvas epic (T-317, decision D-91). A full workspace pane that renders .canvas files by CONVERTING them into the drawing-card JSON (per D-91: .canvas is an import format, not a native schema) and painting via the shared canvas renderer (T-318). Scope: nodes (note, text, group, image) + edges + layout state; pan/zoom; node selection, drag, resize; edit affordances (add note from file picker, add text node, draw edge between nodes); persist layout back to the .canvas file on disk. Uses MultitabPane (T-83) for tabs and its own slot per D-47; panels are extension-shaped (D-17). Depends on the core renderer (T-318). NOTE: unlike the conversation drawing card (display-only, D-78), this pane is interactive/editable — it is a pane, not a conversation widget.
|
||||||
|
|
||||||
|
SCOPE NOTE (2026-06-29): currently a 17-line stub. This is a from-scratch interactive Tier-5 pane (parse .canvas -> drawing-card JSON, CustomPaint render, pan/zoom, node select/drag/resize, edit affordances, persist .canvas) — a multi-session feature, NOT template-class work. The drawing-card TEMPLATE half of epic T-317 is now complete (svg/d2/image/icon/compare/graph + stdin).
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02): two foundation slices built + tested (from the 17-line stub). (1) JSONCanvas parser/model — lib/src/canvas/json_canvas.dart (2eb5d0f1): typed CanvasDoc (text/file/link/group nodes + edges with sides/ends/color/label), parse + toJson round-trip, skips unknown/malformed; pure Dart, 8 dart-test cases. (2) CustomPaint renderer — lib/builtin/canvas/src/canvas_painter.dart (035a37a1): CanvasBounds + pan/zoom CanvasViewport, group frames + edges (arrowheads) + node cards; node colours from the file (Obsidian presets/hex, NOT clide tokens per arbitrary-content rule), chrome themed; 7 tests (pixel-probe + viewport + colour). DECISION NOTE: the interactive pane paints the CanvasDoc model directly via CustomPaint (hit-testable, cheap re-paint) rather than re-lowering to SVG each frame — the ticket''s ''convert to drawing-card JSON'' path (D-91 SVG substrate) is for the display-only viewer; an editable pane needs direct model painting. Mirrors the graph pane. REMAINING (multi-session): interactive CanvasView (hit-test nodes + pan/zoom + click-select), pane shell (load .canvas from disk, workspace slot D-47, MultitabPane), CanvasExtension registration + open-.canvas routing, then edit affordances (add node/edge, drag, resize) + persist back to disk.
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02, cont.): third foundation slice landed — interactive CanvasView (lib/builtin/canvas/src/canvas_view.dart, 7700fc7a): hitTestCanvasNode (topmost node under a point; cards beat the group frames behind, via the painter''s own viewport) + scroll-zoom + drag-pan + click-select with a focus ring; 6 tests. The canvas rendering + interaction FOUNDATION is now complete + tested (parser 2eb5d0f1, renderer 035a37a1, view 7700fc7a — 21 canvas tests), mirroring where T-323''s foundation was before its integration phase. NOT yet reachable. REACHABLE-INTEGRATION PHASE (next, fresh session): (a) pane shell — a StatefulWidget that loads a .canvas from disk (files.read/editor.open path), holds the CanvasDoc, embeds CanvasView; (b) CanvasExtension registration as a workspace pane (own slot D-47, MultitabPane T-83); (c) FILE-OPEN ROUTING — how opening a .canvas lands in this pane instead of the text editor: NOTE the TabContribution.fileGlobs field is DECLARED but has ZERO consumers in lib/, so this routing must be built (wire fileGlobs, or have the editor delegate by extension, or a command + workspace tab); (d) i18n + tests. THEN the edit phase: add node/text/edge affordances, node drag + resize, and persist the CanvasDoc back to the .canvas file (encode() already exists).', 'in_progress', 'medium', NULL, NULL, NULL, '2026-06-10 11:17:17', '2026-07-02 21:22:59.395', NULL, '6ba2a2c1892dbf56c582f83bd9753314', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2G1WD1839Z90AQ5C0BHNV4', 'story', '06FHAX7FV5KWGZQ31617R63W94', 'Tier-5 canvas pane (builtin.canvas)', 'Tier-5 canvas PANE, absorbed from the former T-7 into the unified canvas epic (T-317, decision D-91). A full workspace pane that renders .canvas files by CONVERTING them into the drawing-card JSON (per D-91: .canvas is an import format, not a native schema) and painting via the shared canvas renderer (T-318). Scope: nodes (note, text, group, image) + edges + layout state; pan/zoom; node selection, drag, resize; edit affordances (add note from file picker, add text node, draw edge between nodes); persist layout back to the .canvas file on disk. Uses MultitabPane (T-83) for tabs and its own slot per D-47; panels are extension-shaped (D-17). Depends on the core renderer (T-318). NOTE: unlike the conversation drawing card (display-only, D-78), this pane is interactive/editable — it is a pane, not a conversation widget.
|
||||||
|
|
||||||
|
SCOPE NOTE (2026-06-29): currently a 17-line stub. This is a from-scratch interactive Tier-5 pane (parse .canvas -> drawing-card JSON, CustomPaint render, pan/zoom, node select/drag/resize, edit affordances, persist .canvas) — a multi-session feature, NOT template-class work. The drawing-card TEMPLATE half of epic T-317 is now complete (svg/d2/image/icon/compare/graph + stdin).
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02): two foundation slices built + tested (from the 17-line stub). (1) JSONCanvas parser/model — lib/src/canvas/json_canvas.dart (2eb5d0f1): typed CanvasDoc (text/file/link/group nodes + edges with sides/ends/color/label), parse + toJson round-trip, skips unknown/malformed; pure Dart, 8 dart-test cases. (2) CustomPaint renderer — lib/builtin/canvas/src/canvas_painter.dart (035a37a1): CanvasBounds + pan/zoom CanvasViewport, group frames + edges (arrowheads) + node cards; node colours from the file (Obsidian presets/hex, NOT clide tokens per arbitrary-content rule), chrome themed; 7 tests (pixel-probe + viewport + colour). DECISION NOTE: the interactive pane paints the CanvasDoc model directly via CustomPaint (hit-testable, cheap re-paint) rather than re-lowering to SVG each frame — the ticket''s ''convert to drawing-card JSON'' path (D-91 SVG substrate) is for the display-only viewer; an editable pane needs direct model painting. Mirrors the graph pane. REMAINING (multi-session): interactive CanvasView (hit-test nodes + pan/zoom + click-select), pane shell (load .canvas from disk, workspace slot D-47, MultitabPane), CanvasExtension registration + open-.canvas routing, then edit affordances (add node/edge, drag, resize) + persist back to disk.
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02, cont.): third foundation slice landed — interactive CanvasView (lib/builtin/canvas/src/canvas_view.dart, 7700fc7a): hitTestCanvasNode (topmost node under a point; cards beat the group frames behind, via the painter''s own viewport) + scroll-zoom + drag-pan + click-select with a focus ring; 6 tests. The canvas rendering + interaction FOUNDATION is now complete + tested (parser 2eb5d0f1, renderer 035a37a1, view 7700fc7a — 21 canvas tests), mirroring where T-323''s foundation was before its integration phase. NOT yet reachable. REACHABLE-INTEGRATION PHASE (next, fresh session): (a) pane shell — a StatefulWidget that loads a .canvas from disk (files.read/editor.open path), holds the CanvasDoc, embeds CanvasView; (b) CanvasExtension registration as a workspace pane (own slot D-47, MultitabPane T-83); (c) FILE-OPEN ROUTING — how opening a .canvas lands in this pane instead of the text editor: NOTE the TabContribution.fileGlobs field is DECLARED but has ZERO consumers in lib/, so this routing must be built (wire fileGlobs, or have the editor delegate by extension, or a command + workspace tab); (d) i18n + tests. THEN the edit phase: add node/text/edge affordances, node drag + resize, and persist the CanvasDoc back to the .canvas file (encode() already exists).
|
||||||
|
|
||||||
|
Refinement (2026-07-03, user-confirmed): (1) SLOT: Slots.workspace — diff/editor recipe, center column; coexists with Claude the way diff does (D-47). (2) TABS: real MultitabPane<CanvasDoc> — N .canvas files open as tabs (user explicitly chose over the single-TabContribution graph/diff precedent; needs MultitabController plumbing like Claude sessions). (3) FILE-OPEN ROUTING resolved by inspection: TabContribution.fileGlobs is dead (zero consumers) — do NOT wire it. Add a .canvas branch in lib/kernel/src/file_open.dart openWorkspaceFile() publishing to ''builtin.canvas''/''selection'' (mirror of the .md branch), and D-6 CLI parity via a ''canvas'' entry in the _readers map at lib/src/daemon/ui_command.dart:34 → clide ui open canvas <path> (diff precedent). (4) Fix stale doc header lib/src/canvas/json_canvas.dart:5-7 (claims SVG-lowering; actual architecture paints CanvasDoc directly per the ticket''s DECISION NOTE) in the same pass. (5) Edit phase later needs a mutation path (CanvasView has no onChanged; CanvasDoc is immutable-construction only) — deferred, flagged now.', 'in_progress', 'medium', NULL, NULL, NULL, '2026-06-10 11:17:17', '2026-07-03 20:20:00.827', NULL, '34eeab12879a55e77e6c9841a442cf27', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2G1WD1839Z90AQ5C0BHNV4', 'story', '06FHAX7FV5KWGZQ31617R63W94', 'Tier-5 canvas pane (builtin.canvas)', 'Tier-5 canvas PANE, absorbed from the former T-7 into the unified canvas epic (T-317, decision D-91). A full workspace pane that renders .canvas files by CONVERTING them into the drawing-card JSON (per D-91: .canvas is an import format, not a native schema) and painting via the shared canvas renderer (T-318). Scope: nodes (note, text, group, image) + edges + layout state; pan/zoom; node selection, drag, resize; edit affordances (add note from file picker, add text node, draw edge between nodes); persist layout back to the .canvas file on disk. Uses MultitabPane (T-83) for tabs and its own slot per D-47; panels are extension-shaped (D-17). Depends on the core renderer (T-318). NOTE: unlike the conversation drawing card (display-only, D-78), this pane is interactive/editable — it is a pane, not a conversation widget.
|
||||||
|
|
||||||
|
SCOPE NOTE (2026-06-29): currently a 17-line stub. This is a from-scratch interactive Tier-5 pane (parse .canvas -> drawing-card JSON, CustomPaint render, pan/zoom, node select/drag/resize, edit affordances, persist .canvas) — a multi-session feature, NOT template-class work. The drawing-card TEMPLATE half of epic T-317 is now complete (svg/d2/image/icon/compare/graph + stdin).
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02): two foundation slices built + tested (from the 17-line stub). (1) JSONCanvas parser/model — lib/src/canvas/json_canvas.dart (2eb5d0f1): typed CanvasDoc (text/file/link/group nodes + edges with sides/ends/color/label), parse + toJson round-trip, skips unknown/malformed; pure Dart, 8 dart-test cases. (2) CustomPaint renderer — lib/builtin/canvas/src/canvas_painter.dart (035a37a1): CanvasBounds + pan/zoom CanvasViewport, group frames + edges (arrowheads) + node cards; node colours from the file (Obsidian presets/hex, NOT clide tokens per arbitrary-content rule), chrome themed; 7 tests (pixel-probe + viewport + colour). DECISION NOTE: the interactive pane paints the CanvasDoc model directly via CustomPaint (hit-testable, cheap re-paint) rather than re-lowering to SVG each frame — the ticket''s ''convert to drawing-card JSON'' path (D-91 SVG substrate) is for the display-only viewer; an editable pane needs direct model painting. Mirrors the graph pane. REMAINING (multi-session): interactive CanvasView (hit-test nodes + pan/zoom + click-select), pane shell (load .canvas from disk, workspace slot D-47, MultitabPane), CanvasExtension registration + open-.canvas routing, then edit affordances (add node/edge, drag, resize) + persist back to disk.
|
||||||
|
|
||||||
|
PROGRESS (2026-07-02, cont.): third foundation slice landed — interactive CanvasView (lib/builtin/canvas/src/canvas_view.dart, 7700fc7a): hitTestCanvasNode (topmost node under a point; cards beat the group frames behind, via the painter''s own viewport) + scroll-zoom + drag-pan + click-select with a focus ring; 6 tests. The canvas rendering + interaction FOUNDATION is now complete + tested (parser 2eb5d0f1, renderer 035a37a1, view 7700fc7a — 21 canvas tests), mirroring where T-323''s foundation was before its integration phase. NOT yet reachable. REACHABLE-INTEGRATION PHASE (next, fresh session): (a) pane shell — a StatefulWidget that loads a .canvas from disk (files.read/editor.open path), holds the CanvasDoc, embeds CanvasView; (b) CanvasExtension registration as a workspace pane (own slot D-47, MultitabPane T-83); (c) FILE-OPEN ROUTING — how opening a .canvas lands in this pane instead of the text editor: NOTE the TabContribution.fileGlobs field is DECLARED but has ZERO consumers in lib/, so this routing must be built (wire fileGlobs, or have the editor delegate by extension, or a command + workspace tab); (d) i18n + tests. THEN the edit phase: add node/text/edge affordances, node drag + resize, and persist the CanvasDoc back to the .canvas file (encode() already exists).
|
||||||
|
|
||||||
|
Refinement (2026-07-03, user-confirmed): (1) SLOT: Slots.workspace — diff/editor recipe, center column; coexists with Claude the way diff does (D-47). (2) TABS: real MultitabPane<CanvasDoc> — N .canvas files open as tabs (user explicitly chose over the single-TabContribution graph/diff precedent; needs MultitabController plumbing like Claude sessions). (3) FILE-OPEN ROUTING resolved by inspection: TabContribution.fileGlobs is dead (zero consumers) — do NOT wire it. Add a .canvas branch in lib/kernel/src/file_open.dart openWorkspaceFile() publishing to ''builtin.canvas''/''selection'' (mirror of the .md branch), and D-6 CLI parity via a ''canvas'' entry in the _readers map at lib/src/daemon/ui_command.dart:34 → clide ui open canvas <path> (diff precedent). (4) Fix stale doc header lib/src/canvas/json_canvas.dart:5-7 (claims SVG-lowering; actual architecture paints CanvasDoc directly per the ticket''s DECISION NOTE) in the same pass. (5) Edit phase later needs a mutation path (CanvasView has no onChanged; CanvasDoc is immutable-construction only) — deferred, flagged now.
|
||||||
|
|
||||||
|
PROGRESS (2026-07-05): REACHABLE-INTEGRATION PHASE COMPLETE (e2e305de). CanvasExtension is a real workspace pane: app-scoped MultitabController on the extension (diff/T-233 pattern) with real per-document sub-tabs (MultitabPane keepAlive, per refinement decision), CanvasPaneHost + CanvasDocumentTab (files.read -> CanvasDoc.parse -> CanvasView; loading/error states), routing wired (openWorkspaceFile .canvas branch; ui.open ''canvas'' reader so clide ui open canvas <path> works; fileGlobs left dead as decided), en_us+nl_nl catalogs, json_canvas doc header corrected. Tests: extension lifecycle (7), pane-host widget (6), file_open routing (5, new file), ui_command canvas case; testmode extension roster now includes builtin.canvas (26/26 real-boot pass). REMAINING (edit phase, fresh session): node drag + resize, add note/text/edge affordances, persist CanvasDoc back to disk — encode() exists; CanvasView needs an onChanged/mutation path (refinement note item 5).', 'in_progress', 'medium', NULL, NULL, NULL, '2026-06-10 11:17:17', '2026-07-05 07:29:15.447', NULL, '1be84ba4d4357171ef329f39b601f4e1', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FK3CDZQD2JM95ZQY5MH53PWC', 'task', '06FB0TNQM5TWC00GW0P3X02HZW', 'Composer bypass reachability: Ctrl/Cmd+Shift+M full cycle + shift-click bypass row', 'User decision (2026-07-05), amending T-226''s refinement wording: the original intent was Ctrl/Cmd+Shift+M cycling the FULL permission-mode list including bypassPermissions, with plain Ctrl/Cmd+M keeping the safe trio (default/acceptEdits/plan). Holding shift IS the explicit opt-in gesture — no separate confirm needed. Likewise the composer mode popup (T-275): the bypass row is currently permanently disabled, pointing at ''the cockpit''s confirmed path'' (T-181 roster shift-click) — but that roster is ghost-fed (T-396, TeamMemberJoined never emitted in production), so bypass is unreachable from the primary session''s UI entirely; a visible-but-unreachable option is worse than none. Scope: (1) claude_status: kFullPermissionCycle + nextPermissionMode(); (2) composer key handler: mod+shift+M -> full cycle, mod+M (no shift) -> safe trio; (3) PermissionModeControl: bypass row enabled behind a shift-click gate (plain click no-ops, menu stays open; shift-click selects + closes), trailing ''shift-click'' hint, semantics + tooltip updated; (4) i18n en+nl; (5) tests. The /permissions picker and roster badge paths are unchanged. Refs T-226, T-275, T-181, T-396.', 'backlog', 'medium', NULL, NULL, NULL, '2026-07-05 09:52:40.379', '2026-07-05 09:52:40.379', NULL, 'ec1eed07c9a69b4edbf3f4ffe671f696', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FK3CDZQD2JM95ZQY5MH53PWC', 'task', '06FB0TNQM5TWC00GW0P3X02HZW', 'Composer bypass reachability: Ctrl/Cmd+Shift+M full cycle + shift-click bypass row', 'User decision (2026-07-05), amending T-226''s refinement wording: the original intent was Ctrl/Cmd+Shift+M cycling the FULL permission-mode list including bypassPermissions, with plain Ctrl/Cmd+M keeping the safe trio (default/acceptEdits/plan). Holding shift IS the explicit opt-in gesture — no separate confirm needed. Likewise the composer mode popup (T-275): the bypass row is currently permanently disabled, pointing at ''the cockpit''s confirmed path'' (T-181 roster shift-click) — but that roster is ghost-fed (T-396, TeamMemberJoined never emitted in production), so bypass is unreachable from the primary session''s UI entirely; a visible-but-unreachable option is worse than none. Scope: (1) claude_status: kFullPermissionCycle + nextPermissionMode(); (2) composer key handler: mod+shift+M -> full cycle, mod+M (no shift) -> safe trio; (3) PermissionModeControl: bypass row enabled behind a shift-click gate (plain click no-ops, menu stays open; shift-click selects + closes), trailing ''shift-click'' hint, semantics + tooltip updated; (4) i18n en+nl; (5) tests. The /permissions picker and roster badge paths are unchanged. Refs T-226, T-275, T-181, T-396.', 'in_progress', 'medium', NULL, NULL, NULL, '2026-07-05 09:52:40.379', '2026-07-05 09:52:54.013', NULL, '56204043cd686ca0fcae06db735b72ef', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FK3CDZQD2JM95ZQY5MH53PWC', 'task', '06FB0TNQM5TWC00GW0P3X02HZW', 'Composer bypass reachability: Ctrl/Cmd+Shift+M full cycle + shift-click bypass row', 'User decision (2026-07-05), amending T-226''s refinement wording: the original intent was Ctrl/Cmd+Shift+M cycling the FULL permission-mode list including bypassPermissions, with plain Ctrl/Cmd+M keeping the safe trio (default/acceptEdits/plan). Holding shift IS the explicit opt-in gesture — no separate confirm needed. Likewise the composer mode popup (T-275): the bypass row is currently permanently disabled, pointing at ''the cockpit''s confirmed path'' (T-181 roster shift-click) — but that roster is ghost-fed (T-396, TeamMemberJoined never emitted in production), so bypass is unreachable from the primary session''s UI entirely; a visible-but-unreachable option is worse than none. Scope: (1) claude_status: kFullPermissionCycle + nextPermissionMode(); (2) composer key handler: mod+shift+M -> full cycle, mod+M (no shift) -> safe trio; (3) PermissionModeControl: bypass row enabled behind a shift-click gate (plain click no-ops, menu stays open; shift-click selects + closes), trailing ''shift-click'' hint, semantics + tooltip updated; (4) i18n en+nl; (5) tests. The /permissions picker and roster badge paths are unchanged. Refs T-226, T-275, T-181, T-396.', 'done', 'medium', NULL, NULL, NULL, '2026-07-05 09:52:40.379', '2026-07-05 10:54:23.532', NULL, '143695c5eefa42dab2c05edcb06a4427', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FNR3DP0D48AZZ3NRA8JF3Q10', 'task', NULL, 'Per-workspace PATH preset: settings + CLI (env.path) + spawn injection, worktree-aware (FR-1)', NULL, 'backlog', 'high', NULL, NULL, 'D-106', '2026-07-13 15:17:10.275', '2026-07-13 15:17:10.275', NULL, 'eb6abfb644234fe0c73b4785efcdad16', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FNR3DP0D48AZZ3NRA8JF3Q10', 'task', NULL, 'Per-workspace PATH preset: settings + CLI (env.path) + spawn injection, worktree-aware (FR-1)', NULL, 'in_progress', 'high', NULL, NULL, 'D-106', '2026-07-13 15:17:10.275', '2026-07-13 15:17:17.532', NULL, '6e4b7347d0e854ea4c5fe4b394c61412', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FNR3DP0D48AZZ3NRA8JF3Q10', 'task', NULL, 'Per-workspace PATH preset: settings + CLI (env.path) + spawn injection, worktree-aware (FR-1)', 'Implements D-106 (FR-1 + worktree addendum). Storage: user-scope key app.env.pathPrepend.<fnv1a64Hex(canonicalWorkspaceKey(presetRoot))> in ~/.config/clide/settings.yaml — never committed; presetRootFor() resolves a linked-worktree workspace (gitdir: pointer file, e.g. .worktrees/<name>) to the main repo root so all worktrees share the repo''s preset.
|
||||||
|
|
||||||
|
Injection (prepend, dedup, next-spawn semantics): PTY panes via PaneRegistry.pathForSpawn hook (main.dart wires the preset-aware closure); hosted Claude via agentEnvDelta(prependDirs:) — now exports PATH whenever a preset exists even if clide is already on PATH (previous gap) — threaded orchestrator.pathPresetFor ← claude extension ← ctx.settings. Toolchain/supporter-binary resolution deliberately preset-blind (T-98/D-92 fence).
|
||||||
|
|
||||||
|
CLI (D-6): one cmd id env.path → clide env path list|set|add|remove|clear|capture; Flutter-free handler lib/src/daemon/env_path_commands.dart over an injected PathPresetStore port (adapter in main.dart); mutations publish on envPathChannel; capture diffs loginShellPathOrNull() (new shell_env getter) vs process PATH. UI: Settings → Tools → Workspace PATH section, custom control (ordered list, add/remove/reorder, missing-dir warning, worktree note, capture suggestions) in builtin.tools-settings; en+nl catalogs.
|
||||||
|
|
||||||
|
.worktrees/ added to IgnoreSet.builtin() and the project-init gitignore scaffold. Tests: path_preset_test (pure fns + real worktree layout), env_path_commands_test (all verbs), agent_bootstrap prependDirs cases, PaneRegistry pathForSpawn PTY test, widget tests for the control incl. worktree key sharing + capture. make test (4048) + make test-a11y green.', 'in_progress', 'high', NULL, NULL, 'D-106', '2026-07-13 15:17:10.275', '2026-07-13 15:39:31.309', NULL, 'c5a978f32c7497e478c471069ed20b7c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FNR3DP0D48AZZ3NRA8JF3Q10', 'task', NULL, 'Per-workspace PATH preset: settings + CLI (env.path) + spawn injection, worktree-aware (FR-1)', 'Implements D-106 (FR-1 + worktree addendum). Storage: user-scope key app.env.pathPrepend.<fnv1a64Hex(canonicalWorkspaceKey(presetRoot))> in ~/.config/clide/settings.yaml — never committed; presetRootFor() resolves a linked-worktree workspace (gitdir: pointer file, e.g. .worktrees/<name>) to the main repo root so all worktrees share the repo''s preset.
|
||||||
|
|
||||||
|
Injection (prepend, dedup, next-spawn semantics): PTY panes via PaneRegistry.pathForSpawn hook (main.dart wires the preset-aware closure); hosted Claude via agentEnvDelta(prependDirs:) — now exports PATH whenever a preset exists even if clide is already on PATH (previous gap) — threaded orchestrator.pathPresetFor ← claude extension ← ctx.settings. Toolchain/supporter-binary resolution deliberately preset-blind (T-98/D-92 fence).
|
||||||
|
|
||||||
|
CLI (D-6): one cmd id env.path → clide env path list|set|add|remove|clear|capture; Flutter-free handler lib/src/daemon/env_path_commands.dart over an injected PathPresetStore port (adapter in main.dart); mutations publish on envPathChannel; capture diffs loginShellPathOrNull() (new shell_env getter) vs process PATH. UI: Settings → Tools → Workspace PATH section, custom control (ordered list, add/remove/reorder, missing-dir warning, worktree note, capture suggestions) in builtin.tools-settings; en+nl catalogs.
|
||||||
|
|
||||||
|
.worktrees/ added to IgnoreSet.builtin() and the project-init gitignore scaffold. Tests: path_preset_test (pure fns + real worktree layout), env_path_commands_test (all verbs), agent_bootstrap prependDirs cases, PaneRegistry pathForSpawn PTY test, widget tests for the control incl. worktree key sharing + capture. make test (4048) + make test-a11y green.', 'done', 'high', NULL, NULL, 'D-106', '2026-07-13 15:17:10.275', '2026-07-13 16:48:56.833', NULL, '09c6b262b3c0ecfd2f621d27f2cc5eb2', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FNTF7KE5Y497PQC7SCFGR1KC', 'task', NULL, 'Lead the clide skill description with clide capabilities + env mechanics (FR-2)', NULL, 'backlog', 'low', NULL, NULL, NULL, '2026-07-13 20:48:23.409', '2026-07-13 20:48:23.409', NULL, '28edb12dfa1f2bf75d108f6cf9465ea5', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FNTF7KE5Y497PQC7SCFGR1KC', 'task', NULL, 'Lead the clide skill description with clide capabilities + env mechanics (FR-2)', NULL, 'done', 'low', NULL, NULL, NULL, '2026-07-13 20:48:23.409', '2026-07-13 20:49:17.282', NULL, 'b7eaec1d037d1c36cf54fac07b3b2dd4', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
@@ -0,0 +1,350 @@
|
|||||||
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FD0ABC7QNEC3XCTV73YPSGR4', 'task', NULL, 'Plumb in Claude Code''s remote-control feature', 'User report 2026-06-16: Claude Code''s **remote-control** feature (start / monitor / steer a running Claude Code session remotely — e.g. from claude.ai or the mobile app) is **not plumbed into clide**.
|
||||||
|
|
||||||
|
clide hosts the `claude` CLI as a stream-json child (`--session-id` / `--resume`, D-77). For remote control to work through clide, a clide-hosted session needs to be discoverable + steerable by the remote-control surface the same way a terminal-launched `claude` is.
|
||||||
|
|
||||||
|
**Step 1 — characterize (don''t assume the mechanism):** determine exactly what Claude Code exposes for remote control on the running CLI version. Likely touch points:
|
||||||
|
- the `~/.claude/sessions/<pid>.json` live-session registry we characterized in T-437 (PID-keyed: sessionId, cwd, version, kind, entrypoint, status) — is this what the remote-control surface enumerates? clide-spawned sessions DO write an entry (we saw `entrypoint: sdk-cli`). Confirm whether clide''s entry is visible/controllable remotely, or whether `entrypoint: sdk-cli` / headless spawn excludes it.
|
||||||
|
- any flag / capability in the `initialize` stream-json probe (T-411/T-151 cache) advertising remote control.
|
||||||
|
- whether enrollment requires the interactive TUI (and so is suppressed under clide''s stream-json spawn).
|
||||||
|
|
||||||
|
**Step 2 — plumb:** wire clide so a clide-hosted session participates in remote control (register correctly / pass the needed flag), and surface its state in the UI (e.g. an indicator that the session is remote-controllable / being driven remotely). If it conflicts with clide''s session ownership (pane pins a session-id, T-156), document the boundary.
|
||||||
|
|
||||||
|
**Open question:** is the goal (a) clide sessions become remotely controllable from claude.ai/mobile, or (b) clide can act as a remote controller of other sessions? Default read is (a). Confirm with the user before building.
|
||||||
|
|
||||||
|
Related: D-77 (stream-json session model), T-437 (sessions registry characterization), T-156 (clide owns session lifecycle), T-411 (capability probe).
|
||||||
|
|
||||||
|
## Step 1 COMPLETE — mechanism characterized and empirically proven (2026-08-07)
|
||||||
|
|
||||||
|
**Goal confirmed as (a):** clide-hosted sessions become remotely controllable from
|
||||||
|
claude.ai / the mobile app. (b) is not in scope.
|
||||||
|
|
||||||
|
### The mechanism is a control_request, not the sessions registry
|
||||||
|
|
||||||
|
The Step-1 hypothesis (that `~/.claude/sessions/<pid>.json` is what the remote
|
||||||
|
surface enumerates) is **wrong**. That registry is incidental. Remote Control is
|
||||||
|
enabled per-session over the stream-json control channel clide already owns.
|
||||||
|
|
||||||
|
Claude Code 2.1.220 ships two bridge integrations:
|
||||||
|
- `[bridge:repl]` — the interactive TUI path (`--remote-control` flag, `/remote-control`)
|
||||||
|
- `[bridge:sdk]` — a **stream-json/SDK path**, which is the one clide needs
|
||||||
|
|
||||||
|
No interactive session, no extra flag, and no CLI changes are required.
|
||||||
|
|
||||||
|
### Wire contract (verified live)
|
||||||
|
|
||||||
|
```
|
||||||
|
→ {"type":"control_request","request_id":"…",
|
||||||
|
"request":{"subtype":"remote_control","enabled":true,"name":"<session name>"}}
|
||||||
|
|
||||||
|
← {"type":"system","subtype":"bridge_state","state":"ready"}
|
||||||
|
← {"type":"control_response","response":{"subtype":"success","response":{
|
||||||
|
"session_url":"https://claude.ai/code/session_0127…",
|
||||||
|
"connect_url":"https://claude.ai/code?environment=",
|
||||||
|
"environment_id":""}}}
|
||||||
|
← {"type":"system","subtype":"bridge_state","state":"connected"}
|
||||||
|
|
||||||
|
→ {"request":{"subtype":"remote_control","enabled":false}} # clean teardown
|
||||||
|
← {"type":"control_response","response":{"subtype":"success"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Proven by probe against clide''s exact spawn flags (`stream_json_session.dart:78`).
|
||||||
|
`ready → connected` in ~420ms. Debug log confirms `[bridge:sdk] State change: ready`
|
||||||
|
then `connected`; transport is CCR v2 over SSE, shared with the repl bridge.
|
||||||
|
|
||||||
|
**Surface `session_url`, not `connect_url`.** `connect_url` came back as
|
||||||
|
`https://claude.ai/code?environment=` with an empty `environment_id` — the
|
||||||
|
environment concept is not populated on the bare-SDK path (it appears to be filled
|
||||||
|
in only when the `claude remote-control` daemon owns a registered directory).
|
||||||
|
`session_url` is the complete, live link. Confirm before building a QR affordance.
|
||||||
|
|
||||||
|
### CLI-side callback surface (from binary analysis)
|
||||||
|
|
||||||
|
| Callback | Effect |
|
||||||
|
|---|---|
|
||||||
|
| `onInboundMessage` | remote message injected as a user turn (tagged `bridgeOrigin`, `clientPlatform`, `origin`) |
|
||||||
|
| `onPermissionResponse` | → `injectControlResponse` — the remote can answer permission prompts |
|
||||||
|
| `onInterrupt` | remote cancel of the running turn |
|
||||||
|
| `onSetModel` / `onSetPermissionMode` / `onSetMaxThinkingTokens` | remote session control |
|
||||||
|
| `onStateChange` | emits `system/bridge_state` (`ready`\|`connected`\|`failed` + `detail`) on the normal output stream |
|
||||||
|
|
||||||
|
Plus outbound `writeSdkMessages` forwarding of task/thinking/vcs events.
|
||||||
|
|
||||||
|
### Prompt arbitration — resolved, no clide policy to invent
|
||||||
|
|
||||||
|
Decided model (user, 2026-08-07): **first-to-apply wins, both sides linked by the
|
||||||
|
same `request_id`, loser''s prompt retracts on that link, clear is idempotent.**
|
||||||
|
|
||||||
|
This is already the shipped protocol, and it is symmetric:
|
||||||
|
- `setOnControlRequestSent` forwards the pending request to the remote;
|
||||||
|
`setOnControlRequestResolved` → `sendControlCancelRequest(request_id)` retracts it.
|
||||||
|
- `RemoteSessionManager.handleMessage` handles inbound `control_cancel_request` by
|
||||||
|
looking up `pendingPermissionRequests` / `pendingDialogRequests` and retracting;
|
||||||
|
unknown ids are ignored ("nothing pending, ignoring").
|
||||||
|
- The refusal schema states the rule directly: *"Evict on RESOLUTION (your own
|
||||||
|
response — any choice — or `control_cancel_request` retirement), never on receipt
|
||||||
|
… Eviction is idempotent."*
|
||||||
|
|
||||||
|
**The clide gap:** `stream_json_session.dart` parses `control_request` but has **no
|
||||||
|
`control_cancel_request` handling at all**. If the remote answers first, clide''s
|
||||||
|
prompt widget hangs with no retraction. Since pending prompts are already keyed by
|
||||||
|
`request_id` for `resolvePrompt()` (`:758`), the fix is a delete + UI clear on the
|
||||||
|
same key. NOT YET OBSERVED live — the probe ran no tools, so the retraction path is
|
||||||
|
confirmed by decompile only. Verify during implementation.
|
||||||
|
|
||||||
|
### Step 2 scope (remaining)
|
||||||
|
|
||||||
|
1. `enableRemoteControl({String? name})` / `disableRemoteControl()` on
|
||||||
|
`StreamJsonSession` — shaped exactly like `setModel()` (`:932`): request with
|
||||||
|
`request_id`, pending map, reconcile response into `SessionStatus`.
|
||||||
|
2. Handle `system/bridge_state` in the event switch → connection state.
|
||||||
|
3. **Handle inbound `control_cancel_request` → retract the matching pending
|
||||||
|
`ToolPrompt`.** (The arbitration work above; also correct on its own merits.)
|
||||||
|
4. Two `SessionStatus` fields (`session_url`, bridge state).
|
||||||
|
5. Cockpit affordance: connect link / QR + connected indicator.
|
||||||
|
6. `clide claude remote-control <on|off>` verb for D-6 parity.
|
||||||
|
7. Teardown on pane close; pass clide''s derived pane name as `name` (the CLI
|
||||||
|
already names clide sessions e.g. `clide-18`).
|
||||||
|
|
||||||
|
### Constraints found
|
||||||
|
|
||||||
|
- Requires a logged-in subscription account; bridge is skipped on non-first-party
|
||||||
|
providers (`isFirstPartyProvider` check) — needs a disabled UI state.
|
||||||
|
- Help text for the daemon path notes the workspace trust dialog must have been
|
||||||
|
accepted by running `claude` interactively in the directory once. clide spawns
|
||||||
|
non-interactively where trust is auto-skipped — verify this doesn''t block the bridge.
|
||||||
|
- `remoteControlAtStartup` is a user setting ("Start Remote Control bridge
|
||||||
|
automatically each session") — a zero-code way to A/B the behaviour, and a
|
||||||
|
setting clide should probably respect rather than fight.
|
||||||
|
- Related but out of scope: `isolatePeerMachines` (cross-machine `SendMessage`
|
||||||
|
between peer sessions); `claude remote-control` hidden subcommand (`bridgeMain`)
|
||||||
|
which runs a per-directory daemon with `--spawn same-dir|worktree|session`.', 'backlog', 'medium', NULL, NULL, NULL, '2026-06-16 11:20:36', '2026-08-07 12:21:08.809', NULL, 'a420c6a2175901ac10d20685907847a5', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGYS06SDJGZ4W3Z9V9HDEATW', 'bug', NULL, 'pre-commit changelog hook leaves ticket_deps/ticket_idmap unstaged', 'The pre-commit hook re-exports + stages .pql/changelog on commit but only catches the tickets + ticket_history tables — it leaves ticket_deps (blocker edges) and ticket_idmap (new T-NNN <-> record_id mappings) UNSTAGED. Seen repeatedly this session (D-103 re-sequencing blockers; T-495 id mapping), each needing a manual follow-up commit; otherwise the planning state silently doesn''t persist and a later branch switch drops it — exactly the failure the hook exists to prevent. Fix: stage ALL of .pql/changelog/ (git add .pql/changelog/), not just the tables the export rewrote. Repro: pql ticket block X --by Y + create a ticket, commit unrelated files, observe ticket_deps/ticket_idmap still modified afterward.
|
||||||
|
|
||||||
|
## Widened 2026-08-07 — broader than the title, and the root cause is different
|
||||||
|
|
||||||
|
### The scope is wrong: tickets + ticket_history are NOT immune
|
||||||
|
|
||||||
|
This ticket states the hook "only catches the tickets + ticket_history tables."
|
||||||
|
That is not the failure mode. On 2026-08-07 a ticket-only turn (appending Step-1
|
||||||
|
findings to T-454) left **`tickets/2026-08.sql` and `ticket_history/2026-08.sql`
|
||||||
|
untracked and unstaged** — the two tables assumed to work. The commit aborted
|
||||||
|
with "nothing added to commit but untracked files present" and needed an explicit
|
||||||
|
`git add` of both paths.
|
||||||
|
|
||||||
|
So no table is reliably staged. Retitle accordingly.
|
||||||
|
|
||||||
|
### Likely root cause: staging is gated on rows appended, not on file dirtiness
|
||||||
|
|
||||||
|
The pre-commit hook is a one-liner that delegates everything to pql:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# .pql/hooks/pre-commit
|
||||||
|
''/…/pql'' plan export --stage 2>/dev/null || true
|
||||||
|
```
|
||||||
|
|
||||||
|
Its output on the failing commit:
|
||||||
|
|
||||||
|
```
|
||||||
|
{"files_written":["…/ticket_history/2026-08.sql","…/tickets/2026-08.sql"],"rows_written":0}
|
||||||
|
```
|
||||||
|
|
||||||
|
It **wrote both files and staged neither**. Second invocation (after a manual
|
||||||
|
`git add`) returned `{"files_written":null,"rows_written":0}`.
|
||||||
|
|
||||||
|
Hypothesis: `--stage` only issues the `git add` when it appends rows
|
||||||
|
(`rows_written > 0`). Because ticket mutations already **write through** to
|
||||||
|
`.pql/changelog/` synchronously, by the time the pre-commit hook runs there is
|
||||||
|
nothing left to append — `rows_written` is 0 — so the staging step is skipped even
|
||||||
|
though the file on disk is new/dirty. NOT YET VERIFIED; confirm against pql''s
|
||||||
|
`plan export --stage` implementation.
|
||||||
|
|
||||||
|
This also better explains the originally-reported symptom: `ticket_deps` /
|
||||||
|
`ticket_idmap` aren''t special-cased out, they just tend to be *new month files*
|
||||||
|
or already-written-through, hitting the same skip.
|
||||||
|
|
||||||
|
Contributing factor: new-month rollover. These were the first August files, so
|
||||||
|
they were untracked rather than modified — worth checking whether `--stage`
|
||||||
|
handles untracked paths differently from tracked-but-modified ones.
|
||||||
|
|
||||||
|
### The fix belongs in pql, not clide
|
||||||
|
|
||||||
|
clide''s hook has no logic to fix — it is a single delegating line installed by
|
||||||
|
`pql init`. The change is in pql''s `plan export --stage`: stage every file under
|
||||||
|
`.pql/changelog/` that is dirty or untracked, regardless of `rows_written`.
|
||||||
|
Track/land it in the pql repo; this ticket is the clide-side symptom record.
|
||||||
|
|
||||||
|
The ticket''s proposed workaround (`git add .pql/changelog/` on the whole
|
||||||
|
directory) is still correct and would cover untracked files too.
|
||||||
|
|
||||||
|
### Severity is higher than "medium"
|
||||||
|
|
||||||
|
This is a silent data-loss path, not a nuisance. A turn that only files or edits
|
||||||
|
tickets makes no other commit, so the hook is the sole persistence mechanism; when
|
||||||
|
it silently no-ops, the planning state never lands and a later branch switch drops
|
||||||
|
it. The failure is invisible unless someone reads the hook''s JSON on stderr.
|
||||||
|
Consider raising priority and/or making a failed stage loud rather than
|
||||||
|
`2>/dev/null || true`.', 'backlog', 'medium', NULL, NULL, NULL, '2026-06-28 18:00:41.419', '2026-08-07 12:30:44.880', NULL, 'bb5179427efa3ad0aff9a48164833f57', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGYS06SDJGZ4W3Z9V9HDEATW', 'bug', NULL, 'pre-commit hook stages no .pql/changelog files (pql plan export --stage)', 'The pre-commit hook re-exports + stages .pql/changelog on commit but only catches the tickets + ticket_history tables — it leaves ticket_deps (blocker edges) and ticket_idmap (new T-NNN <-> record_id mappings) UNSTAGED. Seen repeatedly this session (D-103 re-sequencing blockers; T-495 id mapping), each needing a manual follow-up commit; otherwise the planning state silently doesn''t persist and a later branch switch drops it — exactly the failure the hook exists to prevent. Fix: stage ALL of .pql/changelog/ (git add .pql/changelog/), not just the tables the export rewrote. Repro: pql ticket block X --by Y + create a ticket, commit unrelated files, observe ticket_deps/ticket_idmap still modified afterward.
|
||||||
|
|
||||||
|
## Widened 2026-08-07 — broader than the title, and the root cause is different
|
||||||
|
|
||||||
|
### The scope is wrong: tickets + ticket_history are NOT immune
|
||||||
|
|
||||||
|
This ticket states the hook "only catches the tickets + ticket_history tables."
|
||||||
|
That is not the failure mode. On 2026-08-07 a ticket-only turn (appending Step-1
|
||||||
|
findings to T-454) left **`tickets/2026-08.sql` and `ticket_history/2026-08.sql`
|
||||||
|
untracked and unstaged** — the two tables assumed to work. The commit aborted
|
||||||
|
with "nothing added to commit but untracked files present" and needed an explicit
|
||||||
|
`git add` of both paths.
|
||||||
|
|
||||||
|
So no table is reliably staged. Retitle accordingly.
|
||||||
|
|
||||||
|
### Likely root cause: staging is gated on rows appended, not on file dirtiness
|
||||||
|
|
||||||
|
The pre-commit hook is a one-liner that delegates everything to pql:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# .pql/hooks/pre-commit
|
||||||
|
''/…/pql'' plan export --stage 2>/dev/null || true
|
||||||
|
```
|
||||||
|
|
||||||
|
Its output on the failing commit:
|
||||||
|
|
||||||
|
```
|
||||||
|
{"files_written":["…/ticket_history/2026-08.sql","…/tickets/2026-08.sql"],"rows_written":0}
|
||||||
|
```
|
||||||
|
|
||||||
|
It **wrote both files and staged neither**. Second invocation (after a manual
|
||||||
|
`git add`) returned `{"files_written":null,"rows_written":0}`.
|
||||||
|
|
||||||
|
Hypothesis: `--stage` only issues the `git add` when it appends rows
|
||||||
|
(`rows_written > 0`). Because ticket mutations already **write through** to
|
||||||
|
`.pql/changelog/` synchronously, by the time the pre-commit hook runs there is
|
||||||
|
nothing left to append — `rows_written` is 0 — so the staging step is skipped even
|
||||||
|
though the file on disk is new/dirty. NOT YET VERIFIED; confirm against pql''s
|
||||||
|
`plan export --stage` implementation.
|
||||||
|
|
||||||
|
This also better explains the originally-reported symptom: `ticket_deps` /
|
||||||
|
`ticket_idmap` aren''t special-cased out, they just tend to be *new month files*
|
||||||
|
or already-written-through, hitting the same skip.
|
||||||
|
|
||||||
|
Contributing factor: new-month rollover. These were the first August files, so
|
||||||
|
they were untracked rather than modified — worth checking whether `--stage`
|
||||||
|
handles untracked paths differently from tracked-but-modified ones.
|
||||||
|
|
||||||
|
### The fix belongs in pql, not clide
|
||||||
|
|
||||||
|
clide''s hook has no logic to fix — it is a single delegating line installed by
|
||||||
|
`pql init`. The change is in pql''s `plan export --stage`: stage every file under
|
||||||
|
`.pql/changelog/` that is dirty or untracked, regardless of `rows_written`.
|
||||||
|
Track/land it in the pql repo; this ticket is the clide-side symptom record.
|
||||||
|
|
||||||
|
The ticket''s proposed workaround (`git add .pql/changelog/` on the whole
|
||||||
|
directory) is still correct and would cover untracked files too.
|
||||||
|
|
||||||
|
### Severity is higher than "medium"
|
||||||
|
|
||||||
|
This is a silent data-loss path, not a nuisance. A turn that only files or edits
|
||||||
|
tickets makes no other commit, so the hook is the sole persistence mechanism; when
|
||||||
|
it silently no-ops, the planning state never lands and a later branch switch drops
|
||||||
|
it. The failure is invisible unless someone reads the hook''s JSON on stderr.
|
||||||
|
Consider raising priority and/or making a failed stage loud rather than
|
||||||
|
`2>/dev/null || true`.', 'backlog', 'high', NULL, NULL, NULL, '2026-06-28 18:00:41.419', '2026-08-07 12:30:59.962', NULL, '29a636f1d7c9de8c57184afd2eaf949f', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
|
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGYS06SDJGZ4W3Z9V9HDEATW', 'bug', NULL, 'pre-commit hook stages no .pql/changelog files (pql plan export --stage)', 'The pre-commit hook re-exports + stages .pql/changelog on commit but only catches the tickets + ticket_history tables — it leaves ticket_deps (blocker edges) and ticket_idmap (new T-NNN <-> record_id mappings) UNSTAGED. Seen repeatedly this session (D-103 re-sequencing blockers; T-495 id mapping), each needing a manual follow-up commit; otherwise the planning state silently doesn''t persist and a later branch switch drops it — exactly the failure the hook exists to prevent. Fix: stage ALL of .pql/changelog/ (git add .pql/changelog/), not just the tables the export rewrote. Repro: pql ticket block X --by Y + create a ticket, commit unrelated files, observe ticket_deps/ticket_idmap still modified afterward.
|
||||||
|
|
||||||
|
## Widened 2026-08-07 — broader than the title, and the root cause is different
|
||||||
|
|
||||||
|
### The scope is wrong: tickets + ticket_history are NOT immune
|
||||||
|
|
||||||
|
This ticket states the hook "only catches the tickets + ticket_history tables."
|
||||||
|
That is not the failure mode. On 2026-08-07 a ticket-only turn (appending Step-1
|
||||||
|
findings to T-454) left **`tickets/2026-08.sql` and `ticket_history/2026-08.sql`
|
||||||
|
untracked and unstaged** — the two tables assumed to work. The commit aborted
|
||||||
|
with "nothing added to commit but untracked files present" and needed an explicit
|
||||||
|
`git add` of both paths.
|
||||||
|
|
||||||
|
So no table is reliably staged. Retitle accordingly.
|
||||||
|
|
||||||
|
### Likely root cause: staging is gated on rows appended, not on file dirtiness
|
||||||
|
|
||||||
|
The pre-commit hook is a one-liner that delegates everything to pql:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# .pql/hooks/pre-commit
|
||||||
|
''/…/pql'' plan export --stage 2>/dev/null || true
|
||||||
|
```
|
||||||
|
|
||||||
|
Its output on the failing commit:
|
||||||
|
|
||||||
|
```
|
||||||
|
{"files_written":["…/ticket_history/2026-08.sql","…/tickets/2026-08.sql"],"rows_written":0}
|
||||||
|
```
|
||||||
|
|
||||||
|
It **wrote both files and staged neither**. Second invocation (after a manual
|
||||||
|
`git add`) returned `{"files_written":null,"rows_written":0}`.
|
||||||
|
|
||||||
|
Hypothesis: `--stage` only issues the `git add` when it appends rows
|
||||||
|
(`rows_written > 0`). Because ticket mutations already **write through** to
|
||||||
|
`.pql/changelog/` synchronously, by the time the pre-commit hook runs there is
|
||||||
|
nothing left to append — `rows_written` is 0 — so the staging step is skipped even
|
||||||
|
though the file on disk is new/dirty. NOT YET VERIFIED; confirm against pql''s
|
||||||
|
`plan export --stage` implementation.
|
||||||
|
|
||||||
|
This also better explains the originally-reported symptom: `ticket_deps` /
|
||||||
|
`ticket_idmap` aren''t special-cased out, they just tend to be *new month files*
|
||||||
|
or already-written-through, hitting the same skip.
|
||||||
|
|
||||||
|
Contributing factor: new-month rollover. These were the first August files, so
|
||||||
|
they were untracked rather than modified — worth checking whether `--stage`
|
||||||
|
handles untracked paths differently from tracked-but-modified ones.
|
||||||
|
|
||||||
|
### The fix belongs in pql, not clide
|
||||||
|
|
||||||
|
clide''s hook has no logic to fix — it is a single delegating line installed by
|
||||||
|
`pql init`. The change is in pql''s `plan export --stage`: stage every file under
|
||||||
|
`.pql/changelog/` that is dirty or untracked, regardless of `rows_written`.
|
||||||
|
Track/land it in the pql repo; this ticket is the clide-side symptom record.
|
||||||
|
|
||||||
|
The ticket''s proposed workaround (`git add .pql/changelog/` on the whole
|
||||||
|
directory) is still correct and would cover untracked files too.
|
||||||
|
|
||||||
|
### Severity is higher than "medium"
|
||||||
|
|
||||||
|
This is a silent data-loss path, not a nuisance. A turn that only files or edits
|
||||||
|
tickets makes no other commit, so the hook is the sole persistence mechanism; when
|
||||||
|
it silently no-ops, the planning state never lands and a later branch switch drops
|
||||||
|
it. The failure is invisible unless someone reads the hook''s JSON on stderr.
|
||||||
|
Consider raising priority and/or making a failed stage loud rather than
|
||||||
|
`2>/dev/null || true`.
|
||||||
|
|
||||||
|
### Correction (same session): not an untracked-file issue — `--stage` never stages
|
||||||
|
|
||||||
|
The "new-month rollover / untracked path" contributing factor above is **disproved**.
|
||||||
|
Tested directly: with `tickets/2026-08.sql` and `ticket_history/2026-08.sql` already
|
||||||
|
tracked and merely *modified*, a bare `git commit` still aborted with "no changes
|
||||||
|
added to commit". Hook output was identical:
|
||||||
|
|
||||||
|
```
|
||||||
|
{"files_written":["…/ticket_history/2026-08.sql","…/tickets/2026-08.sql"],"rows_written":0}
|
||||||
|
```
|
||||||
|
|
||||||
|
Tracked-modified and untracked-new both fail. The only common factor is
|
||||||
|
`rows_written: 0`.
|
||||||
|
|
||||||
|
**Escalates the diagnosis:** this is not intermittent and not table-specific.
|
||||||
|
Because ticket mutations write through to `.pql/changelog/` synchronously, the
|
||||||
|
pre-commit export always finds zero rows left to append, so `--stage` skips its
|
||||||
|
`git add` on *every* commit. In this repo the hook''s staging step is effectively
|
||||||
|
dead — it has likely never worked, and every ticket change that landed did so
|
||||||
|
because some other file in the commit was staged by hand, or because someone
|
||||||
|
noticed and re-added.
|
||||||
|
|
||||||
|
That reframes the earlier `ticket_deps` / `ticket_idmap` reports: those tables
|
||||||
|
weren''t being singled out, they were just the cases where nothing else in the
|
||||||
|
commit masked the failure.
|
||||||
|
|
||||||
|
**Fix (pql):** `plan export --stage` must stage on file state, not on
|
||||||
|
`rows_written` — `git add` every dirty-or-untracked path under `.pql/changelog/`
|
||||||
|
whenever the directory differs from the index, including when the export was a
|
||||||
|
no-op. Consider also dropping the hook''s `2>/dev/null || true` so a staging
|
||||||
|
failure is visible instead of silent.', 'backlog', 'high', NULL, NULL, NULL, '2026-06-28 18:00:41.419', '2026-08-07 12:31:41.104', NULL, '4839606f6898f3f0f39f5c0cbd3d183d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||||
+582
@@ -0,0 +1,582 @@
|
|||||||
|
# AGENTS.md for clide — Mistral Vibe operating as Claude Code peer
|
||||||
|
|
||||||
|
This file configures Mistral Vibe to operate in this repo with the same
|
||||||
|
effectiveness as Claude Code. It distills the CLAUDE.md guardrails and all
|
||||||
|
`.claude/skills/` into Vibe's instruction hierarchy, preserving "Claude punch"
|
||||||
|
in a hybrid workflow.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Identity
|
||||||
|
|
||||||
|
You are operating in **clide** — a Flutter/Dart IDE for Claude Code CLI.
|
||||||
|
Your role: **peer to Claude Code**, not replacement. Maintain Claude's
|
||||||
|
behavioral standards, tool discipline, and architectural rigor.
|
||||||
|
|
||||||
|
**Primary directive:** Never lose "Claude punch" — the combination of
|
||||||
|
strict guardrails, CLI-first interaction, and parity between UI and CLI
|
||||||
|
that defines effective operation in this repo.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Non-Negotiable Guardrails (from CLAUDE.md)
|
||||||
|
|
||||||
|
These are load-bearing. Violating any means the design is wrong, not the rule.
|
||||||
|
|
||||||
|
- **Flutter desktop is the host. No Electron, ever.**
|
||||||
|
- **Single process.** The Flutter app hosts everything in-process: IPC server,
|
||||||
|
subsystem handlers (pane, files, editor, git, pql), extensions.
|
||||||
|
- **CLI-first, not MCP.** Drive via `clide <subsystem> <verb>` Bash commands.
|
||||||
|
- **Dart is the core; pql fills the query gap.** PTY spawning is native Dart FFI
|
||||||
|
(`posix_openpt` + `posix_spawn`). `pql` (Go) handles vault queries.
|
||||||
|
- **Own the rendering stack.** PTY, markdown, graph, canvas — all clide-owned.
|
||||||
|
- **User/Claude parity (D-6).** Every CLI subcommand has a UI affordance,
|
||||||
|
and every UI action has a CLI equivalent.
|
||||||
|
- **pql: wrap, don't duplicate.** Clide wraps pql; never re-implements it.
|
||||||
|
- **Repo-is-the-workspace.** Git repo root is the workspace.
|
||||||
|
- **Decision discipline.** All architectural choices live in
|
||||||
|
`governance/decisions/<domain>.md` as `D-NNN` records. Open questions as
|
||||||
|
`Q-NNN` under `governance/questions/<domain>.md`. Rejected as `R-NNN`.
|
||||||
|
- **No pre-existing excuse.** Solo-dev repo — if `make test` is red, fix it
|
||||||
|
first, then your work. Surface blockers; don't push on top of broken state.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tool Discipline (from CLAUDE.md)
|
||||||
|
|
||||||
|
### Make targets are the entry points
|
||||||
|
|
||||||
|
| Purpose | Command | Never call directly |
|
||||||
|
|---------|---------|---------------------|
|
||||||
|
| Launch app | `make run` | `flutter run` |
|
||||||
|
| Static analysis | `make analyze` | `flutter analyze` |
|
||||||
|
| Format | `make format` | `dart format` |
|
||||||
|
| Fast test suite | `make test` | `flutter test` |
|
||||||
|
| Core subsystem tests | `make test-core` | underlying scripts |
|
||||||
|
| Accessibility tests | `make test-a11y` | underlying scripts |
|
||||||
|
| Integration tests | `make test-integration` | underlying scripts |
|
||||||
|
| Pre-push gate | `make push-check` | `ci/*` scripts |
|
||||||
|
| Setup hooks | `make hooks` | `cp .githooks/* .git/hooks/` |
|
||||||
|
| Clean | `make clean` | `rm -rf build/` |
|
||||||
|
|
||||||
|
### Shell hygiene
|
||||||
|
|
||||||
|
- **Working directory is repo root** — never `cd /path/to/clide` or `git -C`
|
||||||
|
- **One command per invocation** — no `&&`/`;` chaining
|
||||||
|
- Exception: `git commit -F` HEREDOC for multi-line messages
|
||||||
|
- Prefer Read/Edit/Grep tools over `cat`/`sed`/`grep` for file inspection
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Git Workflow (from git-commit skill)
|
||||||
|
|
||||||
|
### Commit message format: Conventional Commits 1.0
|
||||||
|
|
||||||
|
```
|
||||||
|
<type>(<scope>): <imperative subject> (<T-NNN>)
|
||||||
|
|
||||||
|
Optional body: explain WHY, not WHAT. Wrap at ~72 chars.
|
||||||
|
|
||||||
|
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Type:** `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `chore`
|
||||||
|
- Use `feat`/`fix` for user-visible behavior
|
||||||
|
- Use `chore` for bookkeeping (`chore(plan)` for pql ticket housekeeping)
|
||||||
|
- Append `!` after scope for breaking changes: `feat(ipc)!: ...`
|
||||||
|
|
||||||
|
**Scope:** Optional but preferred — subsystem: `settings`, `vim`, `pty`, `git`, `plan`
|
||||||
|
- Lower-case, no spaces
|
||||||
|
|
||||||
|
**Subject:** ≤ 72 characters INCLUDING prefix. No emojis. No "and".
|
||||||
|
|
||||||
|
**Ticket ref:** Trailing `(T-NNN)` when work has a ticket.
|
||||||
|
|
||||||
|
**Body:** Explain the *why*. The diff shows the *what*. Don't restate it.
|
||||||
|
- Hard cap: **60 words per bullet** for CHANGELOG entries
|
||||||
|
- No multi-paragraph bullets
|
||||||
|
- No sub-headers inside bullets
|
||||||
|
- No probe numbers, latency stats, or %-coverage deltas
|
||||||
|
|
||||||
|
### Logically-separated commits
|
||||||
|
|
||||||
|
1. **Read `git status` + `git diff` first** — never stage blind
|
||||||
|
2. **Group by concern, not location:**
|
||||||
|
- Bookkeeping: `.gitignore`, lockfiles, config
|
||||||
|
- Documentation: `README.md`, ADRs, design notes
|
||||||
|
- Tooling/skills: reusable, non-project-specific
|
||||||
|
- Project conventions: repo's own rules
|
||||||
|
- Feature/subsystem: one cohesive change
|
||||||
|
- Layer changes: app, sidecar CLI, daemon, IPC, pql wrapper, canvas, git panel
|
||||||
|
3. **Prefer many small focused commits over one large mixed one**
|
||||||
|
4. **Use `git add <specific paths>`** — NEVER `git add -A`, `git add .`, `git add -u`
|
||||||
|
5. **Verify between commits** with `git status`, `git diff --staged`, `git log -1`
|
||||||
|
|
||||||
|
### Changelog discipline
|
||||||
|
|
||||||
|
- **Every user-visible commit must touch CHANGELOG.md** under `## [Unreleased]`
|
||||||
|
- Use Keep a Changelog 1.1.0 format with sections: Added, Changed, Deprecated, Removed, Fixed, Security
|
||||||
|
- Entries: short imperative phrases describing user-facing impact
|
||||||
|
- **60 words hard cap per bullet** — verify with `make changelog-gate`
|
||||||
|
- What skips changelog: pure bookkeeping with no user-visible effect
|
||||||
|
|
||||||
|
### Safety rules (reinforced)
|
||||||
|
|
||||||
|
- **Never** `--no-verify`
|
||||||
|
- **Never** `--amend` unless user explicitly asks
|
||||||
|
- **Never** force-push to `main` or `master`
|
||||||
|
- **Always** check `git status` before staging, `git diff --staged` before committing
|
||||||
|
- Commit message via HEREDOC:
|
||||||
|
```bash
|
||||||
|
git commit -m "$(cat <<'EOF'
|
||||||
|
<message>
|
||||||
|
EOF
|
||||||
|
)"
|
||||||
|
```
|
||||||
|
|
||||||
|
### What NOT to commit
|
||||||
|
|
||||||
|
- `.env`, `*.env.local`
|
||||||
|
- `.claude/settings.local.json`
|
||||||
|
- Build artefacts: `sidecar/bin/`, `sidecar/dist/`, `build/`, `app/.dart_tool/`
|
||||||
|
- SQLite index files: `*.sqlite`, `*.sqlite-wal`, `*.sqlite-shm`, `*.db`
|
||||||
|
- Coverage/test output: `*.out`, `coverage.*`, `*.test`
|
||||||
|
- `.pql/changelog/` — auto-staged by pre-commit hook from pql DB
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## pql — Vault Queries + Project Planning
|
||||||
|
|
||||||
|
`pql` indexes a vault into SQLite and exposes structural queries plus a
|
||||||
|
planning layer for decision records and tickets. One binary, two surfaces.
|
||||||
|
|
||||||
|
### Precondition
|
||||||
|
|
||||||
|
```bash
|
||||||
|
command -v pql
|
||||||
|
```
|
||||||
|
|
||||||
|
If absent, tell the user to install from
|
||||||
|
https://github.com/postmeridiem/pql/releases/latest. Don't install it
|
||||||
|
yourself. Don't fall back to grep unless the user explicitly asks.
|
||||||
|
|
||||||
|
### First touch: learn the vault
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pql schema
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns one row per frontmatter key with observed types and file counts.
|
||||||
|
Run once per session before writing queries.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Surface 1: Vault queries
|
||||||
|
|
||||||
|
#### Subcommands
|
||||||
|
|
||||||
|
| Command | Purpose |
|
||||||
|
|---|---|
|
||||||
|
| `pql files [glob]` | List indexed files; optional glob filter |
|
||||||
|
| `pql tags [--sort count]` | Distinct tags with counts |
|
||||||
|
| `pql backlinks <path>` | Files linking TO a path |
|
||||||
|
| `pql outlinks <path>` | Links FROM a file |
|
||||||
|
| `pql meta <path>` | Frontmatter + tags + outlinks + headings for one file |
|
||||||
|
| `pql schema` | Typed frontmatter schema |
|
||||||
|
| `pql base <name>` | Execute an Obsidian .base file |
|
||||||
|
| `pql shell` | Interactive REPL (indexes once, then query per line) |
|
||||||
|
| `pql query "<DSL>"` | SQL-derived DSL for complex queries |
|
||||||
|
| `pql doctor` | Resolved vault/config/DB/index state |
|
||||||
|
|
||||||
|
#### DSL examples
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT name, fm.date WHERE fm.type = 'meeting' ORDER BY fm.date DESC LIMIT 10
|
||||||
|
SELECT path WHERE 'project' IN tags ORDER BY path
|
||||||
|
SELECT name, fm.prior_job WHERE fm.type = 'council-member' ORDER BY name
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `--file q.pql` or `--stdin` for long queries. Don't interpolate vault
|
||||||
|
content into the command line.
|
||||||
|
|
||||||
|
#### Query cookbook
|
||||||
|
|
||||||
|
- **Files in folder** → `pql files 'sessions/*'`
|
||||||
|
- **Top tags** → `pql tags --sort count --limit 20`
|
||||||
|
- **What links to X?** → `pql backlinks members/vaasa/persona.md`
|
||||||
|
- **Date range** → `pql query "SELECT name, fm.date WHERE fm.date BETWEEN '2024-01-01' AND '2024-12-31'"`
|
||||||
|
- **Run a Base** → `pql base council-sessions`
|
||||||
|
- **Inspect one file** → `pql meta members/vaasa/persona.md --pretty`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Surface 2: Planning (decisions + tickets)
|
||||||
|
|
||||||
|
Planning state lives in `<vault>/.pql/pql.db` (user-authored state, not a
|
||||||
|
cache). Decision records come from the DQR tree — `governance/{decisions,
|
||||||
|
questions,rejected}/<domain>.md` by default (D-21), configurable via
|
||||||
|
`dqr_dir` in `.pql/config.yaml` or the `PQL_DQR_DIR` env var (env > file >
|
||||||
|
default); a legacy flat `decisions/` is auto-detected as a fallback.
|
||||||
|
Tickets are SQLite-native.
|
||||||
|
|
||||||
|
#### Decision subcommands
|
||||||
|
|
||||||
|
| Command | Purpose |
|
||||||
|
|---|---|
|
||||||
|
| `pql decisions sync [--no-style]` | Parse the DQR tree → upsert into pql.db; surfaces style warnings (filename, subdir-type, domain pairing/conflicts) unless `--no-style` |
|
||||||
|
| `pql decisions validate [--no-style]` | Dry-run parse; structural errors exit non-zero, style issues warn (suppress with `--no-style`) |
|
||||||
|
| `pql decisions claim <D\|Q\|R> <domain> "title"` | Print next available ID |
|
||||||
|
| `pql decisions list [--type X] [--domain X] [--status X]` | List decisions |
|
||||||
|
| `pql decisions show <id> [--with-refs] [--with-tickets]` | Show with joins |
|
||||||
|
| `pql decisions coverage` | Confirmed decisions without tickets |
|
||||||
|
| `pql decisions refs <id>` | Cross-references involving a decision |
|
||||||
|
|
||||||
|
Always `pql decisions sync` before querying if decisions/*.md may have changed.
|
||||||
|
|
||||||
|
#### Ticket subcommands
|
||||||
|
|
||||||
|
| Command | Purpose |
|
||||||
|
|---|---|
|
||||||
|
| `pql ticket new <type> "title" [--parent T-NNN] [--decision D-NNN] [--priority P] [--id-only]` | Create (emits T-NNN; `--parent` files it under an epic/story in one step; `--id-only` prints the bare id for tree-creation scripts) |
|
||||||
|
| `pql ticket list [--status S] [--team T] [--assigned A] [--label L] [--under T-NNN] [--leaf] [--unblocked]` | List with filters. `--under` = recursive descendants of a ticket; `--leaf` = no children; `--unblocked` = blockers all reached a terminal status |
|
||||||
|
| `pql ticket show <id[,id,...]> [--with-context] [--with-blockers] [--with-children] [--tree] [--depth N]` | Show one or more (comma-batch → array of show-trees). `--with-children` = direct children; `--tree` = nested descendant subtree + direct parent (cap with `--depth N`) |
|
||||||
|
| `pql ticket status <id> <new-status> [--force]` | Change status. Closing (terminal status) is blocked while the ticket has open children; `--force` cascades that status to all not-yet-closed descendants and lists them |
|
||||||
|
| `pql ticket statuslist` | List the configured status vocabulary (name, label, class, order, is_default, is_terminal) — what a UI reads to render columns |
|
||||||
|
| `pql ticket relabel <id\|record_id> [--new-label T-NNN] [--fix-prose]` | Reassign a ticket's friendly T-NNN label (reconcile a duplicate-label collision). Identity (record_id) and the structural graph are untouched; only the label moves. `--fix-prose` rewrites stale T-NNN mentions in DQR markdown |
|
||||||
|
| `pql ticket assign <id> <agent>` | Set assignee |
|
||||||
|
| `pql ticket setparent <id[,id,...]> <parent-id \| none>` | Set (or clear with `none`) a ticket's **parent** — the hierarchy link (epic→story→task). Positional, not a flag. This is the parent/child relationship, distinct from blockers |
|
||||||
|
| `pql ticket append <id> <text\|--file\|--stdin>` | Append to the description (blank-line separated); never round-trips existing text |
|
||||||
|
| `pql ticket block <id> --by <other>` | Add a **blocker** (a dependency: <id> can't start until <other> is done) — NOT a parent/child link; use `setparent` or `new --parent` for hierarchy |
|
||||||
|
| `pql ticket unblock <id> --from <other>` | Remove blocker |
|
||||||
|
| `pql ticket team <id> <team>` | Set team |
|
||||||
|
| `pql ticket label <id> add\|rm <label>` | Manage labels |
|
||||||
|
| `pql ticket board [--team T]` | Kanban board view |
|
||||||
|
| `pql ticket refine list` | Tickets with empty descriptions, status-priority-sorted |
|
||||||
|
| `pql ticket refine next [--skip N]` | Head of the unrefined queue with full show-tree + remaining count |
|
||||||
|
| `pql ticket refine write <id> <json\|--file\|--stdin>` | Patch writable fields (title, description, priority, type) |
|
||||||
|
|
||||||
|
Ticket types: initiative, epic, story, task, bug.
|
||||||
|
The `id` you type and see (T-NNN) is a friendly label backed by a stable
|
||||||
|
underwater `record_id` (also in output); two clones never collide on identity,
|
||||||
|
and a duplicate label is fixed with `pql ticket relabel` (D-26).
|
||||||
|
Statuses are a per-vault vocabulary (`ticket_statuses` in `.pql/config.yaml`),
|
||||||
|
defaulting to: backlog, ready, in_progress, review, done, cancelled. Each status
|
||||||
|
has a class — initial, active, review, terminal — that the engine reasons about.
|
||||||
|
Run `pql ticket statuslist` to discover the live set. Any status can transition
|
||||||
|
to any other — pql does not enforce a state machine — except that a ticket
|
||||||
|
cannot reach a terminal status while it has open children (use `--force` to
|
||||||
|
cascade the close down the subtree).
|
||||||
|
|
||||||
|
#### Plan subcommands
|
||||||
|
|
||||||
|
| Command | Purpose |
|
||||||
|
|---|---|
|
||||||
|
| `pql plan status` | Dashboard: decision counts, open Qs, ticket summary, coverage gaps |
|
||||||
|
| `pql plan whatsnext` | Next ticket to work on (active work, then the "ready" lane) with full context bundle |
|
||||||
|
| `pql plan review` | Next ticket awaiting review with full context bundle |
|
||||||
|
| `pql plan export [--stage]` | Append changed planning rows to `.pql/changelog/<table>/<YYYY-MM>.sql` (the git-tracked log of record); `--stage` also `git add`s them. Normally a no-op — mutations already write through |
|
||||||
|
| `pql plan import [--legacy FILE]` | Replay `.pql/changelog/` into `pql.db` (or one-time `--legacy pql-plan.json` migration from the pre-D-15 snapshot) |
|
||||||
|
| `pql plan rebuild` | Drop replicated tables and replay `.pql/changelog/` from scratch. Warns on stderr (`changelog.ticket_id_collision`) + lists `collisions` in the result if one ticket id was filed twice across clones |
|
||||||
|
|
||||||
|
#### Versioning planning state
|
||||||
|
|
||||||
|
`pql.db` is gitignored — the durable, git-tracked artifact is
|
||||||
|
`.pql/changelog/` (D-15/D-16). Ticket mutations **write through** to the
|
||||||
|
changelog synchronously, so it is always current; you never have to
|
||||||
|
remember to "export". The hooks installed by `pql init` do the rest:
|
||||||
|
|
||||||
|
- `pre-commit` stages `.pql/changelog/` so it lands in the same commit as
|
||||||
|
the change that produced it.
|
||||||
|
- `post-merge` replays incoming changelog edits (`pql plan import`) and
|
||||||
|
re-syncs decisions from their markdown.
|
||||||
|
- `post-checkout` / `post-rewrite` rebuild `pql.db` from the changelog.
|
||||||
|
|
||||||
|
On a fresh clone, `pql plan import` (run automatically on first open)
|
||||||
|
replays the changelog into a new `pql.db`. There is **no** `pql-plan.json`
|
||||||
|
snapshot — that artifact is retired; `pql plan export` is now only a
|
||||||
|
manual catch-up/reconcile.
|
||||||
|
|
||||||
|
A ticket mutation (create / status transition / any write) leaves
|
||||||
|
`.pql/changelog/` dirty by design — the `pre-commit` hook stages it onto
|
||||||
|
the next `git commit`. This is expected, not a problem to flag. Don't
|
||||||
|
narrate "the ticket won't persist until committed" on every edit; either
|
||||||
|
fold the bookkeeping into a commit or trust the normal commit flow.
|
||||||
|
|
||||||
|
#### Planning cookbook
|
||||||
|
|
||||||
|
- **Sync and list confirmed** → `pql decisions sync && pql decisions list --type confirmed`
|
||||||
|
- **Show with refs** → `pql decisions show D-5 --with-refs --pretty`
|
||||||
|
- **Read full body** → `pql decisions read D-5`
|
||||||
|
- **Create ticket** → `pql ticket new task "implement X" --decision D-5`
|
||||||
|
- **Create ticket, capture id for a script** → `id=$(pql ticket new task "implement X" --id-only)` — prints just `T-NNN`
|
||||||
|
- **File a ticket under an epic** → `pql ticket new bug "fix X" --parent T-276` (one step), or reparent an existing one → `pql ticket setparent T-9 T-276` (clear with `none`). Parent = hierarchy; use `block` only for blocking dependencies
|
||||||
|
- **Batch close** → `pql ticket status T-1,T-2,T-3 done`
|
||||||
|
- **Full context** → `pql ticket show T-5 --with-context --pretty`
|
||||||
|
- **Batch show** → `pql ticket show T-1,T-2,T-3 --pretty`
|
||||||
|
- **Refine next ticket** → `pql ticket refine next --pretty`, then `pql ticket refine write T-N '{"description":"..."}'`
|
||||||
|
- **Append a note** → `pql ticket append T-5 "benchmarked; TTL now 5m"` — blank-line separated, never overwrites; use `--file note.md` or `--stdin` for longer content
|
||||||
|
- **Subtree of an epic** → `pql ticket show T-2 --tree --pretty` — nested `subtree` + direct parent in `ancestors`; add `--depth N` to cap levels
|
||||||
|
- **Ready leaf work under an epic** → `pql ticket list --under T-2 --leaf --unblocked` — leaf tickets beneath T-2 whose blockers have all reached a terminal status; the batch complement to `plan whatsnext`
|
||||||
|
- **What's next?** → `pql plan whatsnext --pretty`
|
||||||
|
- **Review queue** → `pql plan review --pretty`
|
||||||
|
- **Coverage gaps** → `pql decisions coverage`
|
||||||
|
- **Dashboard** → `pql plan status --pretty`
|
||||||
|
- **Force a changelog catch-up** → `pql plan export` (normally a no-op; mutations already write through to `.pql/changelog/`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Output contract (both surfaces)
|
||||||
|
|
||||||
|
- **stdout:** JSON array (default); `--jsonl` for one object/line; `--pretty`; `--limit N`.
|
||||||
|
- **stderr:** JSON diagnostics `{"level":"...","code":"pql.<phase>.<kind>","msg":"..."}`.
|
||||||
|
- **Exit codes:**
|
||||||
|
- `0` — success, including zero matches (empty `[]` — say "no matches", not "failed")
|
||||||
|
- `64` — bad flag
|
||||||
|
- `65` — parse/compile error (pass stderr back)
|
||||||
|
- `66` — vault/config not found
|
||||||
|
- `69` — unavailable
|
||||||
|
- `70` — internal error
|
||||||
|
|
||||||
|
### Anti-patterns
|
||||||
|
|
||||||
|
- Don't pipe to `jq` for simple projections — use `--limit`, `--pretty`, `--jsonl`.
|
||||||
|
- Don't chain `pql files` + `pql meta` — one `pql query` with WHERE.
|
||||||
|
- Don't parse errors — pass stderr diagnostics back directly.
|
||||||
|
- Don't forget `pql decisions sync` before querying decisions.
|
||||||
|
- Don't try to install or upgrade pql — instruct the user if missing.
|
||||||
|
|
||||||
|
### When NOT to use
|
||||||
|
|
||||||
|
- **Body text search** → `grep`/`rg`.
|
||||||
|
- **Reading file contents** → `Read` tool.
|
||||||
|
- **Code structure** → tree-sitter / LSP.
|
||||||
|
- **Modifying vault files** → `Write`/`Edit`. pql doesn't write to vault content.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Driving clide UI via CLI (from clide skill)
|
||||||
|
|
||||||
|
**Core principle: Every UI action has a CLI equivalent (D-6).**
|
||||||
|
Discover the live surface; don't hard-code it.
|
||||||
|
|
||||||
|
### Discover capabilities
|
||||||
|
|
||||||
|
```bash
|
||||||
|
clide capabilities
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns JSON: every registered command, split into `subsystem` + `verb`,
|
||||||
|
with argument schema. **This is authoritative** — re-run it, don't trust
|
||||||
|
remembered lists.
|
||||||
|
|
||||||
|
### Slots (layout areas)
|
||||||
|
|
||||||
|
- `sidebar` — left
|
||||||
|
- `workspace` — center (where Claude lives)
|
||||||
|
- `context` — right
|
||||||
|
- `statusbar` — bottom
|
||||||
|
|
||||||
|
### Observe state
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# One-shot orientation
|
||||||
|
clide status
|
||||||
|
|
||||||
|
# Narrower snapshots
|
||||||
|
clide pane list
|
||||||
|
clide editor active
|
||||||
|
clide git status
|
||||||
|
```
|
||||||
|
|
||||||
|
### Drive UI
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Open a doc in a GUI reader
|
||||||
|
clide ui open <reader> <ref>
|
||||||
|
# readers: tickets, decisions, markdown, diff
|
||||||
|
# examples:
|
||||||
|
clide ui open tickets T-123
|
||||||
|
clide ui open decisions D-456
|
||||||
|
clide ui open diff lib/src/foo.dart
|
||||||
|
clide ui open markdown docs/bar.md
|
||||||
|
|
||||||
|
# Show diff and scroll to file
|
||||||
|
clide ui diff lib/src/foo.dart
|
||||||
|
|
||||||
|
# Raise a toast
|
||||||
|
clide ui toast "message" --severity success|warning|error|info
|
||||||
|
|
||||||
|
# General: clide <subsystem> <verb> [args]
|
||||||
|
clide files list
|
||||||
|
clide editor open <path>
|
||||||
|
clide pane focus <pane-id>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Convention:** If a drive verb has no live GUI, return toolError
|
||||||
|
("no live UI to drive"), not hang. Exit code conveys ok/usage/tool error.
|
||||||
|
JSON on stdout.
|
||||||
|
|
||||||
|
### You only see what flows through clide
|
||||||
|
|
||||||
|
Your own non-`clide` shell work (plain file reads, `make test`, `git`) is
|
||||||
|
outside clide's view by design (D-83). Run it **through** `clide ...` if
|
||||||
|
you want clide to observe it.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Testmode (from testmode skill)
|
||||||
|
|
||||||
|
`ClideTestApp` is a lightweight Flutter app for integration testing.
|
||||||
|
Catches regressions unit tests cannot: missing binaries, broken subprocess
|
||||||
|
wiring, IPC dispatch failures, extension activation order, theme parse errors.
|
||||||
|
|
||||||
|
### Running
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make run-testmode # all categories, 60s timeout
|
||||||
|
make run-testmode TESTMODE_CATEGORY=toolchain
|
||||||
|
make run-testmode TESTMODE_CATEGORY=ipc
|
||||||
|
make run-testmode TESTMODE_CATEGORY=extensions
|
||||||
|
make run-testmode TESTMODE_TIMEOUT=120
|
||||||
|
```
|
||||||
|
|
||||||
|
Results: stdout + `/tmp/clide-testmode.log`
|
||||||
|
Last line is machine-readable JSON: `{"passed":N,"failed":M,"total":N+M,"failures":[...]}`
|
||||||
|
|
||||||
|
### When to run
|
||||||
|
|
||||||
|
| Changed area | Category | Why |
|
||||||
|
|-------------|----------|-----|
|
||||||
|
| Toolchain, PATH, ptyc | `toolchain` | Binary resolution + exec |
|
||||||
|
| IPC envelope, dispatcher | `ipc` | Round-trip + error contract |
|
||||||
|
| Extension manifest, activate | `extensions` | Register + activate lifecycle |
|
||||||
|
| Theme YAML, loader | `extensions` | Theme parse is in this category |
|
||||||
|
| Platform config | `all` | Full rebuild validates everything |
|
||||||
|
| Any doubt | `all` | ~30s, cheap insurance |
|
||||||
|
|
||||||
|
### Interpreting output
|
||||||
|
|
||||||
|
- `[testmode] exec | ... | OK` — subprocess ran, exit 0 or 1
|
||||||
|
- `[testmode] PASS | ...` — assertion passed
|
||||||
|
- `[testmode] FAIL | ...` — assertion failed
|
||||||
|
- `[testmode] exec | ... | EXCEPTION` — binary not found or not executable
|
||||||
|
- `[testmode] exec | ... | TIMEOUT` — subprocess hung
|
||||||
|
|
||||||
|
If no `[testmode]` lines appear, the testmode gate didn't fire — verify
|
||||||
|
`CLIDE_TESTMODE` is set to a non-empty string.
|
||||||
|
|
||||||
|
### Adding tests
|
||||||
|
|
||||||
|
All test logic in `lib/test_app.dart`. Pattern:
|
||||||
|
```dart
|
||||||
|
await _testExec('label', binary, ['args'], workDir);
|
||||||
|
// or
|
||||||
|
_addResult('label', boolCondition, 'detail string');
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Repo Layout
|
||||||
|
|
||||||
|
```
|
||||||
|
lib/
|
||||||
|
main.dart # Flutter entry point
|
||||||
|
app.dart # Root layout, workspace, panels
|
||||||
|
clide.dart # Barrel: shared types
|
||||||
|
src/ # Core subsystems (IPC, PTY, git, files, pql, panes)
|
||||||
|
kernel/ # Kernel services (theme, i18n, settings, panels)
|
||||||
|
builtin/ # Built-in extensions
|
||||||
|
widgets/ # Custom widget primitives
|
||||||
|
extension/ # Extension contract and registration
|
||||||
|
lua/ # Lua runtime support
|
||||||
|
|
||||||
|
test/ # All tests (core + widgets + goldens + a11y)
|
||||||
|
assets/ # Fonts, themes, grammars, licenses, logo
|
||||||
|
linux/, macos/, web/ # Flutter platform directories
|
||||||
|
native/ # Vendored native libs (tree-sitter, dugite)
|
||||||
|
governance/ # D/Q/R records
|
||||||
|
docs/ # Design docs, wireframes
|
||||||
|
legacy/ # Python Textual clide v1.2 (frozen)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Dependency & Supply Chain Discipline
|
||||||
|
|
||||||
|
- **Prefer-zero-deps.** Flutter-SDK widgets first; third-party needs justification
|
||||||
|
- **Exact-pinned in pubspec.yaml** — no caret ranges
|
||||||
|
- **Advisories reviewed** before every bump
|
||||||
|
- **pubspec.lock committed**
|
||||||
|
- **Document every bundled dependency** in `assets/licenses.yaml`:
|
||||||
|
- name, kind, version, homepage, license, purpose
|
||||||
|
- Adding a dep: two-step commit — artefact AND `licenses.yaml` entry
|
||||||
|
- Native deps (dugite, libtree-sitter): vendored in `native/`, pinned by SHA
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Pre-push Gate
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make push-check
|
||||||
|
```
|
||||||
|
|
||||||
|
Runs: decisions validation + core tests + fast suite + a11y + coverage + changelog
|
||||||
|
|
||||||
|
**Never bypass.** If it fails, fix the underlying issue.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Session Setup
|
||||||
|
|
||||||
|
One-time setup on fresh clone:
|
||||||
|
```bash
|
||||||
|
make hooks && flutter pub get
|
||||||
|
pql init # wires up pql skill + perms
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Mistral-Specific Notes
|
||||||
|
|
||||||
|
### What to preserve from Claude
|
||||||
|
|
||||||
|
- CLI-first interaction model
|
||||||
|
- Strict guardrails enforcement
|
||||||
|
- Logically-separated commits
|
||||||
|
- Changelog discipline (60-word cap)
|
||||||
|
- pql as single source of truth for decisions/tickets
|
||||||
|
- UI/CLI parity
|
||||||
|
- Testmode for integration validation
|
||||||
|
|
||||||
|
### What to adapt
|
||||||
|
|
||||||
|
- **Tool names:** Claude's `Bash(...)` → my `bash` tool
|
||||||
|
- **Agent spawning:** Claude's `Agent{}` → my `task` tool for subagents
|
||||||
|
- **Permissions:** `.claude/settings.json` allow/deny → my system prompt + your instructions
|
||||||
|
|
||||||
|
### When in doubt
|
||||||
|
|
||||||
|
Ask: "What would Claude do?" Then do that. The AGENTS.md is the bridge,
|
||||||
|
not a replacement.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick Reference Card
|
||||||
|
|
||||||
|
| Task | Command |
|
||||||
|
|------|---------|
|
||||||
|
| Discover clide commands | `clide capabilities` |
|
||||||
|
| See current UI state | `clide status` |
|
||||||
|
| Open ticket in UI | `clide ui open tickets T-NNN` |
|
||||||
|
| Toast notification | `clide ui toast "msg" --severity info` |
|
||||||
|
| List actionable tickets | `pql ticket list --under <id> --leaf --unblocked --status backlog --pretty` |
|
||||||
|
| Sync decisions | `pql decisions sync` |
|
||||||
|
| Run integration tests | `make run-testmode` |
|
||||||
|
| Fast test suite | `make test` |
|
||||||
|
| Full pre-push | `make push-check` |
|
||||||
|
| Commit with message | `git commit -m "$(cat <<'EOF'\n<message>\nEOF\n)"` |
|
||||||
|
| Verify changelog | `make changelog-gate` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Generated for Mistral Vibe. Preserves Claude Code punch for clide repo.*
|
||||||
+607
@@ -16,6 +16,613 @@ heading, and (b) bumping `pubspec.yaml` `version:` in the same commit.
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
## [2.10.0] — 2026-07-13
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **Canvas pane.** `.canvas` (Obsidian JSONCanvas) files now open in an
|
||||||
|
interactive workspace pane — each document a sub-tab, with pan, zoom, and
|
||||||
|
node selection. Routed from the file tree, quick-open, and
|
||||||
|
`clide ui open canvas <path>`. (T-322)
|
||||||
|
- **Vault graph view.** A force-directed link graph of the whole vault in the
|
||||||
|
context panel — notes are nodes, wikilinks edges. Hover highlights a note's
|
||||||
|
neighbourhood; click opens it. Scroll to zoom, drag to pan; filter by path
|
||||||
|
glob, tag include/exclude, or depth from the active note. (T-323)
|
||||||
|
- **Per-workspace PATH preset.** Directories prepended to the PATH of every
|
||||||
|
shell clide spawns for a repo — Claude sessions and terminal panes. Settings
|
||||||
|
→ Tools → Workspace PATH, or `clide env path …` with capture-from-login-shell
|
||||||
|
suggestions. Worktrees share their repo's preset; stored machine-local, never
|
||||||
|
committed. (D-106, T-511)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Permission mode: Ctrl/Cmd+Shift+M cycles the full list including
|
||||||
|
bypassPermissions, and the composer menu's bypass row unlocks via
|
||||||
|
shift-click — plain Ctrl/Cmd+M and plain clicks stay safe-trio only (T-510).
|
||||||
|
- Bundled Claude skills pruned to clide-specific ones (T-507): broken/duplicate
|
||||||
|
skills removed, repo-agnostic ones moved to user scope, and stale guidance in
|
||||||
|
the remaining five (paths, commands, icon API) brought back in line with the
|
||||||
|
repo.
|
||||||
|
- The `clide` skill description now leads with the hosting mechanics (`clide`
|
||||||
|
on PATH, `CLIDE_SOCK`) and `clide capabilities` as the entry action, so an
|
||||||
|
agent deciding whether to invoke it sees the first move up front (T-512).
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Hash-keyed settings (per-workspace PATH presets, Claude account bindings)
|
||||||
|
with a number-shaped hash suffix were silently lost on restart — YAML map
|
||||||
|
keys are now quoted on write.
|
||||||
|
|
||||||
|
## [2.9.0] — 2026-06-30
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **Graph cards.** `clide draw --file graph.json` (template `graph`) renders a
|
||||||
|
nodes/edges graph in the conversation as a circular layout — labelled nodes,
|
||||||
|
lines between them. Honest error on a duplicate id or an edge to an unknown
|
||||||
|
node. (T-321)
|
||||||
|
- **Piped `--stdin` payloads.** `cat icons.json | clide icon show --stdin` (and
|
||||||
|
`image show`) accept a JSON payload on stdin — the ergonomic peer of `--file`
|
||||||
|
for structured commands. (T-315)
|
||||||
|
- **Before/after compare cards.** `clide draw --file compare.json` (template
|
||||||
|
`compare`) renders two or more images side by side, each with its own
|
||||||
|
label/description and tap-to-zoom; images aspect-fit so differing shapes
|
||||||
|
don't distort. (T-319)
|
||||||
|
- **Phosphor glyph cards.** `clide icon show gear folder` (or `--file` entries
|
||||||
|
with label/description/color) renders glyphs in the conversation at a hero
|
||||||
|
size plus a real-UI-size strip (10–48), for previewing and comparing icons.
|
||||||
|
Resolves by name or 0xNNNN codepoint; honest error on an unknown glyph. (T-313)
|
||||||
|
- **Annotated image cards.** `clide image show --file meta.json` attaches a
|
||||||
|
title/label and a longer description to an image card (alongside the existing
|
||||||
|
one-line caption); the bare `image show <path> --caption` form is unchanged.
|
||||||
|
Visual marker overlays remain a follow-up. (T-316)
|
||||||
|
- **D2 diagram cards.** `clide draw --file diagram.d2` compiles a d2 diagram to
|
||||||
|
SVG (via the `d2` binary) and renders it in the conversation; `template:"d2"`
|
||||||
|
with inline source works too, and a `.svg` file renders directly. Honest error
|
||||||
|
if d2 isn't installed or the source doesn't compile. (T-494, D-103)
|
||||||
|
- **Tool path resolution + settings.** clide resolves supporter binaries (claude,
|
||||||
|
d2) via an explicit per-tool path, else PATH and the common install dirs — now
|
||||||
|
including Homebrew-on-Linux. A Tools settings category edits the paths and
|
||||||
|
re-detects; a broken path shows in Problems. (T-495, D-104)
|
||||||
|
- **Check for updates (About box).** Help → About has a manual "Check for
|
||||||
|
updates" button that compares your version to the latest GitHub release and
|
||||||
|
links to the notes — explicit and user-initiated, no background polling (the
|
||||||
|
first and only outbound call clide makes, on your action). (T-47)
|
||||||
|
- **Live-sync markdown read-mirror.** Editing a `.md` in the editor auto-opens a
|
||||||
|
read-only preview in the context panel that mirrors the buffer and re-renders
|
||||||
|
as you type; non-renderable files get no auto-viewer. (T-36, D-50)
|
||||||
|
- **New project flow.** A "New project…" action in the welcome view creates +
|
||||||
|
opens a project, then prompts for the Claude account to bind it to — the
|
||||||
|
per-repo account roadblock fires only for freshly-created projects. (T-488,
|
||||||
|
story T-486)
|
||||||
|
- **Initialize a non-repo folder.** Opening a folder that isn't a git repo now
|
||||||
|
offers to initialize it as a clide project (`git init` + scaffold + the
|
||||||
|
account roadblock) instead of dead-ending. Also `clide project init`. (T-489)
|
||||||
|
- **`clide project new <name> [--dir <parent>]`.** Create a new clide project —
|
||||||
|
a fresh dir, `git init`, and a minimal scaffold. `--dir` defaults to the
|
||||||
|
current workspace's parent. (T-487, story T-486)
|
||||||
|
- **Claude account login pane.** `account login` (and the UI add/re-login
|
||||||
|
affordances) open a modal terminal running `CLAUDE_CONFIG_DIR=<dir> claude
|
||||||
|
login`; the CLI owns the OAuth flow, credentials land in that account's dir.
|
||||||
|
(T-485, epic T-476)
|
||||||
|
- **Claude pane account badge.** The pane header shows which account this repo
|
||||||
|
is bound to (colour-tinted per account); tap to switch. Hidden when no
|
||||||
|
accounts are registered. (T-481, epic T-476)
|
||||||
|
- **Settings → Claude → Accounts.** A registry list (sign-in status, dir,
|
||||||
|
re-login / remove, add) plus a per-workspace picker that binds this repo to an
|
||||||
|
account (or Default); switching respawns the pane onto it. (T-482, epic T-476)
|
||||||
|
- **Per-repo Claude accounts — `clide claude account` verbs.** Manage named
|
||||||
|
Claude config dirs and bind one per workspace: `add`/`list`/`set`/`unset`/
|
||||||
|
`remove [--purge]`. `set`/`unset` respawn the workspace's Claude pane(s) onto
|
||||||
|
the bound account (resuming the conversation under its `CLAUDE_CONFIG_DIR`).
|
||||||
|
(T-480, epic T-476)
|
||||||
|
- **`clide instances` / `clide instance` CLI verbs.** `instances` lists every
|
||||||
|
live clide on the machine with its version, pid, workspace, and socket path
|
||||||
|
(probing the runtime dir); `instance` reports the one you're connected to — so
|
||||||
|
you can find and target a specific instance via `CLIDE_SOCK`. (T-247)
|
||||||
|
- **Summer Night theme + high-contrast sibling.** The legacy v1.2 palette is
|
||||||
|
fleshed out to full token + syntax coverage and ships alongside a
|
||||||
|
contrast-hardened `summer-night-hc`, both selectable in Settings → Appearance.
|
||||||
|
(T-478)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- **Fresh Claude sessions are nudged to use the bundled skills.** New tabs and
|
||||||
|
post-`/clear` respawns get a one-line prompt to load the `pql` + `clide`
|
||||||
|
skills from the first turn; resumed/forked sessions are left alone. (T-490)
|
||||||
|
- **Claude meta sidebar facelift.** The Activity, Team, and Config tabs render
|
||||||
|
their sections as elevated cards with small-caps headers, matching the
|
||||||
|
settings overlay's card design. (T-158)
|
||||||
|
- **Bundled themes and Tier-0 i18n namespaces resolve from one canonical list
|
||||||
|
each.** The app, testmode harness, and contrast/i18n gates iterate the shared
|
||||||
|
lists instead of drifting copies; a new theme or catalog is validated
|
||||||
|
automatically, and the i18n gate now checks every catalog for en/nl parity.
|
||||||
|
(T-371)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **No more i18n "missing key" log spam for tool names.** Proper-name tools
|
||||||
|
(Bash, ScheduleWakeup, MCP tools, …) intentionally have no catalog entry and
|
||||||
|
fall back to the raw name; the conversation pane no longer logs a warning for
|
||||||
|
each. (T-493)
|
||||||
|
- **`clide` CLI honors `CLIDE_SOCK`.** The shell client now connects to the
|
||||||
|
socket named by `CLIDE_SOCK` when set — an explicit target (e.g. a spawned
|
||||||
|
agent pinning its parent instance) that beats workspace auto-discovery — and
|
||||||
|
fails loudly if that socket is dead instead of silently driving a different
|
||||||
|
instance. (T-247)
|
||||||
|
- **Orphaned IPC sockets are swept on startup.** The app probes the runtime
|
||||||
|
socket dir on launch and unlinks dead `*.sock` nodes left by crashed
|
||||||
|
instances (live instances are left untouched), so the dir no longer
|
||||||
|
accumulates stale sockets. (T-247)
|
||||||
|
- **Default window opens larger (1600×900) on Linux.** 720p was short enough
|
||||||
|
that the welcome screen's version/theme footer overlapped the tips card;
|
||||||
|
the taller default clears it, matching the macOS default. (T-477)
|
||||||
|
- **Editor split collapses when the last buffer closes.** Closing the final
|
||||||
|
editor buffer left the top split orphaned over the Claude pane; the daemon
|
||||||
|
now emits the buffer-cleared event it was suppressing, so the split drops
|
||||||
|
out and the primary pane fills the column. (T-459)
|
||||||
|
|
||||||
|
## [2.8.0] — 2026-06-19
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **Language selector + Dutch (nl-NL).** Settings → Appearance → Language
|
||||||
|
switches the UI language live (persisted as `app.locale`); a full Dutch
|
||||||
|
translation ships. English (en-US) stays the default. (T-462)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- **App is fully localizable (i18n everywhere).** Every user-facing label —
|
||||||
|
panels, dialogs, command palette, menus, and settings — now resolves through
|
||||||
|
the i18n catalog instead of a hardcoded string; catalogs are bundled per
|
||||||
|
locale under `assets/i18n/<locale>/`. A new language is a drop-in folder;
|
||||||
|
en_US behaviour is unchanged. (T-462)
|
||||||
|
|
||||||
|
## [2.8.1] — 2026-06-22
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **Localized the remaining Claude-pane strings.** Running-indicator verbs, the
|
||||||
|
primary/secondary session titles and banner role, tool-card titles, the
|
||||||
|
step/edit/agent counters, and the folded-activity ticker now resolve through
|
||||||
|
the catalog — completing i18n coverage of the conversation surface. (T-462)
|
||||||
|
|
||||||
|
## [2.7.1] — 2026-06-18
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- **Josefin Sans is the default UI font again.** Reverts the Inter default from
|
||||||
|
2.7.0; Inter stays bundled and selectable in Settings → Appearance. JetBrains
|
||||||
|
Mono remains the default monospace face (Fira Mono selectable). (T-460)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **Markdown prose honours the UI-font setting.** Claude's conversation prose
|
||||||
|
and inline links render through the markdown engine, which pinned the bundled
|
||||||
|
UI face and ignored the Appearance UI-font pick; it now follows the setting
|
||||||
|
live, like the rest of the app. (T-475)
|
||||||
|
|
||||||
|
## [2.7.0] — 2026-06-17
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **Settings panel shell.** A new `settings.open` command (⌘`,`, plus a File
|
||||||
|
menu and command-palette entry) opens a centered Settings modal over the
|
||||||
|
dimmed app — the foundation of the schema-driven settings UI. It frames the
|
||||||
|
category rail and scrolling carded panel that later work fills in; closes on
|
||||||
|
✕, Esc, or a barrier tap. (T-445)
|
||||||
|
|
||||||
|
- **Schema-driven settings engine.** Subsystems register a `SettingsCategory`
|
||||||
|
(via `SettingsCategoryContribution` → the kernel `SettingsRegistry`); the
|
||||||
|
panel renders it as carded sections of toggle/select/text/number/file rows,
|
||||||
|
each bound to a `SettingsStore` key with help and reset-to-default.
|
||||||
|
Registering a category surfaces a new tab. (T-448)
|
||||||
|
|
||||||
|
- **Settings category rail.** The modal's left rail lists the registered
|
||||||
|
categories (icon + title, data-driven from the registry) with an accent
|
||||||
|
left-stripe + surfaceHi selection; picking one swaps the panel. (T-447)
|
||||||
|
|
||||||
|
- **Per-field scope tags.** Each field shows where its value lives — folder =
|
||||||
|
Project (`.clide`), globe = Always (`~/.clide`), circle-dashed =
|
||||||
|
Default/unset — with a tooltip and a menu to move the value between scopes or
|
||||||
|
reset it. Backed by scope-explicit `SettingsStore` access. (T-449)
|
||||||
|
|
||||||
|
- **Cross-category settings search.** A search box atop the rail filters fields
|
||||||
|
across every category; the panel shows the matches grouped under category
|
||||||
|
subheaders (editable inline), and each rail row shows its match count with
|
||||||
|
zero-match categories dimmed. (T-450)
|
||||||
|
|
||||||
|
- **Settings → Activity category.** The first real settings tab: the
|
||||||
|
conversation fold level (none / tools / thinking / everything) as a schema
|
||||||
|
field; picking a level applies live to the activity stream. (T-453)
|
||||||
|
|
||||||
|
- **Settings → Keymap category.** A preset select (Default / Vim / VS Code /
|
||||||
|
JetBrains); picking one switches the active keymap live via the preset
|
||||||
|
command. (T-451)
|
||||||
|
|
||||||
|
- **Settings → Appearance category.** A theme picker in the panel — base-theme
|
||||||
|
chips + a high-contrast toggle, applied live. Adds the engine's custom-control
|
||||||
|
escape hatch (`SettingsControlContribution` / `SettingsControlRegistry`) for
|
||||||
|
one-off controls the generic field kinds can't express. (T-452)
|
||||||
|
|
||||||
|
- **Settings → Extensions tab.** A "watch this space" notice — installing and
|
||||||
|
toggling extensions arrives with third-party (Lua) support; built-ins stay
|
||||||
|
always-on for now. (T-456)
|
||||||
|
|
||||||
|
- **Settings → Claude category.** New-session defaults — model, effort, and
|
||||||
|
permission mode — seed fresh sessions (effort via `--effort` at spawn;
|
||||||
|
model and permission applied right after start). (T-457)
|
||||||
|
|
||||||
|
- **Inter is the default UI font + a UI-font picker.** Bundled Inter (variable)
|
||||||
|
as the default interface typeface — Josefin Sans stays selectable — and
|
||||||
|
Settings → Appearance gains a UI-font picker that applies live. (T-460)
|
||||||
|
|
||||||
|
- **Monospace font picker.** Settings → Appearance adds a monospace font select
|
||||||
|
(JetBrains Mono / Fira Mono) that applies live to the terminal, diffs, code,
|
||||||
|
and IDs. Bundles Fira Mono. (T-471)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- **Theme picker relabelled "Theme…".** The ⌘K theme picker's command title
|
||||||
|
changed from "Settings…" to "Theme…" so it no longer collides with the new
|
||||||
|
Settings panel in the palette; behaviour is unchanged. (T-445)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **Monospace setting now applies everywhere.** Eleven context-free render
|
||||||
|
helpers (Claude tool bodies + results, inline markdown code/refs, search
|
||||||
|
previews, welcome tips) hard-coded JetBrains Mono and ignored the Monospace
|
||||||
|
font setting; they now honour it live. (T-472)
|
||||||
|
|
||||||
|
## [2.6.0] — 2026-06-16
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **Vim `gt` / `gT` tab motions.** Under the Vim preset, `gt`/`gT` cycle the
|
||||||
|
workspace tab strip (the same `workspace.tab.*` commands as `ctrl+pagedown`/
|
||||||
|
`ctrl+pageup`), resolved by the focused editor or pane and sharing the `g`
|
||||||
|
prefix with `gg`. Completes the T-403 cross-pane vim layer. (T-405)
|
||||||
|
|
||||||
|
- **Vim ex command-line (`:`).** Under the Vim preset, `:` opens a transient
|
||||||
|
one-line overlay running a fixed table — `:w` save, `:q` close the active tab
|
||||||
|
(the split self-collapses on the last one), `:wq`/`:x` and `ZZ` save+close,
|
||||||
|
`:e <path>` jump to quick-open seeded with the path, `:<n>` goto-line. Unknown
|
||||||
|
commands flash and stay open; with no active buffer it no-ops. Opens from the
|
||||||
|
editor or a focused pane; Esc dismisses. Adds the `editor.goto-line` CLI/IPC
|
||||||
|
verb. (T-407)
|
||||||
|
|
||||||
|
- **Crash-survivable logging.** clide writes a durable JSON-lines log to a
|
||||||
|
persistent per-platform dir (Windows `%LOCALAPPDATA%`, macOS `~/Library/Logs`,
|
||||||
|
Linux `$XDG_STATE_HOME`), fsyncing warn/error + pty/ffi records immediately so
|
||||||
|
a freeze leaves on-disk evidence. `CLIDE_LOG` (dart-define / env) or the
|
||||||
|
`app.log.level` setting sets verbosity (warn in release, info in debug);
|
||||||
|
`CLIDE_LOG_DIR` redirects where the logs land. (T-432, T-436)
|
||||||
|
- **PTY FFI breadcrumbs.** Each PTY backend drops a breadcrumb before/after
|
||||||
|
every risky syscall (`CreatePseudoConsole`/`CreateProcessW`/`ReadFile`,
|
||||||
|
`posix_spawn`/`read`); the reader/waiter isolates fsync their OWN file handle
|
||||||
|
so a wedged isolate's last crumb survives a freeze that also froze the main
|
||||||
|
isolate — naming the wedge after the fact. Per-syscall crumbs at debug level.
|
||||||
|
(T-434)
|
||||||
|
- **Crash-diagnostic watchdog.** A dedicated isolate fsyncs a heartbeat every
|
||||||
|
~500ms (bounding a freeze to ~500ms) and every ~2s samples this process's
|
||||||
|
thread / handle / child-host / RSS counts to `clide-watchdog.log` — a climbing
|
||||||
|
child or thread count is the leak signature. Survives a frozen main isolate;
|
||||||
|
spawn failure is non-fatal. (T-435)
|
||||||
|
- **Live log-verbosity toggle.** The output dock's Level chip now sets the
|
||||||
|
running logger's level and persists `app.log.level` (not just a view filter),
|
||||||
|
and `clide log level [<level>]` does the same from the CLI — D-6 parity. The
|
||||||
|
choice survives restart. (T-433)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **`/clear` no longer kills the Claude pane.** Clearing the primary pane tore
|
||||||
|
the session down and respawned on the same deterministic `--session-id`
|
||||||
|
*before the old `claude` process had actually exited*, so claude 2.1.177
|
||||||
|
rejected the id as "already in use" and the respawn exited 1. The session
|
||||||
|
teardown now awaits the process's real death (SIGTERM, escalating to SIGKILL)
|
||||||
|
before clearing the transcript and respawning. A dead pane also now shows the
|
||||||
|
CLI's own reason instead of a bare "exited (code 1)". (T-437)
|
||||||
|
- **Web/WASM build compiles again.** `flutter build web --wasm` (and the
|
||||||
|
`test-e2e` / `ui-dev` / `ui-smoke` harness) had been broken since the
|
||||||
|
tree-sitter/PTY `dart:ffi` pivot. Every native binding (PTY, tree-sitter, the
|
||||||
|
Lua host, the Windows watchdog, the ABI/fd-inheritance probes) now sits behind
|
||||||
|
a `dart.library.ffi` conditional import with a graceful web stub, and the FNV
|
||||||
|
hash constants are dart2js-safe. A `flutter build web --wasm` compile gate was
|
||||||
|
added to CI so the fence can't silently rot. Desktop builds are unchanged — the
|
||||||
|
web target degrades (no terminal, no native git, no syntax highlighting), it
|
||||||
|
does not compromise desktop fidelity. (T-438, D-100, Q-50)
|
||||||
|
- **Desktop-launched clide finds your installed tools.** A dock/launcher start
|
||||||
|
inherits a sparse `PATH` (no `~/.local/bin`, brew, nvm, …), so pql/git/claude
|
||||||
|
and terminal tools could go missing. clide now resolves the real login-shell
|
||||||
|
`PATH` once at startup (`$SHELL -l -c`, bounded + graceful fallback) and routes
|
||||||
|
every spawn site — PTY children, git, the toolchain probe, hosted claude —
|
||||||
|
through one shared resolver, replacing three divergent (and partly macOS-only)
|
||||||
|
PATH expanders. (T-439, follows T-347)
|
||||||
|
|
||||||
|
## [2.5.0] — 2026-06-14
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **Experimental Windows desktop support.** clide builds and runs on Windows —
|
||||||
|
ConPTY-backed terminals, an AF_UNIX `clide` CLI client, PowerShell as the
|
||||||
|
default shell, and a `make build-windows` target. Preview quality: ConPTY
|
||||||
|
child-process reaping under sustained use is still being hardened. (T-424)
|
||||||
|
- **Vim `ctrl+w` window commands.** Under the vim preset, `ctrl+w` followed by
|
||||||
|
h/l (focus left/right panel), j (toggle dock), w / ctrl+w (cycle panels),
|
||||||
|
shift+w (cycle back), o (focus mode), or q/c (close editor). A new global
|
||||||
|
multi-chord matcher in the shell resolves these from any focus; bare `ctrl+w`
|
||||||
|
still closes the editor after the ambiguity timeout. (T-404)
|
||||||
|
- **Workspace tab cycling with ctrl+pagedown / ctrl+pageup.** New
|
||||||
|
`workspace.tab.next` / `workspace.tab.previous` commands cycle the workspace
|
||||||
|
tab strip with wraparound, bound across every preset. (T-405)
|
||||||
|
- **Vim normal-mode navigation works outside the editor.** Under the vim preset,
|
||||||
|
a focused file tree or conversation now responds to j/k, ctrl+d/ctrl+u, gg/G,
|
||||||
|
and (tree) h/l/o — a selection cursor in the tree, scrolling in the
|
||||||
|
conversation. Each pane runs its own sequence matcher; an `editor.focused`
|
||||||
|
flag keeps these keys as buffer motions while the editor holds focus. (T-406)
|
||||||
|
- **Claude Code Workflow runs surface in the conversation and sidebar.** A
|
||||||
|
`Workflow` tool-use renders a dedicated run card — phase groups, per-agent
|
||||||
|
rows with live spinner/check status, usage, and the script — driven by the
|
||||||
|
harness's out-of-band progress events. The Activity tab adds a WORKFLOWS
|
||||||
|
section showing each run's done/total agent count. (T-416)
|
||||||
|
- **Session controls and live usage in the Claude sidebar Activity tab.** A
|
||||||
|
SESSION strip offers clear/compact/fork/resume buttons (same code path as the
|
||||||
|
typed commands), and a refresh control fetches `/usage` — plan usage renders
|
||||||
|
as a USAGE block (session and weekly percentages). The runtime row now also
|
||||||
|
shows the session's effort level. (T-415)
|
||||||
|
- **The Claude sidebar Config tab is a live control panel.** Model, effort, and
|
||||||
|
permission mode are popover controls showing the running session's values;
|
||||||
|
picking an option drives the session through the same path as the typed slash
|
||||||
|
command. The sidebar tables also got a visual pass — larger type, accent
|
||||||
|
section headers, more breathing room. (T-414)
|
||||||
|
- **The TUI command family opens clide surfaces.** `/permissions` sets the mode
|
||||||
|
directly or opens a picker; `/status`, `/config`, `/mcp`, `/agents`, `/hooks`
|
||||||
|
jump to the matching Claude sidebar tab; `/memory` opens CLAUDE.md in the
|
||||||
|
editor; `/help` shows clide's own command summary. (T-413)
|
||||||
|
- **`/effort` works in the Claude pane.** With a level (`/effort xhigh`) the
|
||||||
|
session restarts in place carrying `--effort` — resume keeps the
|
||||||
|
conversation; bare `/effort` opens a picker with the five levels and the
|
||||||
|
current one marked. The active effort shows in the session status. (T-412)
|
||||||
|
- **TUI-only slash commands get a helpful notice instead of failing.** A typed
|
||||||
|
`/cost` or `/doctor` no longer errors raw from the CLI or leaks to the model
|
||||||
|
as literal text — known TUI-only commands route to a muted notice card with
|
||||||
|
the clide-native way. CLI-local output (like `/usage`) renders as a "clide"
|
||||||
|
card, never fake Claude prose. (T-411)
|
||||||
|
- **`/model` works in the Claude pane.** With a name (`/model sonnet`) it
|
||||||
|
switches the live session's model over the control channel; bare `/model`
|
||||||
|
opens a picker in the interaction zone with the CLI's model list and the
|
||||||
|
current model marked. A rejected name rolls back and raises a toast. (T-408)
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- **tmux is no longer a required tool.** clide stopped spawning tmux when Claude
|
||||||
|
session persistence moved to `--resume` (D-77); the toolchain no longer probes
|
||||||
|
for it or warns when it's absent, on any platform.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **`ClaudeConfig` no longer crashes on a project switch that races teardown.**
|
||||||
|
`setProjectDir` / `refresh` / `ensureProbe` now skip `notifyListeners()` if the
|
||||||
|
config was disposed during their async load (the guard `load()` already had).
|
||||||
|
|
||||||
|
## [2.4.1] — 2026-06-12
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **`Shift+;` types a colon again — double-Shift no longer fires on chorded
|
||||||
|
Shift.** The double-tap detector counted any Shift press as a tap, even
|
||||||
|
mid-chord, and never saw keys the focused editor consumed; a tap now
|
||||||
|
requires a clean press-and-release, observed at the raw-keyboard level.
|
||||||
|
(T-409)
|
||||||
|
|
||||||
|
## [2.4.0] — 2026-06-12
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **Live tail inside expanded Bash activity cards.** A Bash card that follows a
|
||||||
|
file (`tail -f …`) now shows a live, scrolling read-only tail of that file
|
||||||
|
below the result — connected only while the card is expanded. Commands with no
|
||||||
|
followable file show a muted "nothing to follow" note. (T-325)
|
||||||
|
|
||||||
|
- **Double-tap-modifier shortcuts (e.g. double-Shift "Search Everywhere").**
|
||||||
|
The keymap can now bind a bare modifier and a double-tap sequence
|
||||||
|
(`shift shift`). All four presets (default, vim, vscode, jetbrains) map
|
||||||
|
double-Shift to the quick-open finder — JetBrains' "Search Everywhere"
|
||||||
|
gesture, aliased to clide's existing fuzzy file finder. (T-341)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- **Each spawned subagent gets its own collapsing activity card.** A fan-out of
|
||||||
|
N agents no longer merges into one "Activity / N steps" cluster — each spawn is
|
||||||
|
its own card with its prompt and nested run. Non-agent tool calls still group
|
||||||
|
as before. (T-342)
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- **Dead-code sweep.** The legacy free-function git API (with its latent
|
||||||
|
pipe deadlock), ToolCheck, the fd-passing-era libc bindings, the GraphView
|
||||||
|
placeholder, the superseded ColumnHat widget, the tmux-era
|
||||||
|
TranscriptPublisher, the committed `ptyc` binary, and the unused
|
||||||
|
`mocktail` dev-dependency (D-25 amended) are gone. (T-385)
|
||||||
|
|
||||||
|
- **Dead welcome-screen tiles.** "Clone from git…" and "Start a Claude
|
||||||
|
session" did nothing on tap and advertised shortcuts that were never
|
||||||
|
registered; the tips card now lists only shortcuts that exist in the
|
||||||
|
default keymap. Each tile returns when its flow ships. (T-383)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **Terminal CSI sequences with intermediate bytes no longer mis-dispatch.**
|
||||||
|
The parser dropped intermediates, so e.g. VT420 scroll-left (`CSI 5 SP @`)
|
||||||
|
executed as "insert 5 blank characters"; such sequences are now reported
|
||||||
|
as unknown instead. (T-123)
|
||||||
|
|
||||||
|
- **PTY master fd no longer leaks when a child exits on its own.** Every
|
||||||
|
terminal or Claude pane whose process ended naturally left its pty device
|
||||||
|
open for the life of the app; natural exit now releases the fd. (T-360)
|
||||||
|
|
||||||
|
- **Closing a terminal pane now closes its shell.** Pane disposal looked up
|
||||||
|
the kernel illegally and swallowed the failure, so `pane.close` was never
|
||||||
|
sent — the backend PTY and daemon pane leaked on every closed terminal
|
||||||
|
pane, and Claude panes leaked a settings listener the same way. (T-366)
|
||||||
|
|
||||||
|
- **Scrolling up during a streaming reply no longer fights the auto-scroll.**
|
||||||
|
The conversation followed the tail on every streamed token regardless of
|
||||||
|
scroll position, dragging a reader back to the bottom; it now follows only
|
||||||
|
while already pinned there. (T-368)
|
||||||
|
|
||||||
|
- **The terminal no longer crashes on truncated SGR color sequences.**
|
||||||
|
`ESC[38m` and friends threw a RangeError inside the emulator; incomplete
|
||||||
|
38/48 sequences are now ignored, and colon-form truecolor/256-color
|
||||||
|
sub-parameters (`38:2:r:g:b`, ITU T.416) parse like the semicolon form
|
||||||
|
instead of being mangled. (T-369)
|
||||||
|
|
||||||
|
- **File listing flags symlinks again and the workspace walk no longer
|
||||||
|
follows them.** Symlink detection was dead code, so `files.walk` (and the
|
||||||
|
search engine on top of it) silently descended symlinked directories —
|
||||||
|
including ones pointing outside the workspace. (T-365)
|
||||||
|
|
||||||
|
- **Search-and-replace now honors its include/exclude globs.** The filters
|
||||||
|
were accepted but never applied, so replace could rewrite files outside
|
||||||
|
the scope the user typed; replace now uses the same glob filtering as
|
||||||
|
search. (T-364)
|
||||||
|
|
||||||
|
- **Switching projects releases the previous workspace's services.** The old
|
||||||
|
file watcher, pane PTYs, in-flight searches, and editor buffers were left
|
||||||
|
alive on every project switch, with stale watcher events leaking into the
|
||||||
|
new workspace. (T-367)
|
||||||
|
|
||||||
|
- **Expanded activity cards are readable by screen readers again.** The
|
||||||
|
collapser's summarized button semantics excluded the whole card, so
|
||||||
|
expanding a run announced nothing inside it; the exclusion is now scoped
|
||||||
|
to the header and the inner cards stay in the a11y tree. (T-370)
|
||||||
|
|
||||||
|
- **A crashed Claude process no longer looks like it's still thinking.**
|
||||||
|
stderr is now drained continuously (an undrained pipe could block the
|
||||||
|
child mid-turn) and the exit code is watched: when the process dies the
|
||||||
|
pane stops spinning, clears any unanswerable permission prompt, reports
|
||||||
|
the exit in the status line, and logs the stderr tail. (T-361)
|
||||||
|
|
||||||
|
- **The Claude status bar populates reliably after a session starts.** The
|
||||||
|
session's init event often fired before the pane subscribed and the plain
|
||||||
|
broadcast stream dropped it, leaving the model/mode/context line blank;
|
||||||
|
session state streams now replay their latest value to late subscribers.
|
||||||
|
(T-274, T-386)
|
||||||
|
|
||||||
|
- **New terminal panes open in the project root.** The shell spawned in the
|
||||||
|
app process's working directory — `$HOME` for desktop launches, and the
|
||||||
|
wrong repo after a project switch. (T-381)
|
||||||
|
|
||||||
|
- **Two simultaneous spawns of the same Claude session no longer leak a
|
||||||
|
process.** Concurrent spawn calls for one pane id both passed the registry
|
||||||
|
check and the loser's live process was orphaned; spawns for an id are now
|
||||||
|
coalesced onto one in-flight future. (T-374)
|
||||||
|
|
||||||
|
- **`/clear` in a fork pane clears instead of re-forking.** The fork source
|
||||||
|
took precedence on every respawn, so clearing a fork tab silently branched
|
||||||
|
the original conversation again; the source now seeds only the first
|
||||||
|
bind. (T-375)
|
||||||
|
|
||||||
|
- **Pipelined IPC requests are now truly serial and framing-safe.** The
|
||||||
|
server's read handler could interleave concurrent requests (against
|
||||||
|
D-72's contract), drop or double frames split across reads, and corrupt
|
||||||
|
multi-byte characters split across chunks. (T-372)
|
||||||
|
|
||||||
|
- **Settings survive nested structures, crashes, and corruption.** Maps
|
||||||
|
inside lists (the keymap overlay shape) were corrupted on save; writes
|
||||||
|
are now atomic (temp file + rename), and a file that fails to parse is
|
||||||
|
preserved as `.broken` with a logged warning instead of being silently
|
||||||
|
reset. (T-376)
|
||||||
|
|
||||||
|
- **Markdown hard breaks break lines and images leave a visible trace.**
|
||||||
|
Both rendered as empty text — words on either side of a hard break glued
|
||||||
|
together and images vanished; breaks now emit a newline and images render
|
||||||
|
an italic `[image: alt]` placeholder. (T-379)
|
||||||
|
|
||||||
|
- **Extension notifications actually appear on screen.** Messages pushed
|
||||||
|
through the kernel Notifications service (e.g. the CLI-install dogfood
|
||||||
|
warnings) accumulated in a list no surface rendered; they now raise
|
||||||
|
toasts with matching severity. (T-382)
|
||||||
|
|
||||||
|
- **Failed `clide claude.*` commands now exit non-zero.** Sixteen handlers
|
||||||
|
reported success with an error message buried in the payload, so scripts
|
||||||
|
could not detect failures like an unknown permission mode; they now
|
||||||
|
return proper error envelopes per the D-6 contract. (T-391)
|
||||||
|
|
||||||
|
- **Terminal output no longer garbles multi-byte characters split across
|
||||||
|
reads.** PTY output and live-tail bytes were decoded per chunk, turning a
|
||||||
|
rune split across reads into replacement-character noise; the terminal
|
||||||
|
now ingests bytes through a persistent decoder. (T-373)
|
||||||
|
|
||||||
|
- **Extension lifecycle is transactional.** A throw mid-activation now
|
||||||
|
unwinds every contribution it had mounted (a retry no longer
|
||||||
|
double-applies), deactivating an extension is refused while active
|
||||||
|
extensions depend on it, and duplicate contribution/command ids are
|
||||||
|
rejected instead of silently clobbering. (T-377)
|
||||||
|
|
||||||
|
- **Accepting ExitPlanMode now leaves plan mode in the conversation panel.**
|
||||||
|
Approving Claude's plan (the ExitPlanMode tool) transitioned the underlying
|
||||||
|
session out of plan mode, but clide's tracked permission mode didn't follow,
|
||||||
|
so the mode indicator and composer stayed stuck on "plan". The approval now
|
||||||
|
syncs the tracked mode to `default`. (T-337)
|
||||||
|
|
||||||
|
### Security
|
||||||
|
|
||||||
|
- **The MCP HTTP server now requires a per-start auth token.** The localhost
|
||||||
|
SSE port served the entire clide command surface unauthenticated,
|
||||||
|
bypassing the unix socket's 0600 gate; requests must now present the
|
||||||
|
token published in the 0600 `/ide` lock file. (T-362)
|
||||||
|
|
||||||
|
- **`editor.open` / `editor.save` are now workspace-confined.** Both verbs
|
||||||
|
accepted absolute paths and `..` traversal verbatim — an unconfined read
|
||||||
|
and write primitive over IPC. They now pass the same path-safety guard as
|
||||||
|
`files.read`, including a symlink re-check at save time. (T-363)
|
||||||
|
|
||||||
|
## [2.3.3] — 2026-06-11
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **Ticket/decision sidebars load on first open after a desktop launch.** A
|
||||||
|
desktop launch starts in HOME (not a git repo), and the daemon booted its
|
||||||
|
pql/git/files workspace there — so pql ran in HOME, hit a stale
|
||||||
|
`~/.pql/pql.db`, and the sidebars showed "pql … failed" until the project was
|
||||||
|
reopened (a manual refresh worked once the workspace had swapped to the repo).
|
||||||
|
The daemon now boots at the last opened project when the launch directory
|
||||||
|
isn't itself a repo, so pql targets the real workspace from the first request.
|
||||||
|
(T-352)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- **Minimum toolchain raised to honest values.** `pubspec.yaml` now declares
|
||||||
|
Flutter `>=3.35.0` / Dart `>=3.9.0` (was `3.19.0` / `3.5.0`) — the real
|
||||||
|
minimums our deps already required (`alchemist` needs Flutter 3.32; Dart 3.9
|
||||||
|
ships in Flutter 3.35). The exact build toolchain is pinned in `.fvmrc`
|
||||||
|
(Flutter 3.44.1). Moving to the Dart 3.9 language level reformatted the tree
|
||||||
|
to the new "tall" style and adopted two new lints (`unnecessary_underscores`,
|
||||||
|
`use_null_aware_elements`). (T-353)
|
||||||
|
|
||||||
|
### Security
|
||||||
|
|
||||||
|
- **Dependency audit + refresh.** Reviewed every pinned and transitive
|
||||||
|
dependency against the GitHub Advisory Database / OSV (Pub ecosystem) — no
|
||||||
|
advisory affects any current or candidate version. Refreshed the safe pins:
|
||||||
|
`ffi` 2.1.3→2.2.0, `jovial_svg` 1.1.26→1.1.30 (pulls `jovial_misc` 0.10.0 +
|
||||||
|
`xml` 7.0.1), `mocktail` 1.0.4→1.0.5, and `markdown` 7.2.2→7.3.1 (unblocked by
|
||||||
|
the Dart 3.9 floor below). Deliberately held with reasons in `pubspec.yaml`:
|
||||||
|
`alchemist` (0.13 golden churn), `test` (Flutter-SDK locked). (T-353)
|
||||||
|
- **Supply-chain gate (`make security`).** A new `security` target runs
|
||||||
|
`osv-scanner` over `pubspec.lock` and fails if any resolved dependency has a
|
||||||
|
known advisory — a hard gate on top of `dart pub`'s passive, non-failing
|
||||||
|
advisory print. Intended for the CI PR-merge pipeline (kept out of
|
||||||
|
`push-check` so dev machines don't need the scanner installed); run locally
|
||||||
|
any time with `make security`. (T-353)
|
||||||
|
|
||||||
## [2.3.2] — 2026-06-11
|
## [2.3.2] — 2026-06-11
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ An IDE for Claude Code CLI. Single Flutter package at the repo root.
|
|||||||
- **`lib/`** — all Dart code. Subsystem handlers (`lib/src/daemon/`, `lib/src/pty/`, `lib/src/ipc/`, `lib/src/git/`, `lib/src/pql/`), kernel services (`lib/kernel/`), UI widgets (`lib/widgets/`), built-in extensions (`lib/builtin/`), and the extension framework (`lib/extension/`). The Flutter app hosts the IPC server in-process (D-56). PTY spawning uses Dart FFI `posix_openpt()` + `posix_spawn()` directly.
|
- **`lib/`** — all Dart code. Subsystem handlers (`lib/src/daemon/`, `lib/src/pty/`, `lib/src/ipc/`, `lib/src/git/`, `lib/src/pql/`), kernel services (`lib/kernel/`), UI widgets (`lib/widgets/`), built-in extensions (`lib/builtin/`), and the extension framework (`lib/extension/`). The Flutter app hosts the IPC server in-process (D-56). PTY spawning uses Dart FFI `posix_openpt()` + `posix_spawn()` directly.
|
||||||
- **[`pql`](https://github.com/postmeridiem/pql)** — external supporter tool. Clide wraps it for every query surface; never re-implements it.
|
- **[`pql`](https://github.com/postmeridiem/pql)** — external supporter tool. Clide wraps it for every query surface; never re-implements it.
|
||||||
|
|
||||||
tmux owns Claude session persistence (D-41) — the app re-attaches on restart via `tmux new-session -A`. Native rendering — markdown, canvas, graph — is Dart/Flutter (`CustomPaint` + widgets), not third-party packages.
|
Claude session persistence is `--resume <session-id>` against Claude Code's transcript files (D-77, superseding the original tmux-backed D-41) — the app re-attaches on restart, no tmux required. Native rendering — markdown, canvas, graph — is Dart/Flutter (`CustomPaint` + widgets), not third-party packages.
|
||||||
|
|
||||||
Design doc: [`docs/initial-plan.md`](docs/initial-plan.md). Decisions: [`governance/`](governance/) (`D-NNN` confirmed, `Q-NNN` open, `R-NNN` rejected — see [`governance/README.md`](governance/README.md)). Python Textual predecessor under [`legacy/`](legacy/).
|
Design doc: [`docs/initial-plan.md`](docs/initial-plan.md). Decisions: [`governance/`](governance/) (`D-NNN` confirmed, `Q-NNN` open, `R-NNN` rejected — see [`governance/README.md`](governance/README.md)). Python Textual predecessor under [`legacy/`](legacy/).
|
||||||
|
|
||||||
@@ -89,6 +89,8 @@ Shell hygiene (keeps commands inside the permission allowlist, so they don't get
|
|||||||
|
|
||||||
Commit and push directly to `main` for routine work — this is a solo-dev repo and does not use a branch-first / feature-branch flow. Do **not** create a working branch just to land a change. (This overrides the generic "branch before committing on the default branch" assistant default.) The usual safety rules still hold: never `--no-verify`, never force-push `main`, and let the pre-push gate run.
|
Commit and push directly to `main` for routine work — this is a solo-dev repo and does not use a branch-first / feature-branch flow. Do **not** create a working branch just to land a change. (This overrides the generic "branch before committing on the default branch" assistant default.) The usual safety rules still hold: never `--no-verify`, never force-push `main`, and let the pre-push gate run.
|
||||||
|
|
||||||
|
**Never `git add -A` or `git add .` — stage explicit paths every time (`git add <file> …`), no exceptions.** This worktree can host concurrent Claude sessions: a blanket add vacuums another session's in-progress files — and your own unrelated edits — into your commit, mislabeling work and entangling history (this has happened). If `git status` shows files you didn't touch this turn, they are not yours to stage. **Always create commits through the [`git-commit` skill](.claude/skills/git-commit/SKILL.md)** — it encodes the message format (Conventional Commits, per [D-37](governance/decisions/process.md#d-37)), the explicit-staging rule, changelog discipline, and the safety reminders. Don't hand-roll a commit that skips it.
|
||||||
|
|
||||||
The pre-commit hook auto-exports and stages `.pql/changelog/` (the pql ticket DB) on every commit — don't hand-stage it. A ticket change only persists if the turn makes at least one commit; with no commit the hook never fires and a later branch switch can drop it.
|
The pre-commit hook auto-exports and stages `.pql/changelog/` (the pql ticket DB) on every commit — don't hand-stage it. A ticket change only persists if the turn makes at least one commit; with no commit the hook never fires and a later branch switch can drop it.
|
||||||
|
|
||||||
## Changelog discipline
|
## Changelog discipline
|
||||||
|
|||||||
+8
-4
@@ -181,14 +181,18 @@ tickets before the diff lands. Trivial typo fixes don't need one.
|
|||||||
See [D-37](governance/decisions/process.md#d-37) and the bundled
|
See [D-37](governance/decisions/process.md#d-37) and the bundled
|
||||||
[`git-commit` skill](.claude/skills/git-commit/SKILL.md). In short:
|
[`git-commit` skill](.claude/skills/git-commit/SKILL.md). In short:
|
||||||
|
|
||||||
- Imperative subject ≤ 70 chars, no Conventional Commits prefix
|
- [Conventional Commits 1.0](https://www.conventionalcommits.org/en/v1.0.0/):
|
||||||
(this isn't a Conventional Commits repo — the archived Python
|
`type(scope): imperative subject`, ≤ 72 chars including the prefix.
|
||||||
predecessor under [`legacy/`](legacy/) is, but the rebuild isn't).
|
Types are `feat`, `fix`, `docs`, `style`, `refactor`, `perf`,
|
||||||
|
`test`, `build`, `chore`; scope is the subsystem (`settings`,
|
||||||
|
`vim`, `pty`…); keep a trailing `(T-NNN)` ticket ref where one
|
||||||
|
applies — e.g. `feat(settings): category rail + navigation (T-447)`.
|
||||||
- One logical change per commit. If the subject needs "and", split it.
|
- One logical change per commit. If the subject needs "and", split it.
|
||||||
- Every user-visible commit adds an entry to `CHANGELOG.md` under
|
- Every user-visible commit adds an entry to `CHANGELOG.md` under
|
||||||
`[Unreleased]` in the right subsection (Added, Changed, Deprecated,
|
`[Unreleased]` in the right subsection (Added, Changed, Deprecated,
|
||||||
Removed, Fixed, Security). Keep entries to one or two short
|
Removed, Fixed, Security). Keep entries to one or two short
|
||||||
sentences — the 60-word cap is enforced by `ci/changelog_gate.sh`.
|
sentences — the 60-word cap is enforced by the pre-push gate
|
||||||
|
(`make changelog-gate`).
|
||||||
- Co-author trailer:
|
- Co-author trailer:
|
||||||
`Co-Authored-By: Claude <noreply@anthropic.com>` when Claude wrote
|
`Co-Authored-By: Claude <noreply@anthropic.com>` when Claude wrote
|
||||||
any of the diff.
|
any of the diff.
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ changelog-gate: ## Changelog concision gate — fails on `## [Unreleased]` bulle
|
|||||||
ci/changelog_gate.sh
|
ci/changelog_gate.sh
|
||||||
|
|
||||||
.PHONY: smoke-bundle
|
.PHONY: smoke-bundle
|
||||||
smoke-bundle: ## Build Linux release bundle and run it under xvfb for 5s.
|
smoke-bundle: gen-build-info ## Build Linux release bundle and run it under xvfb for 5s.
|
||||||
ci/smoke_bundle.sh
|
ci/smoke_bundle.sh
|
||||||
|
|
||||||
# -- web UI harness ------------------------------------------------------
|
# -- web UI harness ------------------------------------------------------
|
||||||
@@ -169,8 +169,7 @@ ui-smoke: ## Build + serve + run Playwright smoke + stop.
|
|||||||
@sh -c 'trap "tools/ui/stop.sh >/dev/null 2>&1" EXIT; cd tools/ui && npx playwright test smoke.spec.ts'
|
@sh -c 'trap "tools/ui/stop.sh >/dev/null 2>&1" EXIT; cd tools/ui && npx playwright test smoke.spec.ts'
|
||||||
|
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
build: gen-build-info clide-cli ## flutter build for the current OS (incl. the C CLI client).
|
build: clide-cli build-$(FLUTTER_OS) ## flutter build for the current OS (via build-<os>) + bundle the C CLI client.
|
||||||
flutter build $(FLUTTER_OS)
|
|
||||||
@install -m 755 $(CLIDE_CLI_BIN) $(CLI_BUNDLE_DEST)
|
@install -m 755 $(CLIDE_CLI_BIN) $(CLI_BUNDLE_DEST)
|
||||||
@echo "==> bundled C client at $(CLI_BUNDLE_DEST)"
|
@echo "==> bundled C client at $(CLI_BUNDLE_DEST)"
|
||||||
|
|
||||||
@@ -182,6 +181,14 @@ build-linux: gen-build-info ## flutter build linux (desktop bundle).
|
|||||||
build-macos: gen-build-info ## flutter build macos (desktop bundle).
|
build-macos: gen-build-info ## flutter build macos (desktop bundle).
|
||||||
flutter build macos
|
flutter build macos
|
||||||
|
|
||||||
|
.PHONY: build-windows
|
||||||
|
build-windows: gen-build-info ## flutter build windows (desktop bundle).
|
||||||
|
flutter build windows
|
||||||
|
|
||||||
|
.PHONY: release
|
||||||
|
release: ## Finalize a release: verify version/changelog/tree, run the gate, tag vX.Y.Z. Run after the `release vX.Y.Z` commit.
|
||||||
|
ci/release.sh
|
||||||
|
|
||||||
# -- install / uninstall -----------------------------------------------------
|
# -- install / uninstall -----------------------------------------------------
|
||||||
|
|
||||||
# Install prefix. Bundle lands at $(INSTALL_PREFIX)/clide/ with a
|
# Install prefix. Bundle lands at $(INSTALL_PREFIX)/clide/ with a
|
||||||
@@ -196,6 +203,9 @@ ifeq ($(FLUTTER_OS),linux)
|
|||||||
else ifeq ($(FLUTTER_OS),macos)
|
else ifeq ($(FLUTTER_OS),macos)
|
||||||
BUNDLE_DIR := build/macos/Build/Products/Release/clide.app
|
BUNDLE_DIR := build/macos/Build/Products/Release/clide.app
|
||||||
CLI_BUNDLE_DEST := $(BUNDLE_DIR)/Contents/MacOS/clide-cli
|
CLI_BUNDLE_DEST := $(BUNDLE_DIR)/Contents/MacOS/clide-cli
|
||||||
|
else ifeq ($(FLUTTER_OS),windows)
|
||||||
|
BUNDLE_DIR := build/windows/x64/runner/Release
|
||||||
|
CLI_BUNDLE_DEST := $(BUNDLE_DIR)/clide-cli.exe
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ICON_SIZES := 16 32 48 128 192 256 512
|
ICON_SIZES := 16 32 48 128 192 256 512
|
||||||
@@ -254,6 +264,8 @@ else ifeq ($(FLUTTER_OS),macos)
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
# -- dugite-native (bundled git) ------------------------------------------
|
# -- dugite-native (bundled git) ------------------------------------------
|
||||||
|
# Security tracking (D-59): run `make dugite-check` quarterly, or on a git CVE,
|
||||||
|
# to compare this pin against the latest upstream release. T-88 is the calendar.
|
||||||
|
|
||||||
DUGITE_VERSION := v2.53.0-3
|
DUGITE_VERSION := v2.53.0-3
|
||||||
DUGITE_COMMIT := f49d009
|
DUGITE_COMMIT := f49d009
|
||||||
@@ -291,7 +303,11 @@ dugite-clean: ## Remove the dugite-native directory.
|
|||||||
# target picks up whatever `cc` is on PATH.
|
# target picks up whatever `cc` is on PATH.
|
||||||
|
|
||||||
CLIDE_CLI_SRC := native/clide-cli/clide.c
|
CLIDE_CLI_SRC := native/clide-cli/clide.c
|
||||||
CLIDE_CLI_BIN := native/$(if $(filter Darwin,$(shell uname -s)),macos,linux)-$(shell uname -m | sed 's/x86_64/x64/;s/aarch64/arm64/')/clide
|
ifeq ($(FLUTTER_OS),windows)
|
||||||
|
CLIDE_CLI_BIN := native/windows-x64/clide.exe
|
||||||
|
else
|
||||||
|
CLIDE_CLI_BIN := native/$(if $(filter Darwin,$(shell uname -s)),macos,linux)-$(shell uname -m | sed 's/x86_64/x64/;s/aarch64/arm64/')/clide
|
||||||
|
endif
|
||||||
CC ?= cc
|
CC ?= cc
|
||||||
|
|
||||||
.PHONY: clide-cli
|
.PHONY: clide-cli
|
||||||
@@ -299,7 +315,11 @@ clide-cli: $(CLIDE_CLI_BIN) ## Compile the C `clide` shell client.
|
|||||||
|
|
||||||
$(CLIDE_CLI_BIN): $(CLIDE_CLI_SRC)
|
$(CLIDE_CLI_BIN): $(CLIDE_CLI_SRC)
|
||||||
@mkdir -p $(dir $(CLIDE_CLI_BIN))
|
@mkdir -p $(dir $(CLIDE_CLI_BIN))
|
||||||
|
ifeq ($(FLUTTER_OS),windows)
|
||||||
|
ci/build_cli_windows.sh
|
||||||
|
else
|
||||||
$(CC) -std=c99 -O2 -Wall -Wextra -o $(CLIDE_CLI_BIN) $(CLIDE_CLI_SRC)
|
$(CC) -std=c99 -O2 -Wall -Wextra -o $(CLIDE_CLI_BIN) $(CLIDE_CLI_SRC)
|
||||||
|
endif
|
||||||
@echo "==> built $(CLIDE_CLI_BIN)"
|
@echo "==> built $(CLIDE_CLI_BIN)"
|
||||||
|
|
||||||
.PHONY: clide-cli-clean
|
.PHONY: clide-cli-clean
|
||||||
@@ -309,8 +329,12 @@ clide-cli-clean: ## Remove the compiled C `clide` client.
|
|||||||
# -- security -------------------------------------------------------------
|
# -- security -------------------------------------------------------------
|
||||||
|
|
||||||
.PHONY: security
|
.PHONY: security
|
||||||
security: ## Dart advisory review.
|
security: ## Supply-chain gate — osv-scanner over pubspec.lock (CI PR-merge pipeline; run locally on demand). Fails on a known advisory.
|
||||||
@echo "security: Dart advisories reviewed manually before pubspec.yaml bumps."
|
ci/osv_scan.sh
|
||||||
|
|
||||||
|
.PHONY: dugite-check
|
||||||
|
dugite-check: ## Track dugite-native (bundled git) upstream releases for security drift (T-88 / D-59). Run quarterly, or on a git CVE. Informational, not a gate.
|
||||||
|
ci/check_dugite_version.sh
|
||||||
|
|
||||||
# -- pre-push gate --------------------------------------------------------
|
# -- pre-push gate --------------------------------------------------------
|
||||||
|
|
||||||
@@ -319,6 +343,10 @@ decisions-validate: ## Parser dry-run over governance/{decisions,questions,rejec
|
|||||||
pql decisions validate
|
pql decisions validate
|
||||||
|
|
||||||
.PHONY: push-check
|
.PHONY: push-check
|
||||||
|
# NOTE: the `security` (osv-scanner) gate is deliberately NOT in push-check —
|
||||||
|
# it runs in the CI PR-merge pipeline (where the scanner is provisioned) so we
|
||||||
|
# don't force every dev machine to install osv-scanner. Run it locally any time
|
||||||
|
# with `make security`.
|
||||||
push-check: decisions-validate changelog-gate test-coverage coverage-gate test-core ## Pre-push gate (fast — <2 min target). Order is fail-fast: instant gates (decisions, changelog) first, then the coverage suite + gate (the expensive, most-likely-to-fail stage) BEFORE test-core — a coverage miss aborts here instead of after running everything, so a fix doesn't force a full re-run of the rest. test-coverage already runs the a11y suite (test/a11y), so no separate test-a11y pass.
|
push-check: decisions-validate changelog-gate test-coverage coverage-gate test-core ## Pre-push gate (fast — <2 min target). Order is fail-fast: instant gates (decisions, changelog) first, then the coverage suite + gate (the expensive, most-likely-to-fail stage) BEFORE test-core — a coverage miss aborts here instead of after running everything, so a fix doesn't force a full re-run of the rest. test-coverage already runs the a11y suite (test/a11y), so no separate test-a11y pass.
|
||||||
|
|
||||||
.PHONY: push-check-full
|
.PHONY: push-check-full
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
This document governs what clide is allowed to do at runtime, what it's allowed to depend on, and how contributors — human and agent — introduce code into the project. It is binding on all contributors. When in doubt, stop and ask.
|
This document governs what clide is allowed to do at runtime, what it's allowed to depend on, and how contributors — human and agent — introduce code into the project. It is binding on all contributors. When in doubt, stop and ask.
|
||||||
|
|
||||||
Rationale for specific architectural choices referenced here and in code comments (the D-### markers) lives in `decisions/`. This document sets the rules; `decisions/` records why the rules produced the code they did in a given case. If the two ever disagree, the rule in this document wins until the document itself is changed.
|
Rationale for specific architectural choices referenced here and in code comments (the D-### markers) lives in `governance/decisions/`. This document sets the rules; `governance/decisions/` records why the rules produced the code they did in a given case. If the two ever disagree, the rule in this document wins until the document itself is changed.
|
||||||
|
|
||||||
## Why this document exists
|
## Why this document exists
|
||||||
|
|
||||||
@@ -124,9 +124,9 @@ When removing a dependency:
|
|||||||
|
|
||||||
1. **Grep the entire repository** for references to the package, its exports, and any type names it contributed. `rg '<package>|<PackageType>|<prefix_>'` across the repo. Zero hits outside git history is the goal. A single lingering import will break the build; a single lingering FFI stub or type alias will compile fine and fail at runtime.
|
1. **Grep the entire repository** for references to the package, its exports, and any type names it contributed. `rg '<package>|<PackageType>|<prefix_>'` across the repo. Zero hits outside git history is the goal. A single lingering import will break the build; a single lingering FFI stub or type alias will compile fine and fail at runtime.
|
||||||
2. **Regenerate the lockfile** as part of the same PR. A `pubspec.yaml` with the dep removed but a `pubspec.lock` that still pins it is a partial removal, and CI or a fresh clone will happily continue installing the package.
|
2. **Regenerate the lockfile** as part of the same PR. A `pubspec.yaml` with the dep removed but a `pubspec.lock` that still pins it is a partial removal, and CI or a fresh clone will happily continue installing the package.
|
||||||
3. **Update `app/assets/licenses.yaml`** to drop the removed package and any transitive deps it brought in that aren't pulled by anything else. If the license manifest is auto-generated on release, verify the generation script sees the change; if it's maintained by hand, edit it in the same PR.
|
3. **Update `assets/licenses.yaml`** to drop the removed package and any transitive deps it brought in that aren't pulled by anything else. If the license manifest is auto-generated on release, verify the generation script sees the change; if it's maintained by hand, edit it in the same PR.
|
||||||
4. **Remove any vendored artifacts** tied to the dep — binaries, prebuilt assets, generated bindings — and delete their `BUILD.md` records. An orphaned vendored binary is worse than a removed one because it looks legitimate.
|
4. **Remove any vendored artifacts** tied to the dep — binaries, prebuilt assets, generated bindings — and delete their `BUILD.md` records. An orphaned vendored binary is worse than a removed one because it looks legitimate.
|
||||||
5. **Check for architectural assumptions** that the dep was carrying. If the removed package was the thing that justified a specific data flow, build step, or platform strategy, either the replacement picks up those responsibilities or the architecture has actually changed and the relevant design decision (see `decisions/`) needs updating.
|
5. **Check for architectural assumptions** that the dep was carrying. If the removed package was the thing that justified a specific data flow, build step, or platform strategy, either the replacement picks up those responsibilities or the architecture has actually changed and the relevant design decision (see `governance/decisions/`) needs updating.
|
||||||
|
|
||||||
A dependency is not removed until all five are true. "I deleted the line from pubspec.yaml" is the start of the removal, not the end.
|
A dependency is not removed until all five are true. "I deleted the line from pubspec.yaml" is the start of the removal, not the end.
|
||||||
|
|
||||||
@@ -188,18 +188,18 @@ When in doubt about a license, the dependency does not land until the question i
|
|||||||
|
|
||||||
### Attribution requirements
|
### Attribution requirements
|
||||||
|
|
||||||
- The license manifest at `app/assets/licenses.yaml` lists every dependency with its license, copyright notice, and upstream URL.
|
- The license manifest at `assets/licenses.yaml` lists every dependency with its license, copyright notice, and upstream URL.
|
||||||
- Transitive dependencies are listed, not just direct ones. If `wasm_run` pulls in `wasmtime` which pulls in `cranelift`, all three appear.
|
- Transitive dependencies are listed, not just direct ones. If `wasm_run` pulls in `wasmtime` which pulls in `cranelift`, all three appear.
|
||||||
- Apache-2.0 dependencies get their `NOTICE` file content preserved verbatim, not summarized.
|
- Apache-2.0 dependencies get their `NOTICE` file content preserved verbatim, not summarized.
|
||||||
- Apache-2.0-with-LLVM-exception (e.g., Cranelift, parts of LLVM) requires the LLVM exception text specifically, not just the Apache-2.0 boilerplate.
|
- Apache-2.0-with-LLVM-exception (e.g., Cranelift, parts of LLVM) requires the LLVM exception text specifically, not just the Apache-2.0 boilerplate.
|
||||||
- Fonts and icon sets get attributed even if the license doesn't strictly require it. It's the right thing to do.
|
- Fonts and icon sets get attributed even if the license doesn't strictly require it. It's the right thing to do.
|
||||||
- `app/assets/licenses.yaml` is regenerated as part of the release build, not maintained by hand. A release that ships a stale manifest is a release defect.
|
- `assets/licenses.yaml` is regenerated as part of the release build, not maintained by hand. A release that ships a stale manifest is a release defect.
|
||||||
|
|
||||||
Adding a dependency means updating the license manifest in the same PR. No exceptions.
|
Adding a dependency means updating the license manifest in the same PR. No exceptions.
|
||||||
|
|
||||||
## Changelog and commit conventions
|
## Changelog and commit conventions
|
||||||
|
|
||||||
clide follows [Keep a Changelog 1.1](https://keepachangelog.com/en/1.1.0/) for `CHANGELOG.md` and [Conventional Commits 1.0](https://www.conventionalcommits.org/en/v1.0.0/) for commit messages. Enforcement is handled by the project's git skill; this section exists so human contributors know the standard before their first PR, and so the connection between these conventions and the rest of the policy is explicit.
|
clide follows [Keep a Changelog 1.1](https://keepachangelog.com/en/1.1.0/) for `CHANGELOG.md` and [Conventional Commits 1.0](https://www.conventionalcommits.org/en/v1.0.0/) for commit messages (see [D-37](governance/decisions/process.md#d-37)). Enforcement is handled by the project's git skill; this section exists so human contributors know the standard before their first PR, and so the connection between these conventions and the rest of the policy is explicit.
|
||||||
|
|
||||||
Security-relevant changes — CVE responses, dependency-driven vulnerability fixes, the removal of a phoning-home transitive dep, anything where the rules in this document were the reason for the change — go under the `Security` heading of the release's changelog entry, regardless of whether the code change itself looks security-shaped. That heading is the trail future-us follows to reconstruct why a dep was bumped or removed. Lumping security fixes under `Fixed` because the diff looks like a normal bug fix loses that signal and is the wrong choice even when it's technically accurate.
|
Security-relevant changes — CVE responses, dependency-driven vulnerability fixes, the removal of a phoning-home transitive dep, anything where the rules in this document were the reason for the change — go under the `Security` heading of the release's changelog entry, regardless of whether the code change itself looks security-shaped. That heading is the trail future-us follows to reconstruct why a dep was bumped or removed. Lumping security fixes under `Fixed` because the diff looks like a normal bug fix loses that signal and is the wrong choice even when it's technically accurate.
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
# clide
|
# clide
|
||||||
|
|
||||||
An IDE for Claude Code CLI. Native rendering, terminal-first interaction, pql-powered queries, canvas and graph surfaces. Linux and macOS.
|
An IDE for Claude Code CLI. Native rendering, terminal-first interaction, pql-powered queries, canvas and graph surfaces. Linux, macOS and Windows.
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
Single Flutter package at the repo root. The app hosts everything in-process: IPC server, subsystem handlers (pane, files, editor, git, pql), and the extension framework. tmux owns Claude session persistence (D-41).
|
Single Flutter package at the repo root. The app hosts everything in-process: IPC server, subsystem handlers (pane, files, editor, git, pql), and the extension framework. Claude session persistence is `--resume <session-id>` against Claude Code's transcript files (D-77, superseding the tmux-backed D-41).
|
||||||
|
|
||||||
- **`lib/`** — all Dart code. Core subsystems (`lib/src/`), kernel services (`lib/kernel/`), UI widgets (`lib/widgets/`), built-in extensions (`lib/builtin/`), the extension framework (`lib/extension/`).
|
- **`lib/`** — all Dart code. Core subsystems (`lib/src/`), kernel services (`lib/kernel/`), UI widgets (`lib/widgets/`), built-in extensions (`lib/builtin/`), the extension framework (`lib/extension/`).
|
||||||
- **PTY** — `lib/src/pty/` spawns child processes via Dart FFI `posix_openpt()` + `posix_spawn()` directly; no external helper binary.
|
- **PTY** — `lib/src/pty/` spawns child processes via Dart FFI `posix_openpt()` + `posix_spawn()` directly; no external helper binary.
|
||||||
@@ -15,7 +15,7 @@ Claude drives the UI through a `clide` CLI surface (Bash, not MCP). Every CLI su
|
|||||||
|
|
||||||
## Built-in extensions
|
## Built-in extensions
|
||||||
|
|
||||||
canvas, claude, claude_control, decisions, diff, editor, extensions_ui, files, git, graph, grammars_core, ipc_status, keybindings_ui, markdown, pql, problems, settings_ui, terminal, theme_picker, tickets, todos, welcome.
|
canvas, claude, claude_control, cli_install, decisions, deeplink, default_layout, diff, editor, extensions_ui, files, git, grammars_core, graph, ipc_status, keybindings_ui, markdown, menubar, output, pql, problems, search, settings_ui, terminal, theme_picker, tickets, todos, view, vim, welcome.
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ make push-check # pre-push gate: decisions + core + fast + a11y + coverage
|
|||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
Pre-v2.0 (`2.0.0-dev`). Interaction model and panel system landed. The Python Textual v1.2.0 predecessor is archived under [`legacy/`](https://github.com/postmeridiem/clide/tree/main/legacy).
|
Active development; the interaction model, panel system, and settings engine have landed. The Python Textual predecessor is archived under [`legacy/`](https://github.com/postmeridiem/clide/tree/main/legacy).
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,93 @@
|
|||||||
|
Copyright (c) 2012-2013, The Mozilla Corporation and Telefonica S.A.
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
https://openfontlicense.org
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,93 @@
|
|||||||
|
Copyright 2020 The Inter Project Authors (https://github.com/rsms/inter)
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
https://openfontlicense.org
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"tab.title": { "translation": "Canvas" },
|
||||||
|
"empty": { "translation": "Open a .canvas file to view it here." },
|
||||||
|
"status.loading": { "translation": "Loading…" }
|
||||||
|
}
|
||||||
@@ -0,0 +1,251 @@
|
|||||||
|
{
|
||||||
|
"tab.title": { "translation": "Claude" },
|
||||||
|
"status.attaching": { "translation": "attaching…" },
|
||||||
|
"status.no-tmux": { "translation": "no-tmux · fresh every launch" },
|
||||||
|
"status.exited": { "translation": "session exited" },
|
||||||
|
"status.primary-exited": { "translation": "session exited — restart clide to retry" },
|
||||||
|
"banner.title": { "translation": "Claude" },
|
||||||
|
"banner.warmingUp": { "translation": "Warming up — your conversation will appear here." },
|
||||||
|
"banner.role.primary": { "translation": "primary" },
|
||||||
|
"banner.role.secondary": { "translation": "session {index}" },
|
||||||
|
"composer.hint": { "translation": "Message Claude… (Enter to send · Shift+Enter for newline)" },
|
||||||
|
"composer.stop": { "translation": "Stop ⎋" },
|
||||||
|
"composer.stop.hint": { "translation": "Interrupt the running turn (Escape)" },
|
||||||
|
"composer.removeAttachment": { "translation": "Remove {name}" },
|
||||||
|
"pane.title.primary": { "translation": "claude — primary" },
|
||||||
|
"pane.title.secondary": { "translation": "claude — secondary {index}" },
|
||||||
|
"pane.starting": { "translation": "starting…" },
|
||||||
|
"pane.modeBadge.semantics": { "translation": "permission mode: {mode}" },
|
||||||
|
"running.semantics": { "translation": "Claude is running" },
|
||||||
|
"running.verb.pondering": { "translation": "Pondering" },
|
||||||
|
"running.verb.conjuring": { "translation": "Conjuring" },
|
||||||
|
"running.verb.brewing": { "translation": "Brewing" },
|
||||||
|
"running.verb.tinkering": { "translation": "Tinkering" },
|
||||||
|
"running.verb.noodling": { "translation": "Noodling" },
|
||||||
|
"running.verb.percolating": { "translation": "Percolating" },
|
||||||
|
"running.verb.computing": { "translation": "Computing" },
|
||||||
|
"running.verb.wrangling": { "translation": "Wrangling" },
|
||||||
|
"running.verb.untangling": { "translation": "Untangling" },
|
||||||
|
"running.verb.synthesizing": { "translation": "Synthesizing" },
|
||||||
|
"running.verb.cogitating": { "translation": "Cogitating" },
|
||||||
|
"running.verb.whirring": { "translation": "Whirring" },
|
||||||
|
"running.verb.mincing": { "translation": "Mincing" },
|
||||||
|
"running.verb.boiling": { "translation": "Boiling" },
|
||||||
|
"running.verb.humming": { "translation": "Humming" },
|
||||||
|
"running.verb.buzzing": { "translation": "Buzzing" },
|
||||||
|
"running.verb.magicking": { "translation": "Magicking" },
|
||||||
|
"running.verb.cliding": { "translation": "Cliding" },
|
||||||
|
"running.verb.zooming": { "translation": "Zooming" },
|
||||||
|
"running.verb.bouncing": { "translation": "Bouncing" },
|
||||||
|
"conversation.empty": { "translation": "Waiting for Claude…" },
|
||||||
|
"conversation.label.you": { "translation": "you" },
|
||||||
|
"conversation.label.claude": { "translation": "claude" },
|
||||||
|
"conversation.label.clide": { "translation": "clide" },
|
||||||
|
"conversation.label.agent": { "translation": "agent" },
|
||||||
|
"conversation.label.agentPrompt": { "translation": "agent prompt" },
|
||||||
|
"conversation.label.context": { "translation": "context" },
|
||||||
|
"conversation.label.thinking": { "translation": "thinking" },
|
||||||
|
"conversation.label.agentThinking": { "translation": "agent thinking" },
|
||||||
|
"conversation.label.image": { "translation": "image" },
|
||||||
|
"conversation.label.icon": { "translation": "icons" },
|
||||||
|
"conversation.label.drawing": { "translation": "drawing" },
|
||||||
|
"conversation.draw.viewSource": { "translation": "view d2 source" },
|
||||||
|
"conversation.label.agentRun": { "translation": "agent run" },
|
||||||
|
"conversation.label.workflow": { "translation": "workflow" },
|
||||||
|
"conversation.label.error": { "translation": "error" },
|
||||||
|
"conversation.label.result": { "translation": "result" },
|
||||||
|
"conversation.label.denied": { "translation": "denied" },
|
||||||
|
"conversation.segment.prompt": { "translation": "prompt" },
|
||||||
|
"conversation.segment.result": { "translation": "result" },
|
||||||
|
"conversation.segment.liveTail": { "translation": "live tail" },
|
||||||
|
"conversation.segment.usage": { "translation": "usage" },
|
||||||
|
"conversation.segment.script": { "translation": "script" },
|
||||||
|
"conversation.workflow.launching": { "translation": "Launching…" },
|
||||||
|
"conversation.imagePlaceholder": { "translation": "could not load {path}" },
|
||||||
|
"conversation.bashTail.empty": { "translation": "no independent source to follow" },
|
||||||
|
"conversation.bashTail.label": { "translation": "live tail" },
|
||||||
|
"conversation.cluster.activity": { "translation": "Activity" },
|
||||||
|
"conversation.cluster.edits": { "translation": "Edits" },
|
||||||
|
"conversation.counter.step": { "translation": "1 step" },
|
||||||
|
"conversation.counter.steps": { "translation": "{count} steps" },
|
||||||
|
"conversation.counter.edit": { "translation": "1 edit" },
|
||||||
|
"conversation.counter.edits": { "translation": "{count} edits" },
|
||||||
|
"conversation.counter.starting": { "translation": "starting" },
|
||||||
|
"conversation.counter.agents": { "translation": "{done}/{total} agents" },
|
||||||
|
"prompt.permission.allow": { "translation": "1. Allow" },
|
||||||
|
"prompt.permission.allowRemember": { "translation": "2. Allow & don't ask again" },
|
||||||
|
"prompt.permission.deny": { "translation": "{n}. Deny" },
|
||||||
|
"prompt.permission.denySimplify": { "translation": "{n}. Deny & simplify" },
|
||||||
|
"prompt.permission.denySimplify.tooltip": { "translation": "Deny and ask Claude to retry this action in a simpler format — complex interactions don't work well with the permission system." },
|
||||||
|
"prompt.permission.note.placeholder": { "translation": "add a note (optional) — sent to Claude" },
|
||||||
|
"prompt.permission.label": { "translation": "permission · {name}" },
|
||||||
|
"prompt.question.label": { "translation": "question" },
|
||||||
|
"prompt.review.label": { "translation": "review" },
|
||||||
|
"prompt.review.title": { "translation": "Review your answers" },
|
||||||
|
"prompt.submit": { "translation": "Submit" },
|
||||||
|
"prompt.submitAnswers": { "translation": "Submit answers" },
|
||||||
|
"prompt.back": { "translation": "‹ Back" },
|
||||||
|
"prompt.next": { "translation": "Next ›" },
|
||||||
|
"prompt.reviewNav": { "translation": "Review ›" },
|
||||||
|
"prompt.nav.review": { "translation": "Review" },
|
||||||
|
"prompt.option.other": { "translation": "Other…" },
|
||||||
|
"prompt.other.placeholder": { "translation": "type your answer…" },
|
||||||
|
"prompt.note.placeholder": { "translation": "+ note (optional)" },
|
||||||
|
"prompt.chatInstead": { "translation": "chat instead" },
|
||||||
|
"tool.edit.before": { "translation": "— before" },
|
||||||
|
"tool.edit.after": { "translation": "+ after" },
|
||||||
|
"tool.bash.background": { "translation": "background" },
|
||||||
|
"tool.name.Read": { "translation": "Read" },
|
||||||
|
"tool.name.Edit": { "translation": "Edit" },
|
||||||
|
"tool.name.MultiEdit": { "translation": "MultiEdit" },
|
||||||
|
"tool.name.Write": { "translation": "Write" },
|
||||||
|
"tool.name.NotebookEdit": { "translation": "NotebookEdit" },
|
||||||
|
"tool.name.WebFetch": { "translation": "WebFetch" },
|
||||||
|
"tool.name.WebSearch": { "translation": "WebSearch" },
|
||||||
|
"tool.name.Task": { "translation": "Task" },
|
||||||
|
"tool.name.TodoWrite": { "translation": "TodoWrite" },
|
||||||
|
"tool.name.ExitPlanMode": { "translation": "ExitPlanMode" },
|
||||||
|
"permissionControl.semantics": { "translation": "permission mode: {mode}. Activate to change." },
|
||||||
|
"permissionControl.tooltip": { "translation": "Permission mode: {mode} — change (Ctrl/Cmd+M cycles; +Shift includes bypass)" },
|
||||||
|
"permissionControl.bypassHint": { "translation": "shift-click" },
|
||||||
|
"permissionControl.bypassSemantics": { "translation": "bypassPermissions — shift-click to enable" },
|
||||||
|
"permissionBadge.tooltip": { "translation": "Permission mode: {mode}. Click to cycle default/acceptEdits/plan; Shift-click for bypassPermissions." },
|
||||||
|
"permissionBadge.semantics": { "translation": "Permission mode: {label}" },
|
||||||
|
"card.expand": { "translation": "Expand" },
|
||||||
|
"card.collapse": { "translation": "Collapse" },
|
||||||
|
"card.succeeded": { "translation": "succeeded" },
|
||||||
|
"card.failed": { "translation": "failed" },
|
||||||
|
"card.copy": { "translation": "copy" },
|
||||||
|
"taskDock.summary": { "translation": "{count} {tasks} · {done} done" },
|
||||||
|
"taskDock.task.singular": { "translation": "task" },
|
||||||
|
"taskDock.task.plural": { "translation": "tasks" },
|
||||||
|
"taskDock.collapse": { "translation": "Collapse tasks" },
|
||||||
|
"taskDock.expand": { "translation": "Expand tasks" },
|
||||||
|
"taskDock.semantics": { "translation": "Claude task list, {summary}, {state}" },
|
||||||
|
"taskDock.state.expanded": { "translation": "expanded" },
|
||||||
|
"taskDock.state.collapsed": { "translation": "collapsed" },
|
||||||
|
"taskDock.status.done": { "translation": "done" },
|
||||||
|
"taskDock.status.inProgress": { "translation": "in progress" },
|
||||||
|
"taskDock.status.pending": { "translation": "pending" },
|
||||||
|
"taskDock.row.semantics": { "translation": "{text}, {status}" },
|
||||||
|
"sessionPicker.title": { "translation": "Resume a Claude session" },
|
||||||
|
"sessionPicker.empty": { "translation": "No sessions found for this workspace." },
|
||||||
|
"modelPicker.cancel": { "translation": "cancel" },
|
||||||
|
"image.semantics": { "translation": "Image {name}" },
|
||||||
|
"activity.section.session": { "translation": "SESSION" },
|
||||||
|
"activity.control.clear": { "translation": "clear" },
|
||||||
|
"activity.control.compact": { "translation": "compact" },
|
||||||
|
"activity.control.fork": { "translation": "fork" },
|
||||||
|
"activity.control.resume": { "translation": "resume" },
|
||||||
|
"activity.control.refreshUsage": { "translation": "refresh usage" },
|
||||||
|
"activity.control.semantics": { "translation": "{label} session" },
|
||||||
|
"activity.control.tooltip": { "translation": "{label} · {command}" },
|
||||||
|
"activity.empty": { "translation": "No activity recorded yet." },
|
||||||
|
"activity.section.workflows": { "translation": "WORKFLOWS" },
|
||||||
|
"activity.workflow.fallback": { "translation": "workflow" },
|
||||||
|
"activity.workflow.done": { "translation": "done" },
|
||||||
|
"activity.workflow.starting": { "translation": "starting" },
|
||||||
|
"activity.section.usage": { "translation": "USAGE" },
|
||||||
|
"activity.row.session": { "translation": "session" },
|
||||||
|
"activity.row.weekAll": { "translation": "week (all)" },
|
||||||
|
"activity.row.weekSonnet": { "translation": "week (sonnet)" },
|
||||||
|
"activity.section.today": { "translation": "TODAY" },
|
||||||
|
"activity.row.messages": { "translation": "messages" },
|
||||||
|
"activity.row.sessions": { "translation": "sessions" },
|
||||||
|
"activity.row.toolCalls": { "translation": "tool calls" },
|
||||||
|
"activity.section.lifetime": { "translation": "LIFETIME" },
|
||||||
|
"activity.section.runtime": { "translation": "RUNTIME · primary" },
|
||||||
|
"activity.row.model": { "translation": "model" },
|
||||||
|
"activity.row.effort": { "translation": "effort" },
|
||||||
|
"activity.row.context": { "translation": "context" },
|
||||||
|
"activity.row.mode": { "translation": "mode" },
|
||||||
|
"activity.row.skills": { "translation": "skills" },
|
||||||
|
"config.empty": { "translation": "Claude environment not loaded." },
|
||||||
|
"config.section.settings": { "translation": "SETTINGS" },
|
||||||
|
"config.row.model": { "translation": "model" },
|
||||||
|
"config.row.effort": { "translation": "effort" },
|
||||||
|
"config.row.permissionMode": { "translation": "permission mode" },
|
||||||
|
"config.row.outputStyle": { "translation": "output style" },
|
||||||
|
"config.row.source": { "translation": "source" },
|
||||||
|
"config.row.source.value": { "translation": "~/.claude + .claude" },
|
||||||
|
"config.footer": { "translation": "expand a list to see all · click a skill/agent/command → opens its .md" },
|
||||||
|
"config.section.skills": { "translation": "SKILLS" },
|
||||||
|
"config.section.agents": { "translation": "AGENTS" },
|
||||||
|
"config.section.commands": { "translation": "COMMANDS" },
|
||||||
|
"config.section.hooks": { "translation": "HOOKS" },
|
||||||
|
"config.section.permissions": { "translation": "PERMISSIONS" },
|
||||||
|
"config.section.mcpServers": { "translation": "MCP SERVERS" },
|
||||||
|
"config.perm.allow": { "translation": "allow" },
|
||||||
|
"config.perm.ask": { "translation": "ask" },
|
||||||
|
"config.perm.deny": { "translation": "deny" },
|
||||||
|
"config.control.semantics": { "translation": "{label}: {value}. Click to change." },
|
||||||
|
"config.control.tooltip": { "translation": "change {label}" },
|
||||||
|
"config.control.option.semantics": { "translation": "{label}: {name}" },
|
||||||
|
"roster.bypass.confirmBody": { "translation": "Enable bypassPermissions? All tool calls will be auto-allowed." },
|
||||||
|
"roster.bypass.confirm.semantics": { "translation": "Confirm bypass" },
|
||||||
|
"roster.bypass.confirm.tooltip": { "translation": "Confirm" },
|
||||||
|
"roster.bypass.ok": { "translation": "OK" },
|
||||||
|
"roster.bypass.cancel.semantics": { "translation": "Cancel bypass" },
|
||||||
|
"roster.bypass.cancel.tooltip": { "translation": "Cancel" },
|
||||||
|
"roster.bypass.cancel": { "translation": "Cancel" },
|
||||||
|
"roster.hidePane": { "translation": "Hide pane" },
|
||||||
|
"roster.showPane": { "translation": "Show pane" },
|
||||||
|
"roster.unmute": { "translation": "Unmute messages" },
|
||||||
|
"roster.mute": { "translation": "Mute messages" },
|
||||||
|
"roster.inject": { "translation": "Inject message" },
|
||||||
|
"roster.fork": { "translation": "Fork session" },
|
||||||
|
"roster.close": { "translation": "Close session" },
|
||||||
|
"roster.inject.cancel": { "translation": "Cancel" },
|
||||||
|
"taskRow.reassign": { "translation": "Reassign task" },
|
||||||
|
"team.empty": { "translation": "No team active." },
|
||||||
|
"team.section.tasks": { "translation": "TASKS" },
|
||||||
|
"tabStrip.activity": { "translation": "Activity" },
|
||||||
|
"tabStrip.team": { "translation": "Team" },
|
||||||
|
"tabStrip.team.count": { "translation": "Team · {count}" },
|
||||||
|
"tabStrip.config": { "translation": "Config" },
|
||||||
|
"teamChat.section.messages": { "translation": "MESSAGES" },
|
||||||
|
"teamChat.popOut.semantics": { "translation": "Open full chat pane" },
|
||||||
|
"teamChat.popOut.tooltip": { "translation": "Open full chat" },
|
||||||
|
"teamChat.empty": { "translation": "No messages yet." },
|
||||||
|
"teamChat.composer.placeholder": { "translation": "@name or @team …" },
|
||||||
|
"teamChat.pane.title": { "translation": "Team Chat" },
|
||||||
|
"teamChat.interrupt.semantics": { "translation": "Interrupt target session" },
|
||||||
|
"teamChat.interrupt.label": { "translation": "Interrupt" },
|
||||||
|
"command.newSecondary": { "translation": "Claude: open a secondary session" },
|
||||||
|
"command.killAllSessions": { "translation": "Claude: kill all sessions for this repo" },
|
||||||
|
"command.sessionStorage": { "translation": "Claude: session storage (disk usage + cleanup)" },
|
||||||
|
"command.activity.foldLevel": { "translation": "Claude: cycle activity fold level" },
|
||||||
|
"command.agent.show": { "translation": "Claude: show an agent session pane" },
|
||||||
|
"command.agent.hide": { "translation": "Claude: hide an agent session pane" },
|
||||||
|
"command.agent.close": { "translation": "Claude: close (kill) an agent session" },
|
||||||
|
"command.agent.mute": { "translation": "Claude: mute broker delivery to an agent session" },
|
||||||
|
"command.agent.unmute": { "translation": "Claude: unmute broker delivery to an agent session" },
|
||||||
|
"command.agent.injectMessage": { "translation": "Claude: inject a text turn into an agent session" },
|
||||||
|
"command.agent.setPermissionMode": { "translation": "Claude: set permission mode for an agent session" },
|
||||||
|
"command.mode.cycle": { "translation": "Claude: Cycle permission mode" },
|
||||||
|
"command.task.reassign": { "translation": "Claude: reassign a shared task to an agent" },
|
||||||
|
"command.teamChat.open": { "translation": "Claude: open the team chat pane" },
|
||||||
|
"command.teamChat.post": { "translation": "Claude: post a message into the team channel as the user" },
|
||||||
|
"command.agent.fork": { "translation": "Claude: fork a managed session into a new branch session" },
|
||||||
|
"settings.activity.title": { "translation": "Activity" },
|
||||||
|
"settings.activity.conversation.label": { "translation": "Conversation" },
|
||||||
|
"settings.activity.foldLevel.label": { "translation": "Fold level" },
|
||||||
|
"settings.activity.foldLevel.help": { "translation": "How aggressively the conversation folds tool calls, thinking, and results." },
|
||||||
|
"settings.activity.opt.none": { "translation": "Show everything" },
|
||||||
|
"settings.activity.opt.tools": { "translation": "Fold tool calls" },
|
||||||
|
"settings.activity.opt.thinking": { "translation": "Fold tools + thinking" },
|
||||||
|
"settings.activity.opt.everything": { "translation": "Fold all but prose" },
|
||||||
|
"settings.claude.title": { "translation": "Claude" },
|
||||||
|
"settings.claude.newSessionDefaults.label": { "translation": "New session defaults" },
|
||||||
|
"settings.claude.model.label": { "translation": "Model" },
|
||||||
|
"settings.claude.model.help": { "translation": "Model for new sessions." },
|
||||||
|
"settings.claude.effort.label": { "translation": "Effort" },
|
||||||
|
"settings.claude.effort.help": { "translation": "Reasoning effort for new sessions (applied via --effort at spawn)." },
|
||||||
|
"settings.claude.permissionMode.label": { "translation": "Permission mode" },
|
||||||
|
"settings.claude.permissionMode.help": { "translation": "Starting permission mode for new sessions." },
|
||||||
|
"settings.claude.account.label": { "translation": "Account" },
|
||||||
|
"settings.claude.account.registry.label": { "translation": "Accounts" },
|
||||||
|
"settings.claude.account.registry.help": { "translation": "Registered Claude accounts (each a separate config dir + login)." },
|
||||||
|
"settings.claude.account.workspace.label": { "translation": "Account for this workspace" },
|
||||||
|
"settings.claude.account.workspace.help": { "translation": "Which Claude account this repo runs under; Default uses the system login." }
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"command.clide.installCli": { "translation": "clide: Install 'clide' command in PATH" }
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"tab.title": { "translation": "Decisions" },
|
||||||
|
"tab.detail.title": { "translation": "Decision" },
|
||||||
|
"loading": { "translation": "Loading decisions..." },
|
||||||
|
"error.load": { "translation": "failed to load decisions" },
|
||||||
|
"empty": { "translation": "No decisions found.\nRun `pql decisions sync` to index." },
|
||||||
|
"filter.hint": { "translation": "Filter decisions…" },
|
||||||
|
"refresh.tooltip": { "translation": "Refresh decisions" },
|
||||||
|
"section.confirmed": { "translation": "CONFIRMED" },
|
||||||
|
"section.questions": { "translation": "QUESTIONS" },
|
||||||
|
"section.rejected": { "translation": "REJECTED" },
|
||||||
|
"badge.resolved": { "translation": "resolved" },
|
||||||
|
"detail.loading": { "translation": "Loading…" },
|
||||||
|
"detail.empty": { "translation": "Select a decision to view details." },
|
||||||
|
"detail.section.refs": { "translation": "CROSS-REFERENCES" }
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"dialog.title": { "translation": "Open an external link?" },
|
||||||
|
"dialog.body": { "translation": "A clide:// link from outside the app is asking to:" },
|
||||||
|
"dialog.warning": { "translation": "Only allow this if you trust where the link came from." },
|
||||||
|
"button.cancel": { "translation": "Cancel" },
|
||||||
|
"button.open": { "translation": "Open" },
|
||||||
|
"command.deeplink.invoke": { "translation": "Open a clide:// deep link" }
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"command.reset": { "translation": "Layout: Reset to Classic" },
|
||||||
|
"preset.classic": { "translation": "Classic" },
|
||||||
|
"command.palette.toggle": { "translation": "Command Palette" },
|
||||||
|
"command.sidebar.collapse": { "translation": "Toggle Sidebar Collapse" },
|
||||||
|
"command.context.collapse": { "translation": "Toggle Context Panel Collapse" },
|
||||||
|
"command.panel.focus.left": { "translation": "Focus Left Panel" },
|
||||||
|
"command.panel.focus.middle": { "translation": "Focus Middle Panel" },
|
||||||
|
"command.panel.focus.right": { "translation": "Focus Right Panel" },
|
||||||
|
"command.panel.focusMode": { "translation": "Toggle Focus Mode" },
|
||||||
|
"command.panel.focusMode.exit": { "translation": "Exit Focus Mode" },
|
||||||
|
"command.editor.open": { "translation": "Open Editor" },
|
||||||
|
"command.editor.close": { "translation": "Close Editor" },
|
||||||
|
"command.workspace.tab.next": { "translation": "Next Workspace Tab" },
|
||||||
|
"command.workspace.tab.previous": { "translation": "Previous Workspace Tab" },
|
||||||
|
"command.sidebar.section.1": { "translation": "Sidebar: Section 1" },
|
||||||
|
"command.sidebar.section.2": { "translation": "Sidebar: Section 2" },
|
||||||
|
"command.sidebar.section.3": { "translation": "Sidebar: Section 3" },
|
||||||
|
"command.sidebar.section.4": { "translation": "Sidebar: Section 4" },
|
||||||
|
"command.sidebar.section.5": { "translation": "Sidebar: Section 5" }
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"tab.title": { "translation": "Diff" },
|
||||||
|
"view.semantics": { "translation": "diff view" },
|
||||||
|
"status.loading": { "translation": "Loading…" },
|
||||||
|
"empty.staged": { "translation": "No staged changes." },
|
||||||
|
"empty.unstaged": { "translation": "No unstaged changes." },
|
||||||
|
"toolbar.unstaged": { "translation": "Unstaged" },
|
||||||
|
"toolbar.unstaged.semantics": { "translation": "show unstaged changes" },
|
||||||
|
"toolbar.staged": { "translation": "Staged" },
|
||||||
|
"toolbar.staged.semantics": { "translation": "show staged changes" },
|
||||||
|
"meta.newFile": { "translation": "new file" },
|
||||||
|
"meta.deleted": { "translation": "deleted" },
|
||||||
|
"meta.renamedFrom": { "translation": "renamed from {path}" },
|
||||||
|
"meta.binary": { "translation": "binary" }
|
||||||
|
}
|
||||||
+3
-1
@@ -1,5 +1,7 @@
|
|||||||
{
|
{
|
||||||
"tab.title": { "translation": "Editor" },
|
"tab.title": { "translation": "Editor" },
|
||||||
|
"chrome.title": { "translation": "editor" },
|
||||||
"empty": { "translation": "Open a file to begin editing." },
|
"empty": { "translation": "Open a file to begin editing." },
|
||||||
"subtitle.no-buffer": { "translation": "no buffer · use `clide open <path>` or pick a file in the tree" }
|
"subtitle.no-buffer": { "translation": "no buffer · use `clide open <path>` or pick a file in the tree" },
|
||||||
|
"a11y.text-area": { "translation": "editor text area" }
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"notice.title": { "translation": "Extension management is coming" },
|
||||||
|
"notice.body": { "translation": "Installing, enabling, and disabling extensions arrives with third-party (Lua) extension support. For now the built-in extensions are always on." },
|
||||||
|
"notice.tracked": { "translation": "Tracked in T-8 (Tier 6) · D-16" },
|
||||||
|
"settings.extensions.title": { "translation": "Extensions" },
|
||||||
|
"settings.extensions.section.notice": { "translation": "" },
|
||||||
|
"settings.extensions.field.notice.label": { "translation": "" }
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"tab.title": { "translation": "Files" },
|
||||||
|
"loading": { "translation": "Loading…" },
|
||||||
|
"empty": { "translation": "No visible files" },
|
||||||
|
"filter.hint": { "translation": "Filter files…" },
|
||||||
|
"a11y.tree": { "translation": "file tree — {name}" },
|
||||||
|
"a11y.collapse": { "translation": "Collapse {name}" },
|
||||||
|
"a11y.expand": { "translation": "Expand {name}" },
|
||||||
|
"a11y.open": { "translation": "Open {name}" }
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"tab.title": { "translation": "Git" },
|
||||||
|
"panel.semantics": { "translation": "git panel" },
|
||||||
|
"filter.hint": { "translation": "Filter changes…" },
|
||||||
|
"status.loading": { "translation": "Loading…" },
|
||||||
|
"status.clean": { "translation": "Nothing to commit, working tree clean." },
|
||||||
|
"group.conflicts": { "translation": "Merge conflicts" },
|
||||||
|
"group.staged": { "translation": "Staged" },
|
||||||
|
"group.changes": { "translation": "Changes" },
|
||||||
|
"group.untracked": { "translation": "Untracked" },
|
||||||
|
"action.unstageAll": { "translation": "Unstage all" },
|
||||||
|
"action.stageAll": { "translation": "Stage all" },
|
||||||
|
"commit.message.semantics": { "translation": "commit message" },
|
||||||
|
"commit.button": { "translation": "Commit" },
|
||||||
|
"commit.button.semantics": { "translation": "commit staged changes" },
|
||||||
|
"branch.detached": { "translation": "(detached)" },
|
||||||
|
"action.pull": { "translation": "Pull" },
|
||||||
|
"action.pull.semantics": { "translation": "git pull" },
|
||||||
|
"action.push": { "translation": "Push" },
|
||||||
|
"action.push.semantics": { "translation": "git push" },
|
||||||
|
"state.added": { "translation": "added" },
|
||||||
|
"state.modified": { "translation": "modified" },
|
||||||
|
"state.deleted": { "translation": "deleted" },
|
||||||
|
"state.renamed": { "translation": "renamed" },
|
||||||
|
"state.copied": { "translation": "copied" },
|
||||||
|
"state.untracked": { "translation": "untracked" },
|
||||||
|
"row.stage.semantics": { "translation": "stage {name}" },
|
||||||
|
"row.unstage.semantics": { "translation": "unstage {name}" },
|
||||||
|
"row.discard.semantics": { "translation": "discard changes to {name}" },
|
||||||
|
"discard.title": { "translation": "Discard changes?" },
|
||||||
|
"discard.body": { "translation": "Unstaged changes to {name} will be permanently lost." },
|
||||||
|
"button.cancel": { "translation": "Cancel" },
|
||||||
|
"button.discard": { "translation": "Discard" },
|
||||||
|
"branch.switch.semantics": { "translation": "switch branch — {branch}" },
|
||||||
|
"branchPicker.title": { "translation": "Switch branch" },
|
||||||
|
"branchPicker.empty": { "translation": "No branches found." },
|
||||||
|
"branchPicker.loadFailed": { "translation": "failed to load branches" }
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"tab.graph.title": { "translation": "Graph" },
|
||||||
|
"graph.empty": { "translation": "No linked notes in this vault." },
|
||||||
|
"graph.empty.filtered": { "translation": "No notes match the filter." },
|
||||||
|
"graph.empty.nolocal": { "translation": "Open a note to see its local graph." },
|
||||||
|
"graph.filter.glob": { "translation": "Path glob, e.g. notes/**" },
|
||||||
|
"graph.filter.depth": { "translation": "Local" },
|
||||||
|
"graph.filter.all": { "translation": "All" }
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"command.preset.default": { "translation": "Keymap: Default" },
|
||||||
|
"command.preset.vim": { "translation": "Keymap: Vim" },
|
||||||
|
"command.preset.vscode": { "translation": "Keymap: VS Code" },
|
||||||
|
"command.preset.jetbrains": { "translation": "Keymap: JetBrains" },
|
||||||
|
"settings.keymap.title": { "translation": "Keymap" },
|
||||||
|
"settings.keymap.section.preset": { "translation": "Preset" },
|
||||||
|
"settings.keymap.field.preset.label": { "translation": "Active preset" },
|
||||||
|
"settings.keymap.field.preset.help": { "translation": "Keyboard layout for the whole app." },
|
||||||
|
"settings.keymap.field.preset.option.default": { "translation": "Default" },
|
||||||
|
"settings.keymap.field.preset.option.vim": { "translation": "Vim" },
|
||||||
|
"settings.keymap.field.preset.option.vscode": { "translation": "VS Code" },
|
||||||
|
"settings.keymap.field.preset.option.jetbrains": { "translation": "JetBrains" }
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"empty": { "translation": "Select a .md file to preview it here." },
|
||||||
|
"chrome.title": { "translation": "viewer" },
|
||||||
|
"subtitle.lines": { "translation": "{count} lines" }
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"menu.file": { "translation": "File" },
|
||||||
|
"menu.view": { "translation": "View" },
|
||||||
|
"menu.help": { "translation": "Help" },
|
||||||
|
"about.version": { "translation": "Version" },
|
||||||
|
"about.commit": { "translation": "Commit" },
|
||||||
|
"about.built": { "translation": "Built" },
|
||||||
|
"about.repository": { "translation": "Repository" },
|
||||||
|
"about.checkUpdates": { "translation": "Check for updates" },
|
||||||
|
"about.checking": { "translation": "Checking…" },
|
||||||
|
"about.upToDate": { "translation": "You're on the latest version." },
|
||||||
|
"about.updateAvailable": { "translation": "clide {version} is available — release notes" },
|
||||||
|
"about.updateFailed": { "translation": "Couldn't check for updates" },
|
||||||
|
"licenses.heading": { "translation": "Bundled dependencies" },
|
||||||
|
"licenses.unavailable": { "translation": "Licenses unavailable." },
|
||||||
|
"licenses.loading": { "translation": "Loading…" },
|
||||||
|
"button.close": { "translation": "Close" },
|
||||||
|
"button.cancel": { "translation": "Cancel" },
|
||||||
|
"button.open": { "translation": "Open" },
|
||||||
|
"button.opening": { "translation": "Opening…" },
|
||||||
|
"button.ok": { "translation": "OK" },
|
||||||
|
"dialog.openProject.title": { "translation": "Open project" },
|
||||||
|
"dialog.openProject.body": { "translation": "Enter the path to a git repository." },
|
||||||
|
"dialog.openProject.error": { "translation": "Not a git repository" },
|
||||||
|
"dialog.notRepo.title": { "translation": "No git repo found" },
|
||||||
|
"dialog.notRepo.body": { "translation": "A clide project root requires a git repository." },
|
||||||
|
"command.file.openFolder": { "translation": "File: Open Folder…" },
|
||||||
|
"command.file.newWindow": { "translation": "File: New Window" },
|
||||||
|
"command.file.closeWorkspace": { "translation": "File: Close Project" },
|
||||||
|
"command.help.about": { "translation": "Help: About clide" }
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"a11y.log": { "translation": "output log" },
|
||||||
|
"empty": { "translation": "No output yet." },
|
||||||
|
"empty.filtered": { "translation": "No output matches the filter." },
|
||||||
|
"filter.hint": { "translation": "Filter…" },
|
||||||
|
"chip.level": { "translation": "Level: {level}" },
|
||||||
|
"chip.source": { "translation": "Source: {source}" },
|
||||||
|
"chip.clear": { "translation": "Clear" },
|
||||||
|
"source.all": { "translation": "all" },
|
||||||
|
"a11y.jumpToLatest": { "translation": "jump to latest" },
|
||||||
|
"jump.label": { "translation": "Jump to latest ↓" },
|
||||||
|
"a11y.toggleDock": { "translation": "toggle output dock" },
|
||||||
|
"dock.label": { "translation": "Output" },
|
||||||
|
"command.dock.toggle": { "translation": "Toggle output dock" }
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"tab.title": { "translation": "pql" },
|
||||||
|
"tab.links.title": { "translation": "Links" },
|
||||||
|
"filter.markdown.hint": { "translation": "Filter markdown…" },
|
||||||
|
"loading": { "translation": "Loading…" },
|
||||||
|
"empty.markdown": { "translation": "No markdown files found." },
|
||||||
|
"search.vault.hint": { "translation": "Search vault…" },
|
||||||
|
"search.query.hint": { "translation": "PQL query…" },
|
||||||
|
"backlinks.empty": { "translation": "Open a file to see its links." },
|
||||||
|
"backlinks.loading": { "translation": "Loading…" },
|
||||||
|
"backlinks.semantics": { "translation": "backlinks for {path}" },
|
||||||
|
"group.backlinks": { "translation": "Backlinks" },
|
||||||
|
"group.outlinks": { "translation": "Outlinks" },
|
||||||
|
"group.label": { "translation": "{label} ({count})" },
|
||||||
|
"group.none": { "translation": "None" }
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"tab.title": { "translation": "Problems" },
|
||||||
|
"semantics.panel": { "translation": "problems panel" },
|
||||||
|
"filter.hint": { "translation": "Filter problems…" },
|
||||||
|
"count": { "translation": "Problems ({count})" },
|
||||||
|
"refresh.label": { "translation": "Refresh" },
|
||||||
|
"refresh.semantics": { "translation": "refresh problems" },
|
||||||
|
"scanning": { "translation": "Scanning…" },
|
||||||
|
"empty": { "translation": "No problems found." }
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"mode.find": { "translation": "Find" },
|
||||||
|
"mode.vault": { "translation": "Vault" },
|
||||||
|
"mode.query": { "translation": "Query" },
|
||||||
|
"mode.markdown": { "translation": "Markdown" },
|
||||||
|
"find.hint": { "translation": "Search" },
|
||||||
|
"replace.hint": { "translation": "Replace" },
|
||||||
|
"include.hint": { "translation": "files to include (e.g. *.dart)" },
|
||||||
|
"exclude.hint": { "translation": "files to exclude" },
|
||||||
|
"toggle.regex": { "translation": "Regular expression" },
|
||||||
|
"toggle.caseInsensitive": { "translation": "Case insensitive" },
|
||||||
|
"status.searching": { "translation": "Searching…" },
|
||||||
|
"status.noResults": { "translation": "No results" },
|
||||||
|
"status.counts": { "translation": "{matches} in {files}" },
|
||||||
|
"a11y.openMatch": { "translation": "Open {path} line {line}" },
|
||||||
|
"button.replaceAll": { "translation": "Replace all" },
|
||||||
|
"button.ok": { "translation": "OK" },
|
||||||
|
"button.cancel": { "translation": "Cancel" },
|
||||||
|
"button.confirm": { "translation": "Confirm" },
|
||||||
|
"dialog.dirty.title": { "translation": "Working tree not clean" },
|
||||||
|
"dialog.dirty.body": { "translation": "Commit or stash your changes before replacing — git is the only undo." },
|
||||||
|
"dialog.confirm.body": { "translation": "Replace {matches} match(es) across {files} file(s)? This cannot be undone in clide." }
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"command.open": { "translation": "Settings…" },
|
||||||
|
"modal.title": { "translation": "Settings" },
|
||||||
|
"modal.close": { "translation": "Close" },
|
||||||
|
"modal.close.hint": { "translation": "Close settings without changing anything" },
|
||||||
|
"rail.header": { "translation": "Categories" },
|
||||||
|
"panel.empty": { "translation": "No settings categories are registered yet." },
|
||||||
|
"search.hint": { "translation": "Search settings…" },
|
||||||
|
"search.empty": { "translation": "No settings match your search." },
|
||||||
|
"scope.project": { "translation": "This project" },
|
||||||
|
"scope.always": { "translation": "All clide" },
|
||||||
|
"scope.default": { "translation": "Default" },
|
||||||
|
"scope.reset": { "translation": "Reset to default" },
|
||||||
|
"scope.tip.project": { "translation": "Stored in this project (.clide)" },
|
||||||
|
"scope.tip.always": { "translation": "Stored for all clide (~/.clide)" },
|
||||||
|
"scope.tip.default": { "translation": "Unset — using the default" }
|
||||||
|
}
|
||||||
+3
-1
@@ -1,7 +1,9 @@
|
|||||||
{
|
{
|
||||||
"tab.title": { "translation": "Terminal" },
|
"tab.title": { "translation": "Terminal" },
|
||||||
|
"chrome.title": { "translation": "terminal" },
|
||||||
"subtitle.spawning": { "translation": "spawning shell…" },
|
"subtitle.spawning": { "translation": "spawning shell…" },
|
||||||
"subtitle.exited": { "translation": "Shell exited." },
|
"subtitle.exited": { "translation": "Shell exited." },
|
||||||
"error.unavailable": { "translation": "Terminal unavailable" },
|
"error.unavailable": { "translation": "Terminal unavailable" },
|
||||||
"error.daemon": { "translation": "Backend not connected." }
|
"error.daemon": { "translation": "Backend not connected." },
|
||||||
|
"a11y.label": { "translation": "terminal — {subtitle}" }
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"command.pick": { "translation": "Theme…" },
|
||||||
|
"modal.title": { "translation": "Select theme" },
|
||||||
|
"modal.cancel": { "translation": "Cancel" },
|
||||||
|
"modal.cancel.hint": { "translation": "Close the theme picker without changing the current theme" },
|
||||||
|
"row.select.hint": { "translation": "Activate this theme" },
|
||||||
|
"section.appearance": { "translation": "Appearance" },
|
||||||
|
"toggle.highContrast": { "translation": "High contrast" },
|
||||||
|
"settings.appearance.title": { "translation": "Appearance" },
|
||||||
|
"settings.appearance.section.theme": { "translation": "Theme" },
|
||||||
|
"settings.appearance.section.typography": { "translation": "Typography" },
|
||||||
|
"settings.appearance.field.theme.label": { "translation": "Theme" },
|
||||||
|
"settings.appearance.field.theme.help": { "translation": "Color theme; high contrast switches to the accessible variant." },
|
||||||
|
"settings.appearance.field.uiFont.label": { "translation": "UI font" },
|
||||||
|
"settings.appearance.field.uiFont.help": { "translation": "Typeface for the app interface; applies live." },
|
||||||
|
"settings.appearance.field.uiFont.option.josefinSans": { "translation": "Josefin Sans" },
|
||||||
|
"settings.appearance.field.uiFont.option.inter": { "translation": "Inter" },
|
||||||
|
"settings.appearance.field.monoFont.label": { "translation": "Monospace font" },
|
||||||
|
"settings.appearance.field.monoFont.help": { "translation": "Terminal, diffs, code, and IDs; applies live." },
|
||||||
|
"settings.appearance.field.monoFont.option.jetBrainsMono": { "translation": "JetBrains Mono" },
|
||||||
|
"settings.appearance.field.monoFont.option.firaMono": { "translation": "Fira Mono" },
|
||||||
|
"settings.appearance.section.language": { "translation": "Language" },
|
||||||
|
"settings.appearance.field.language.label": { "translation": "Language" },
|
||||||
|
"settings.appearance.field.language.help": { "translation": "Language for the app interface; applies live." }
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"tab.title": { "translation": "Tickets" },
|
||||||
|
"tab.detail.title": { "translation": "Ticket" },
|
||||||
|
"type.initiative": { "translation": "Initiative" },
|
||||||
|
"type.epic": { "translation": "Epic" },
|
||||||
|
"type.story": { "translation": "Story" },
|
||||||
|
"type.task": { "translation": "Task" },
|
||||||
|
"type.bug": { "translation": "Bug" },
|
||||||
|
"loading": { "translation": "Loading tickets..." },
|
||||||
|
"error.load": { "translation": "failed to load tickets" },
|
||||||
|
"empty": { "translation": "No tickets.\nRun `pql ticket new` to create one." },
|
||||||
|
"filter.hint": { "translation": "Filter tickets…" },
|
||||||
|
"refresh.tooltip": { "translation": "Refresh tickets" },
|
||||||
|
"section.in_progress": { "translation": "IN PROGRESS" },
|
||||||
|
"section.review": { "translation": "REVIEW" },
|
||||||
|
"section.ready": { "translation": "READY" },
|
||||||
|
"section.backlog": { "translation": "BACKLOG" },
|
||||||
|
"section.done": { "translation": "DONE" },
|
||||||
|
"section.cancelled": { "translation": "CANCELLED" },
|
||||||
|
"chip.label": { "translation": "{type} type filter" },
|
||||||
|
"chip.tooltip": { "translation": "Click to toggle · double-click to isolate" },
|
||||||
|
"badge.wip": { "translation": "WIP" },
|
||||||
|
"badge.review": { "translation": "REVIEW" },
|
||||||
|
"badge.cancelled": { "translation": "CANCELLED" },
|
||||||
|
"pickUp.tooltip": { "translation": "Pick up — hand this ticket to the Claude pane" },
|
||||||
|
"detail.loading": { "translation": "Loading…" },
|
||||||
|
"detail.empty": { "translation": "Select a ticket to view details." },
|
||||||
|
"detail.assigned": { "translation": "assigned: {name}" },
|
||||||
|
"detail.section.parents": { "translation": "PARENT TREE" },
|
||||||
|
"detail.section.decisions": { "translation": "REFERENCED DECISIONS" },
|
||||||
|
"status.backlog": { "translation": "BACKLOG" },
|
||||||
|
"status.ready": { "translation": "READY" },
|
||||||
|
"status.in_progress": { "translation": "WIP" },
|
||||||
|
"status.review": { "translation": "REVIEW" },
|
||||||
|
"status.done": { "translation": "DONE" }
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"command.detect": { "translation": "Re-detect tool paths" },
|
||||||
|
"settings.title": { "translation": "Tools" },
|
||||||
|
"settings.section.binaries": { "translation": "Supporter binaries" },
|
||||||
|
"settings.field.claude.label": { "translation": "Claude CLI" },
|
||||||
|
"settings.field.claude.help": { "translation": "Absolute path to the claude binary; blank to auto-resolve." },
|
||||||
|
"settings.field.d2.label": { "translation": "d2" },
|
||||||
|
"settings.field.d2.help": { "translation": "Absolute path to the d2 diagram compiler; blank to auto-resolve." },
|
||||||
|
"settings.field.detect.label": { "translation": "Re-detect" },
|
||||||
|
"settings.field.detect.help": { "translation": "Re-scan PATH and the common install dirs, overwriting the paths above." },
|
||||||
|
"settings.section.path": { "translation": "Workspace PATH" },
|
||||||
|
"settings.field.pathPreset.label": { "translation": "Prepend to PATH" },
|
||||||
|
"settings.field.pathPreset.help": { "translation": "Directories put ahead of PATH in Claude sessions and terminal panes spawned for this repo; worktrees share the repo's preset. Applies to new shells." },
|
||||||
|
"path.noWorkspace": { "translation": "Open a workspace to set its PATH preset." },
|
||||||
|
"path.sharedRoot": { "translation": "Worktree — preset shared with" },
|
||||||
|
"path.empty": { "translation": "No preset entries — spawned shells get the resolved login-shell PATH as-is." },
|
||||||
|
"path.add": { "translation": "Add entry" },
|
||||||
|
"path.invalid": { "translation": "Enter an absolute path (or ~/…)." },
|
||||||
|
"path.missing": { "translation": "missing" },
|
||||||
|
"path.moveUp": { "translation": "Move up" },
|
||||||
|
"path.moveDown": { "translation": "Move down" },
|
||||||
|
"path.remove": { "translation": "Remove" },
|
||||||
|
"path.capture": { "translation": "Suggest from login shell" },
|
||||||
|
"path.captureNone": { "translation": "Nothing to suggest — the login-shell PATH is already covered." },
|
||||||
|
"path.addSuggestion": { "translation": "Add suggested entry" }
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"command.view.zoomIn": { "translation": "View: Zoom In" },
|
||||||
|
"command.view.zoomOut": { "translation": "View: Zoom Out" },
|
||||||
|
"command.view.zoomReset": { "translation": "View: Reset Zoom" }
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"mode.normal": { "translation": "NORMAL" },
|
||||||
|
"mode.insert": { "translation": "INSERT" },
|
||||||
|
"mode.visual": { "translation": "VISUAL" },
|
||||||
|
"command.vim.mode.normal": { "translation": "Vim: Normal mode" },
|
||||||
|
"command.vim.mode.insert": { "translation": "Vim: Insert mode" },
|
||||||
|
"command.vim.mode.visual": { "translation": "Vim: Visual mode" }
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"title": { "translation": "clide" },
|
||||||
|
"subtitle": { "translation": "IDE for Claude Code CLI" },
|
||||||
|
"open-project": { "translation": "Open project" },
|
||||||
|
"open-project.hint": { "translation": "Pick a git repository to open as the workspace" },
|
||||||
|
"tab.title": { "translation": "Welcome" },
|
||||||
|
"section.tips": { "translation": "TIPS" },
|
||||||
|
"section.start": { "translation": "START" },
|
||||||
|
"section.recent": { "translation": "RECENT" },
|
||||||
|
"tips.quickOpen": { "translation": "Quick open" },
|
||||||
|
"tips.commandPalette": { "translation": "Command palette" },
|
||||||
|
"tips.toggleSidebar": { "translation": "Toggle sidebar" },
|
||||||
|
"tips.toggleContext": { "translation": "Toggle context" },
|
||||||
|
"tips.findInFiles": { "translation": "Find in files" },
|
||||||
|
"tips.focusMode": { "translation": "Focus mode" },
|
||||||
|
"action.openFolder": { "translation": "Open folder…" },
|
||||||
|
"action.newProject": { "translation": "New project…" },
|
||||||
|
"dialog.newProject.title": { "translation": "New project" },
|
||||||
|
"dialog.newProject.body": { "translation": "Creates a git repo + a CLAUDE.md, then opens it." },
|
||||||
|
"button.create": { "translation": "Create" },
|
||||||
|
"button.creating": { "translation": "Creating…" },
|
||||||
|
"recent.empty": { "translation": "No recent projects." },
|
||||||
|
"sticky.label": { "translation": "always open this project on launch" },
|
||||||
|
"sticky.tooltip": { "translation": "Always open this project on launch" },
|
||||||
|
"sticky.tooltip.active": { "translation": "Always open this project on launch (uncheck to restore picker)" },
|
||||||
|
"status.checking": { "translation": "checking…" },
|
||||||
|
"status.ok": { "translation": "application ok" },
|
||||||
|
"status.notFound": { "translation": "{tool} not found" },
|
||||||
|
"status.theme": { "translation": "theme: " },
|
||||||
|
"dialog.openProject.title": { "translation": "Open project" },
|
||||||
|
"dialog.openProject.body": { "translation": "Enter the path to a git repository." },
|
||||||
|
"dialog.openProject.error": { "translation": "Not a git repository" },
|
||||||
|
"button.cancel": { "translation": "Cancel" },
|
||||||
|
"button.open": { "translation": "Open" },
|
||||||
|
"button.opening": { "translation": "Opening…" },
|
||||||
|
"button.ok": { "translation": "OK" },
|
||||||
|
"dialog.notRepo.title": { "translation": "No git repo found" },
|
||||||
|
"dialog.notRepo.body": { "translation": "A clide project needs a git repository. Initialize this folder as one?" },
|
||||||
|
"dialog.notRepo.initialize": { "translation": "Initialize project" },
|
||||||
|
"button.initializing": { "translation": "Initializing…" },
|
||||||
|
"command.workspace.open-project": { "translation": "Workspace: Open project…" }
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"collapser.expand": { "translation": "Expand" },
|
||||||
|
"collapser.collapse": { "translation": "Collapse" },
|
||||||
|
"collapser.expanded": { "translation": "expanded" },
|
||||||
|
"collapser.collapsed": { "translation": "collapsed" },
|
||||||
|
"toast.dismiss": { "translation": "Dismiss notification" },
|
||||||
|
"lightbox.close": { "translation": "close" },
|
||||||
|
"lightbox.hint": { "translation": "scroll to zoom · double-click to reset · Esc to close" },
|
||||||
|
"tab.new": { "translation": "New tab" },
|
||||||
|
"exline.notCommand": { "translation": "Not an editor command" },
|
||||||
|
"spine.expandSuffix": { "translation": "click to expand" },
|
||||||
|
"pane.close": { "translation": "Close pane" },
|
||||||
|
"pane.header": { "translation": "pane header: {title}" },
|
||||||
|
"reader.back": { "translation": "Back" },
|
||||||
|
"reader.forward": { "translation": "Forward" },
|
||||||
|
"reader.jumpToPin": { "translation": "Jump to pin" },
|
||||||
|
"reader.edit": { "translation": "Edit in editor" },
|
||||||
|
"reader.pin": { "translation": "Pin" },
|
||||||
|
"reader.unpin": { "translation": "Unpin" },
|
||||||
|
"link.openInEditor": { "translation": "Open in editor" },
|
||||||
|
"resize.axis.width": { "translation": "width" },
|
||||||
|
"resize.axis.height": { "translation": "height" },
|
||||||
|
"resize.sidebar": { "translation": "Sidebar {axis}" },
|
||||||
|
"resize.contextPanel": { "translation": "Context panel {axis}" },
|
||||||
|
"resize.slot": { "translation": "{slot} {axis}" },
|
||||||
|
"resize.pixels": { "translation": "{n} pixels" }
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"tab.title": { "translation": "Canvas" },
|
||||||
|
"empty": { "translation": "Open een .canvas-bestand om het hier te bekijken." },
|
||||||
|
"status.loading": { "translation": "Laden…" }
|
||||||
|
}
|
||||||
@@ -0,0 +1,251 @@
|
|||||||
|
{
|
||||||
|
"tab.title": { "translation": "Claude" },
|
||||||
|
"status.attaching": { "translation": "verbinden…" },
|
||||||
|
"status.no-tmux": { "translation": "no-tmux · elke start opnieuw" },
|
||||||
|
"status.exited": { "translation": "sessie beëindigd" },
|
||||||
|
"status.primary-exited": { "translation": "sessie beëindigd — herstart clide om opnieuw te proberen" },
|
||||||
|
"banner.title": { "translation": "Claude" },
|
||||||
|
"banner.warmingUp": { "translation": "Opstarten — je gesprek verschijnt hier." },
|
||||||
|
"banner.role.primary": { "translation": "primair" },
|
||||||
|
"banner.role.secondary": { "translation": "sessie {index}" },
|
||||||
|
"composer.hint": { "translation": "Bericht aan Claude… (Enter om te verzenden · Shift+Enter voor een nieuwe regel)" },
|
||||||
|
"composer.stop": { "translation": "Stop ⎋" },
|
||||||
|
"composer.stop.hint": { "translation": "Onderbreek de lopende beurt (Escape)" },
|
||||||
|
"composer.removeAttachment": { "translation": "{name} verwijderen" },
|
||||||
|
"pane.title.primary": { "translation": "claude — primair" },
|
||||||
|
"pane.title.secondary": { "translation": "claude — secundair {index}" },
|
||||||
|
"pane.starting": { "translation": "starten…" },
|
||||||
|
"pane.modeBadge.semantics": { "translation": "permissiemodus: {mode}" },
|
||||||
|
"running.semantics": { "translation": "Claude is bezig" },
|
||||||
|
"running.verb.pondering": { "translation": "Peinzen" },
|
||||||
|
"running.verb.conjuring": { "translation": "Toveren" },
|
||||||
|
"running.verb.brewing": { "translation": "Brouwen" },
|
||||||
|
"running.verb.tinkering": { "translation": "Knutselen" },
|
||||||
|
"running.verb.noodling": { "translation": "Prutsen" },
|
||||||
|
"running.verb.percolating": { "translation": "Pruttelen" },
|
||||||
|
"running.verb.computing": { "translation": "Rekenen" },
|
||||||
|
"running.verb.wrangling": { "translation": "Worstelen" },
|
||||||
|
"running.verb.untangling": { "translation": "Ontwarren" },
|
||||||
|
"running.verb.synthesizing": { "translation": "Synthetiseren" },
|
||||||
|
"running.verb.cogitating": { "translation": "Overpeinzen" },
|
||||||
|
"running.verb.whirring": { "translation": "Snorren" },
|
||||||
|
"running.verb.mincing": { "translation": "Hakken" },
|
||||||
|
"running.verb.boiling": { "translation": "Koken" },
|
||||||
|
"running.verb.humming": { "translation": "Neuriën" },
|
||||||
|
"running.verb.buzzing": { "translation": "Zoemen" },
|
||||||
|
"running.verb.magicking": { "translation": "Goochelen" },
|
||||||
|
"running.verb.cliding": { "translation": "Cliden" },
|
||||||
|
"running.verb.zooming": { "translation": "Zoeven" },
|
||||||
|
"running.verb.bouncing": { "translation": "Stuiteren" },
|
||||||
|
"conversation.empty": { "translation": "Wachten op Claude…" },
|
||||||
|
"conversation.label.you": { "translation": "jij" },
|
||||||
|
"conversation.label.claude": { "translation": "claude" },
|
||||||
|
"conversation.label.clide": { "translation": "clide" },
|
||||||
|
"conversation.label.agent": { "translation": "agent" },
|
||||||
|
"conversation.label.agentPrompt": { "translation": "agent-prompt" },
|
||||||
|
"conversation.label.context": { "translation": "context" },
|
||||||
|
"conversation.label.thinking": { "translation": "nadenken" },
|
||||||
|
"conversation.label.agentThinking": { "translation": "agent denkt na" },
|
||||||
|
"conversation.label.image": { "translation": "afbeelding" },
|
||||||
|
"conversation.label.icon": { "translation": "iconen" },
|
||||||
|
"conversation.label.drawing": { "translation": "tekening" },
|
||||||
|
"conversation.draw.viewSource": { "translation": "d2-bron tonen" },
|
||||||
|
"conversation.label.agentRun": { "translation": "agent-uitvoering" },
|
||||||
|
"conversation.label.workflow": { "translation": "workflow" },
|
||||||
|
"conversation.label.error": { "translation": "fout" },
|
||||||
|
"conversation.label.result": { "translation": "resultaat" },
|
||||||
|
"conversation.label.denied": { "translation": "geweigerd" },
|
||||||
|
"conversation.segment.prompt": { "translation": "prompt" },
|
||||||
|
"conversation.segment.result": { "translation": "resultaat" },
|
||||||
|
"conversation.segment.liveTail": { "translation": "live tail" },
|
||||||
|
"conversation.segment.usage": { "translation": "verbruik" },
|
||||||
|
"conversation.segment.script": { "translation": "script" },
|
||||||
|
"conversation.workflow.launching": { "translation": "Starten…" },
|
||||||
|
"conversation.imagePlaceholder": { "translation": "kon {path} niet laden" },
|
||||||
|
"conversation.bashTail.empty": { "translation": "geen onafhankelijke bron om te volgen" },
|
||||||
|
"conversation.bashTail.label": { "translation": "live tail" },
|
||||||
|
"conversation.cluster.activity": { "translation": "Activiteit" },
|
||||||
|
"conversation.cluster.edits": { "translation": "Wijzigingen" },
|
||||||
|
"conversation.counter.step": { "translation": "1 stap" },
|
||||||
|
"conversation.counter.steps": { "translation": "{count} stappen" },
|
||||||
|
"conversation.counter.edit": { "translation": "1 wijziging" },
|
||||||
|
"conversation.counter.edits": { "translation": "{count} wijzigingen" },
|
||||||
|
"conversation.counter.starting": { "translation": "starten" },
|
||||||
|
"conversation.counter.agents": { "translation": "{done}/{total} agents" },
|
||||||
|
"prompt.permission.allow": { "translation": "1. Toestaan" },
|
||||||
|
"prompt.permission.allowRemember": { "translation": "2. Toestaan en niet meer vragen" },
|
||||||
|
"prompt.permission.deny": { "translation": "{n}. Weigeren" },
|
||||||
|
"prompt.permission.denySimplify": { "translation": "{n}. Weigeren en vereenvoudigen" },
|
||||||
|
"prompt.permission.denySimplify.tooltip": { "translation": "Weiger en vraag Claude deze actie in een eenvoudigere vorm opnieuw te proberen — complexe interacties werken niet goed met het permissiesysteem." },
|
||||||
|
"prompt.permission.note.placeholder": { "translation": "voeg een notitie toe (optioneel) — wordt naar Claude gestuurd" },
|
||||||
|
"prompt.permission.label": { "translation": "permissie · {name}" },
|
||||||
|
"prompt.question.label": { "translation": "vraag" },
|
||||||
|
"prompt.review.label": { "translation": "controleren" },
|
||||||
|
"prompt.review.title": { "translation": "Controleer je antwoorden" },
|
||||||
|
"prompt.submit": { "translation": "Verzenden" },
|
||||||
|
"prompt.submitAnswers": { "translation": "Antwoorden verzenden" },
|
||||||
|
"prompt.back": { "translation": "‹ Terug" },
|
||||||
|
"prompt.next": { "translation": "Volgende ›" },
|
||||||
|
"prompt.reviewNav": { "translation": "Controleren ›" },
|
||||||
|
"prompt.nav.review": { "translation": "Controleren" },
|
||||||
|
"prompt.option.other": { "translation": "Anders…" },
|
||||||
|
"prompt.other.placeholder": { "translation": "typ je antwoord…" },
|
||||||
|
"prompt.note.placeholder": { "translation": "+ notitie (optioneel)" },
|
||||||
|
"prompt.chatInstead": { "translation": "in plaats daarvan chatten" },
|
||||||
|
"tool.edit.before": { "translation": "— voor" },
|
||||||
|
"tool.edit.after": { "translation": "+ na" },
|
||||||
|
"tool.bash.background": { "translation": "achtergrond" },
|
||||||
|
"tool.name.Read": { "translation": "Lezen" },
|
||||||
|
"tool.name.Edit": { "translation": "Bewerken" },
|
||||||
|
"tool.name.MultiEdit": { "translation": "Meervoudig bewerken" },
|
||||||
|
"tool.name.Write": { "translation": "Schrijven" },
|
||||||
|
"tool.name.NotebookEdit": { "translation": "Notebook bewerken" },
|
||||||
|
"tool.name.WebFetch": { "translation": "Web ophalen" },
|
||||||
|
"tool.name.WebSearch": { "translation": "Web zoeken" },
|
||||||
|
"tool.name.Task": { "translation": "Taak" },
|
||||||
|
"tool.name.TodoWrite": { "translation": "Takenlijst" },
|
||||||
|
"tool.name.ExitPlanMode": { "translation": "Planmodus verlaten" },
|
||||||
|
"permissionControl.semantics": { "translation": "permissiemodus: {mode}. Activeer om te wijzigen." },
|
||||||
|
"permissionControl.tooltip": { "translation": "Permissiemodus: {mode} — wijzigen (Ctrl/Cmd+M wisselt; +Shift ook bypass)" },
|
||||||
|
"permissionControl.bypassHint": { "translation": "shift-klik" },
|
||||||
|
"permissionControl.bypassSemantics": { "translation": "bypassPermissions — shift-klik om in te schakelen" },
|
||||||
|
"permissionBadge.tooltip": { "translation": "Permissiemodus: {mode}. Klik om te wisselen tussen default/acceptEdits/plan; Shift-klik voor bypassPermissions." },
|
||||||
|
"permissionBadge.semantics": { "translation": "Permissiemodus: {label}" },
|
||||||
|
"card.expand": { "translation": "Uitvouwen" },
|
||||||
|
"card.collapse": { "translation": "Invouwen" },
|
||||||
|
"card.succeeded": { "translation": "gelukt" },
|
||||||
|
"card.failed": { "translation": "mislukt" },
|
||||||
|
"card.copy": { "translation": "kopiëren" },
|
||||||
|
"taskDock.summary": { "translation": "{count} {tasks} · {done} klaar" },
|
||||||
|
"taskDock.task.singular": { "translation": "taak" },
|
||||||
|
"taskDock.task.plural": { "translation": "taken" },
|
||||||
|
"taskDock.collapse": { "translation": "Taken invouwen" },
|
||||||
|
"taskDock.expand": { "translation": "Taken uitvouwen" },
|
||||||
|
"taskDock.semantics": { "translation": "Takenlijst van Claude, {summary}, {state}" },
|
||||||
|
"taskDock.state.expanded": { "translation": "uitgevouwen" },
|
||||||
|
"taskDock.state.collapsed": { "translation": "ingevouwen" },
|
||||||
|
"taskDock.status.done": { "translation": "klaar" },
|
||||||
|
"taskDock.status.inProgress": { "translation": "bezig" },
|
||||||
|
"taskDock.status.pending": { "translation": "in wachtrij" },
|
||||||
|
"taskDock.row.semantics": { "translation": "{text}, {status}" },
|
||||||
|
"sessionPicker.title": { "translation": "Een Claude-sessie hervatten" },
|
||||||
|
"sessionPicker.empty": { "translation": "Geen sessies gevonden voor deze workspace." },
|
||||||
|
"modelPicker.cancel": { "translation": "annuleren" },
|
||||||
|
"image.semantics": { "translation": "Afbeelding {name}" },
|
||||||
|
"activity.section.session": { "translation": "SESSIE" },
|
||||||
|
"activity.control.clear": { "translation": "wissen" },
|
||||||
|
"activity.control.compact": { "translation": "compact" },
|
||||||
|
"activity.control.fork": { "translation": "fork" },
|
||||||
|
"activity.control.resume": { "translation": "hervatten" },
|
||||||
|
"activity.control.refreshUsage": { "translation": "verbruik vernieuwen" },
|
||||||
|
"activity.control.semantics": { "translation": "{label} sessie" },
|
||||||
|
"activity.control.tooltip": { "translation": "{label} · {command}" },
|
||||||
|
"activity.empty": { "translation": "Nog geen activiteit vastgelegd." },
|
||||||
|
"activity.section.workflows": { "translation": "WORKFLOWS" },
|
||||||
|
"activity.workflow.fallback": { "translation": "workflow" },
|
||||||
|
"activity.workflow.done": { "translation": "klaar" },
|
||||||
|
"activity.workflow.starting": { "translation": "starten" },
|
||||||
|
"activity.section.usage": { "translation": "VERBRUIK" },
|
||||||
|
"activity.row.session": { "translation": "sessie" },
|
||||||
|
"activity.row.weekAll": { "translation": "week (alles)" },
|
||||||
|
"activity.row.weekSonnet": { "translation": "week (sonnet)" },
|
||||||
|
"activity.section.today": { "translation": "VANDAAG" },
|
||||||
|
"activity.row.messages": { "translation": "berichten" },
|
||||||
|
"activity.row.sessions": { "translation": "sessies" },
|
||||||
|
"activity.row.toolCalls": { "translation": "tool-aanroepen" },
|
||||||
|
"activity.section.lifetime": { "translation": "TOTAAL" },
|
||||||
|
"activity.section.runtime": { "translation": "RUNTIME · primair" },
|
||||||
|
"activity.row.model": { "translation": "model" },
|
||||||
|
"activity.row.effort": { "translation": "effort" },
|
||||||
|
"activity.row.context": { "translation": "context" },
|
||||||
|
"activity.row.mode": { "translation": "modus" },
|
||||||
|
"activity.row.skills": { "translation": "skills" },
|
||||||
|
"config.empty": { "translation": "Claude-omgeving niet geladen." },
|
||||||
|
"config.section.settings": { "translation": "INSTELLINGEN" },
|
||||||
|
"config.row.model": { "translation": "model" },
|
||||||
|
"config.row.effort": { "translation": "effort" },
|
||||||
|
"config.row.permissionMode": { "translation": "permissiemodus" },
|
||||||
|
"config.row.outputStyle": { "translation": "uitvoerstijl" },
|
||||||
|
"config.row.source": { "translation": "bron" },
|
||||||
|
"config.row.source.value": { "translation": "~/.claude + .claude" },
|
||||||
|
"config.footer": { "translation": "vouw een lijst uit om alles te zien · klik op een skill/agent/command → opent de .md" },
|
||||||
|
"config.section.skills": { "translation": "SKILLS" },
|
||||||
|
"config.section.agents": { "translation": "AGENTS" },
|
||||||
|
"config.section.commands": { "translation": "COMMANDS" },
|
||||||
|
"config.section.hooks": { "translation": "HOOKS" },
|
||||||
|
"config.section.permissions": { "translation": "PERMISSIES" },
|
||||||
|
"config.section.mcpServers": { "translation": "MCP SERVERS" },
|
||||||
|
"config.perm.allow": { "translation": "toestaan" },
|
||||||
|
"config.perm.ask": { "translation": "vragen" },
|
||||||
|
"config.perm.deny": { "translation": "weigeren" },
|
||||||
|
"config.control.semantics": { "translation": "{label}: {value}. Klik om te wijzigen." },
|
||||||
|
"config.control.tooltip": { "translation": "{label} wijzigen" },
|
||||||
|
"config.control.option.semantics": { "translation": "{label}: {name}" },
|
||||||
|
"roster.bypass.confirmBody": { "translation": "bypassPermissions inschakelen? Alle tool-aanroepen worden automatisch toegestaan." },
|
||||||
|
"roster.bypass.confirm.semantics": { "translation": "Bypass bevestigen" },
|
||||||
|
"roster.bypass.confirm.tooltip": { "translation": "Bevestigen" },
|
||||||
|
"roster.bypass.ok": { "translation": "OK" },
|
||||||
|
"roster.bypass.cancel.semantics": { "translation": "Bypass annuleren" },
|
||||||
|
"roster.bypass.cancel.tooltip": { "translation": "Annuleren" },
|
||||||
|
"roster.bypass.cancel": { "translation": "Annuleren" },
|
||||||
|
"roster.hidePane": { "translation": "Paneel verbergen" },
|
||||||
|
"roster.showPane": { "translation": "Paneel tonen" },
|
||||||
|
"roster.unmute": { "translation": "Berichten weer aanzetten" },
|
||||||
|
"roster.mute": { "translation": "Berichten dempen" },
|
||||||
|
"roster.inject": { "translation": "Bericht injecteren" },
|
||||||
|
"roster.fork": { "translation": "Sessie forken" },
|
||||||
|
"roster.close": { "translation": "Sessie sluiten" },
|
||||||
|
"roster.inject.cancel": { "translation": "Annuleren" },
|
||||||
|
"taskRow.reassign": { "translation": "Taak opnieuw toewijzen" },
|
||||||
|
"team.empty": { "translation": "Geen team actief." },
|
||||||
|
"team.section.tasks": { "translation": "TAKEN" },
|
||||||
|
"tabStrip.activity": { "translation": "Activiteit" },
|
||||||
|
"tabStrip.team": { "translation": "Team" },
|
||||||
|
"tabStrip.team.count": { "translation": "Team · {count}" },
|
||||||
|
"tabStrip.config": { "translation": "Config" },
|
||||||
|
"teamChat.section.messages": { "translation": "BERICHTEN" },
|
||||||
|
"teamChat.popOut.semantics": { "translation": "Volledig chatpaneel openen" },
|
||||||
|
"teamChat.popOut.tooltip": { "translation": "Volledige chat openen" },
|
||||||
|
"teamChat.empty": { "translation": "Nog geen berichten." },
|
||||||
|
"teamChat.composer.placeholder": { "translation": "@naam of @team …" },
|
||||||
|
"teamChat.pane.title": { "translation": "Teamchat" },
|
||||||
|
"teamChat.interrupt.semantics": { "translation": "Doelsessie onderbreken" },
|
||||||
|
"teamChat.interrupt.label": { "translation": "Onderbreken" },
|
||||||
|
"command.newSecondary": { "translation": "Claude: een secundaire sessie openen" },
|
||||||
|
"command.killAllSessions": { "translation": "Claude: alle sessies voor deze repo afsluiten" },
|
||||||
|
"command.sessionStorage": { "translation": "Claude: sessieopslag (schijfgebruik + opschonen)" },
|
||||||
|
"command.activity.foldLevel": { "translation": "Claude: doorloop het invouwniveau van de activiteit" },
|
||||||
|
"command.agent.show": { "translation": "Claude: een agent-sessiepaneel tonen" },
|
||||||
|
"command.agent.hide": { "translation": "Claude: een agent-sessiepaneel verbergen" },
|
||||||
|
"command.agent.close": { "translation": "Claude: een agent-sessie sluiten (afsluiten)" },
|
||||||
|
"command.agent.mute": { "translation": "Claude: broker-aflevering naar een agent-sessie dempen" },
|
||||||
|
"command.agent.unmute": { "translation": "Claude: broker-aflevering naar een agent-sessie weer aanzetten" },
|
||||||
|
"command.agent.injectMessage": { "translation": "Claude: een tekstbeurt in een agent-sessie injecteren" },
|
||||||
|
"command.agent.setPermissionMode": { "translation": "Claude: permissiemodus voor een agent-sessie instellen" },
|
||||||
|
"command.mode.cycle": { "translation": "Claude: Permissiemodus doorlopen" },
|
||||||
|
"command.task.reassign": { "translation": "Claude: een gedeelde taak opnieuw aan een agent toewijzen" },
|
||||||
|
"command.teamChat.open": { "translation": "Claude: het teamchatpaneel openen" },
|
||||||
|
"command.teamChat.post": { "translation": "Claude: een bericht als gebruiker in het teamkanaal plaatsen" },
|
||||||
|
"command.agent.fork": { "translation": "Claude: een beheerde sessie forken naar een nieuwe branch-sessie" },
|
||||||
|
"settings.activity.title": { "translation": "Activiteit" },
|
||||||
|
"settings.activity.conversation.label": { "translation": "Gesprek" },
|
||||||
|
"settings.activity.foldLevel.label": { "translation": "Invouwniveau" },
|
||||||
|
"settings.activity.foldLevel.help": { "translation": "Hoe agressief het gesprek tool-aanroepen, nadenken en resultaten invouwt." },
|
||||||
|
"settings.activity.opt.none": { "translation": "Alles tonen" },
|
||||||
|
"settings.activity.opt.tools": { "translation": "Tool-aanroepen invouwen" },
|
||||||
|
"settings.activity.opt.thinking": { "translation": "Tools + nadenken invouwen" },
|
||||||
|
"settings.activity.opt.everything": { "translation": "Alles invouwen behalve tekst" },
|
||||||
|
"settings.claude.title": { "translation": "Claude" },
|
||||||
|
"settings.claude.newSessionDefaults.label": { "translation": "Standaardwaarden voor nieuwe sessies" },
|
||||||
|
"settings.claude.model.label": { "translation": "Model" },
|
||||||
|
"settings.claude.model.help": { "translation": "Model voor nieuwe sessies." },
|
||||||
|
"settings.claude.effort.label": { "translation": "Effort" },
|
||||||
|
"settings.claude.effort.help": { "translation": "Reasoning effort voor nieuwe sessies (toegepast via --effort bij het starten)." },
|
||||||
|
"settings.claude.permissionMode.label": { "translation": "Permissiemodus" },
|
||||||
|
"settings.claude.permissionMode.help": { "translation": "Begin-permissiemodus voor nieuwe sessies." },
|
||||||
|
"settings.claude.account.label": { "translation": "Account" },
|
||||||
|
"settings.claude.account.registry.label": { "translation": "Accounts" },
|
||||||
|
"settings.claude.account.registry.help": { "translation": "Geregistreerde Claude-accounts (elk een eigen configmap + login)." },
|
||||||
|
"settings.claude.account.workspace.label": { "translation": "Account voor deze werkmap" },
|
||||||
|
"settings.claude.account.workspace.help": { "translation": "Welk Claude-account deze repo gebruikt; Standaard gebruikt de systeemlogin." }
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"command.clide.installCli": { "translation": "clide: Installeer 'clide'-opdracht in PATH" }
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"tab.title": { "translation": "Beslissingen" },
|
||||||
|
"tab.detail.title": { "translation": "Beslissing" },
|
||||||
|
"loading": { "translation": "Beslissingen laden..." },
|
||||||
|
"error.load": { "translation": "laden van beslissingen mislukt" },
|
||||||
|
"empty": { "translation": "Geen beslissingen gevonden.\nVoer `pql decisions sync` uit om te indexeren." },
|
||||||
|
"filter.hint": { "translation": "Beslissingen filteren…" },
|
||||||
|
"refresh.tooltip": { "translation": "Beslissingen vernieuwen" },
|
||||||
|
"section.confirmed": { "translation": "BEVESTIGD" },
|
||||||
|
"section.questions": { "translation": "VRAGEN" },
|
||||||
|
"section.rejected": { "translation": "AFGEWEZEN" },
|
||||||
|
"badge.resolved": { "translation": "opgelost" },
|
||||||
|
"detail.loading": { "translation": "Laden…" },
|
||||||
|
"detail.empty": { "translation": "Selecteer een beslissing om de details te bekijken." },
|
||||||
|
"detail.section.refs": { "translation": "KRUISVERWIJZINGEN" }
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"dialog.title": { "translation": "Een externe link openen?" },
|
||||||
|
"dialog.body": { "translation": "Een clide://-link van buiten de app vraagt om:" },
|
||||||
|
"dialog.warning": { "translation": "Sta dit alleen toe als je vertrouwt waar de link vandaan komt." },
|
||||||
|
"button.cancel": { "translation": "Annuleren" },
|
||||||
|
"button.open": { "translation": "Openen" },
|
||||||
|
"command.deeplink.invoke": { "translation": "Een clide://-deeplink openen" }
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"command.reset": { "translation": "Indeling: Terugzetten naar Klassiek" },
|
||||||
|
"preset.classic": { "translation": "Klassiek" },
|
||||||
|
"command.palette.toggle": { "translation": "Opdrachtenpalet" },
|
||||||
|
"command.sidebar.collapse": { "translation": "Zijbalk samenvouwen aan/uit" },
|
||||||
|
"command.context.collapse": { "translation": "Contextpaneel samenvouwen aan/uit" },
|
||||||
|
"command.panel.focus.left": { "translation": "Focus op linkerpaneel" },
|
||||||
|
"command.panel.focus.middle": { "translation": "Focus op middelste paneel" },
|
||||||
|
"command.panel.focus.right": { "translation": "Focus op rechterpaneel" },
|
||||||
|
"command.panel.focusMode": { "translation": "Focusmodus aan/uit" },
|
||||||
|
"command.panel.focusMode.exit": { "translation": "Focusmodus afsluiten" },
|
||||||
|
"command.editor.open": { "translation": "Editor openen" },
|
||||||
|
"command.editor.close": { "translation": "Editor sluiten" },
|
||||||
|
"command.workspace.tab.next": { "translation": "Volgend werkruimtetabblad" },
|
||||||
|
"command.workspace.tab.previous": { "translation": "Vorig werkruimtetabblad" },
|
||||||
|
"command.sidebar.section.1": { "translation": "Zijbalk: Sectie 1" },
|
||||||
|
"command.sidebar.section.2": { "translation": "Zijbalk: Sectie 2" },
|
||||||
|
"command.sidebar.section.3": { "translation": "Zijbalk: Sectie 3" },
|
||||||
|
"command.sidebar.section.4": { "translation": "Zijbalk: Sectie 4" },
|
||||||
|
"command.sidebar.section.5": { "translation": "Zijbalk: Sectie 5" }
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user