Epic: shadcn/ui redesign — 2/3 drop zone + 1/3 actions panel (desktop) #27

Closed
opened 2026-10-14 16:06:15 +02:00 by EduarD3V · 38 comments
Owner

Goal

Restyle the sign flow with shadcn/ui (Svelte port — shadcn-svelte). Reference screenshots provided by operator (shadcn default style, neutral palette).

Desktop layout (two-column divs, NO full-width stacking)

  • Left column, 2/3 width: upload area (shadcn Card + dashed dropzone: drag & drop + click-to-browse), below it the file list (shadcn Table or Card list: filename, size, format, status badge, per-row remove)
  • Right column, 1/3 width (sticky top): actions card — upload existing signature file, select from stored signatures (dropdown/combobox, issue #29), options (visible/invisible PDF sig), and a big primary button Firmar pinned at card bottom (h-12+, full width)

Ownership boundaries (parallel work in flight)

  • touch: src/lib/components/{FileDrop,FileCard,SignButton,ResultCard,CertPicker}.svelte, app.css, tailwind config, new src/lib/components/ui/ (shadcn primitives)
  • do NOT touch: src/lib/{sign,pkcs12,keystore,certs}.ts logic files, src/lib/stores.ts signatures store (issue #29 owns it), src/lib/mcp/ (issue #13 owns it), any test/ files
  • components keep existing prop interfaces; visual-only refactor

Acceptance

  • shadcn-svelte initialized (button, card, table, badge, dropdown, dialog, input, tooltip)
  • dark mode via CSS vars (shadcn convention)
  • desktop ≥1024px shows the 2/3+1/3 grid; mobile falls back to stacked
  • existing tests still green; add one component snapshot test per new primitive usage
  • no new heavy deps beyond shadcn-svelte + tailwind (already present)
## Goal Restyle the sign flow with shadcn/ui (Svelte port — shadcn-svelte). Reference screenshots provided by operator (shadcn default style, neutral palette). ## Desktop layout (two-column divs, NO full-width stacking) - **Left column, 2/3 width**: upload area (shadcn Card + dashed dropzone: drag & drop + click-to-browse), below it the file list (shadcn Table or Card list: filename, size, format, status badge, per-row remove) - **Right column, 1/3 width** (sticky top): actions card — upload existing signature file, select from stored signatures (dropdown/combobox, issue #29), options (visible/invisible PDF sig), and a **big primary button `Firmar`** pinned at card bottom (h-12+, full width) ## Ownership boundaries (parallel work in flight) - touch: `src/lib/components/{FileDrop,FileCard,SignButton,ResultCard,CertPicker}.svelte`, `app.css`, tailwind config, new `src/lib/components/ui/` (shadcn primitives) - do NOT touch: `src/lib/{sign,pkcs12,keystore,certs}.ts` logic files, `src/lib/stores.ts` signatures store (issue #29 owns it), `src/lib/mcp/` (issue #13 owns it), any `test/` files - components keep existing prop interfaces; visual-only refactor ## Acceptance - shadcn-svelte initialized (button, card, table, badge, dropdown, dialog, input, tooltip) - dark mode via CSS vars (shadcn convention) - desktop ≥1024px shows the 2/3+1/3 grid; mobile falls back to stacked - existing tests still green; add one component snapshot test per new primitive usage - no new heavy deps beyond shadcn-svelte + tailwind (already present)
Author
Owner

bullet: coder launched on branch issue/27-epic-shadcn-ui-redesign-2-3-dr (model nan/deepseek-v4-flash).

bullet: coder launched on branch `issue/27-epic-shadcn-ui-redesign-2-3-dr` (model `nan/deepseek-v4-flash`).
Author
Owner

Claimed — branch issue/27-epic-shadcn-ui-redesign-2-3-dr. Doing: shadcn-svelte init + 2/3 dropzone / 1/3 sticky actions grid in web/, visual-only, existing tests green.

Claimed — branch `issue/27-epic-shadcn-ui-redesign-2-3-dr`. Doing: shadcn-svelte init + 2/3 dropzone / 1/3 sticky actions grid in `web/`, visual-only, existing tests green.
Author
Owner

Plan — Issue #27: shadcn/ui redesign, 2/3 drop zone + 1/3 actions panel (desktop)

Restated goal

Restyle the sign flow of AutoFirma Web with shadcn-svelte so the desktop view is a real
two-column layout: a 2/3 column holding the drop zone (shadcn Card + dashed dropzone, drag&drop +
click-to-browse) and the selected-file list (shadcn Table rows: filename, size, format, status
badge, per-row remove), and a 1/3 sticky column holding the actions card (certificate/PKCS#12
upload + certificate selection, format options, and a big primary Firmar button, full width,
h-12+). Dark mode moves to the shadcn CSS-variable convention (.dark class + :root vars),
mobile (< 1024px) falls back to the current stacked flow. The refactor is visual-only: every
component keeps its existing props, and every existing test stays green.

"Done" = shadcn-svelte initialized in web/ (components.json + src/lib/components/ui/ with
button, card, table, badge, dropdown-menu, dialog, input, tooltip), web/src/app.css carries the
shadcn CSS vars for light + dark, App.svelte renders lg:grid-cols-3 with the left column
spanning 2 and the right column sticky, pnpm test + pnpm check + pnpm build all green, and
src/lib/components/ui/primitives.test.ts snapshots each primitive.

Scope

Will change (matches the issue's ownership list):

  • web/src/app.css — shadcn CSS variables + @custom-variant dark, keeping the existing
    ink-*/brand-* @theme tokens alive (components and tests still reference them).
  • web/src/app.html — tiny inline script setting html.dark from prefers-color-scheme
    (shadcn convention: class-based dark mode).
  • web/package.json, web/pnpm-lock.yaml, web/components.json — shadcn-svelte init output.
  • web/src/lib/utils.ts — shadcn cn() helper.
  • web/src/lib/components/ui/** — new shadcn primitives (button, card, table, badge, input,
    dropdown-menu, dialog, tooltip + their sub-parts).
  • web/src/lib/components/FileDrop.svelte — Card + dashed dropzone styling (same props).
  • web/src/lib/components/FileCard.svelte — one shadcn Table row: filename, size, format,
    status badge, remove button (same props).
  • web/src/lib/components/CertPicker.svelte — restyle only; #pkcs12-file, #pkcs12-pin and the
    native <select id="cert-picker"> stay, because App.test.ts asserts role=combobox,
    select.value and #cert-picker by id.
  • web/src/lib/components/BatchQueue.svelte — the actions card: big primary Firmar
    (h-12 w-full) pinned at the card bottom (same props).
  • web/src/lib/App.svelte — lg:grid-cols-3 (left lg:col-span-2, right lg:col-span-1
    lg:sticky lg:top-6), shadcn Card/Table/Badge/Button/DropdownMenu/Tooltip/Dialog in the shell.
  • web/src/lib/components/ui/primitives.test.ts — new snapshot test per primitive usage.

Will NOT touch (explicit):

  • web/src/lib/{sign,pkcs12,keystore,certs}.ts, web/src/lib/verify/**, web/src/lib/batch.ts,
    web/src/lib/i18n.ts (copy keys are already sufficient — no new copy needed).
  • web/src/lib/stores.ts — does not exist in this tree; issue #29 owns it. No stored-signature
    picker is built here (its data source is missing).
  • web/src/lib/mcp/** — not present, untouched.
  • Everything under web/test/** and every existing *.test.ts (App.test.ts, batch.test.ts,
    crypto tests). No test is edited, skipped or weakened.
  • decompiled/**, original/**, extracted/**, docs/**.

Ordered tasks

# Task Verify
1 shadcn-svelte init in web/ (neutral base, $lib aliases, existing src/app.css) test -f web/components.json && grep -c bits-ui web/package.json
2 Add primitives: button card table badge input dropdown-menu dialog tooltip ls web/src/lib/components/ui
3 Restore/keep ink-* + brand-* @theme tokens; add .dark bootstrap in app.html grep -n 'color-ink-900|\.dark' web/src/app.css web/src/app.html
4 FileDrop.svelte → Card + dashed dropzone cd web && pnpm vitest run src/lib/App.test.ts
5 FileCard.svelte → shadcn Table row + status badge cd web && pnpm vitest run
6 CertPicker.svelte restyle (ids + native select intact) cd web && pnpm vitest run src/lib/App.test.ts
7 BatchQueue.svelte → actions card, Firmar h-12 w-full pinned cd web && pnpm vitest run src/lib/batch.test.ts
8 App.svelte → 2/3+1/3 sticky grid cd web && pnpm vitest run && pnpm check
9 primitives.test.ts snapshots cd web && pnpm vitest run src/lib/components/ui
10 Gates + production build pnpm check && pnpm test && pnpm build
11 Report + commits git log --oneline bullet-develop..HEAD

Open questions → assumptions taken

  1. SignButton.svelte / ResultCard.svelte do not exist in this tree; the Firmar button and
    the result list live in BatchQueue.svelte, and src/lib/batch.test.ts mounts BatchQueue
    standalone and clicks Firmar + Descargar ZIP inside it. → Assumption: no split. The whole
    BatchQueue becomes the right-hand actions card with the primary button pinned at its bottom.
    Splitting it would have required editing an existing test, which is forbidden.
  2. src/lib/stores.ts (#29) and the stored-signature picker are not available. → Assumption: no
    stored-signature control is rendered (a disabled placeholder would be a stub). The select from stored signatures slot is the existing <select id="cert-picker"> in CertPicker.svelte, which
    #29 can extend. The dropdown-menu primitive is used for the real language switcher instead.
  3. Which container the primitives are used in. Assumption: dropdown-menu → language switcher;
    dialog + tooltip → the privacy note (short tooltip text, full text in the dialog); table →
    the selected-file list; badge → per-file status + the "pending #N" format chip.
  4. Dark mode. Convention is a .dark class, but the app currently follows
    prefers-color-scheme. Assumption: keep both — @custom-variant dark + a 3-line inline script
    in app.html that sets html.dark from the media query, so behaviour is unchanged.
  5. CLI vs hand-written primitives. Assumption: run the real shadcn-svelte CLI (network is up,
    git.eduard3v.com and registry.npmjs.org both reachable). Fallback if it fights the repo:
    hand-copy the shadcn source into src/lib/components/ui/ and add only bits-ui,
    clsx, tailwind-merge, tailwind-variants, tw-animate-css (the shadcn-svelte runtime set).

Risk

  • CLI overwrites app.css theme tokens (ink-50, brand-500, font-sans) → those classes are
    used across components; re-add the @theme block after init and re-run pnpm test.
  • Dependency/peer conflicts (Svelte 5.57 with bits-ui) → if install fails, pin the versions the
    registry resolves for Svelte 5 and re-run; worst case hand-write the primitives (fallback above).
  • DOM order changes break the input[type="file"] first-match helper in App.test.ts → keep the
    left column (with FileDrop) before the right column in the DOM.
  • Two role=combobox elements would break screen.getByRole('combobox') → dropdown-menu
    renders role=button, and CertPicker keeps the single native <select>.
  • A11y regressions from primitive markup → keep aria-*, for/id pairs and native elements
    (<select>, <input>, <fieldset>) for anything the tests or screen readers query.
# Plan — Issue #27: shadcn/ui redesign, 2/3 drop zone + 1/3 actions panel (desktop) ## Restated goal Restyle the **sign** flow of AutoFirma Web with shadcn-svelte so the desktop view is a real two-column layout: a 2/3 column holding the drop zone (shadcn Card + dashed dropzone, drag&drop + click-to-browse) and the selected-file list (shadcn Table rows: filename, size, format, status badge, per-row remove), and a 1/3 sticky column holding the actions card (certificate/PKCS#12 upload + certificate selection, format options, and a big primary `Firmar` button, full width, h-12+). Dark mode moves to the shadcn CSS-variable convention (`.dark` class + `:root` vars), mobile (< 1024px) falls back to the current stacked flow. The refactor is **visual-only**: every component keeps its existing props, and every existing test stays green. "Done" = shadcn-svelte initialized in `web/` (components.json + `src/lib/components/ui/` with button, card, table, badge, dropdown-menu, dialog, input, tooltip), `web/src/app.css` carries the shadcn CSS vars for light + dark, `App.svelte` renders `lg:grid-cols-3` with the left column spanning 2 and the right column sticky, `pnpm test` + `pnpm check` + `pnpm build` all green, and `src/lib/components/ui/primitives.test.ts` snapshots each primitive. ## Scope **Will change** (matches the issue's ownership list): - `web/src/app.css` — shadcn CSS variables + `@custom-variant dark`, keeping the existing `ink-*`/`brand-*` `@theme` tokens alive (components and tests still reference them). - `web/src/app.html` — tiny inline script setting `html.dark` from `prefers-color-scheme` (shadcn convention: class-based dark mode). - `web/package.json`, `web/pnpm-lock.yaml`, `web/components.json` — shadcn-svelte init output. - `web/src/lib/utils.ts` — shadcn `cn()` helper. - `web/src/lib/components/ui/**` — new shadcn primitives (button, card, table, badge, input, dropdown-menu, dialog, tooltip + their sub-parts). - `web/src/lib/components/FileDrop.svelte` — Card + dashed dropzone styling (same props). - `web/src/lib/components/FileCard.svelte` — one shadcn Table row: filename, size, format, status badge, remove button (same props). - `web/src/lib/components/CertPicker.svelte` — restyle only; `#pkcs12-file`, `#pkcs12-pin` and the native `<select id="cert-picker">` stay, because App.test.ts asserts `role=combobox`, `select.value` and `#cert-picker` by id. - `web/src/lib/components/BatchQueue.svelte` — the actions card: big primary `Firmar` (`h-12 w-full`) pinned at the card bottom (same props). - `web/src/lib/App.svelte` — `lg:grid-cols-3` (left `lg:col-span-2`, right `lg:col-span-1` `lg:sticky lg:top-6`), shadcn Card/Table/Badge/Button/DropdownMenu/Tooltip/Dialog in the shell. - `web/src/lib/components/ui/primitives.test.ts` — new snapshot test per primitive usage. **Will NOT touch** (explicit): - `web/src/lib/{sign,pkcs12,keystore,certs}.ts`, `web/src/lib/verify/**`, `web/src/lib/batch.ts`, `web/src/lib/i18n.ts` (copy keys are already sufficient — no new copy needed). - `web/src/lib/stores.ts` — **does not exist in this tree**; issue #29 owns it. No stored-signature picker is built here (its data source is missing). - `web/src/lib/mcp/**` — not present, untouched. - Everything under `web/test/**` and every existing `*.test.ts` (`App.test.ts`, `batch.test.ts`, crypto tests). No test is edited, skipped or weakened. - `decompiled/**`, `original/**`, `extracted/**`, `docs/**`. ## Ordered tasks | # | Task | Verify | |---|------|--------| | 1 | `shadcn-svelte init` in `web/` (neutral base, `$lib` aliases, existing `src/app.css`) | `test -f web/components.json && grep -c bits-ui web/package.json` | | 2 | Add primitives: button card table badge input dropdown-menu dialog tooltip | `ls web/src/lib/components/ui` | | 3 | Restore/keep `ink-*` + `brand-*` `@theme` tokens; add `.dark` bootstrap in `app.html` | `grep -n 'color-ink-900\|\.dark' web/src/app.css web/src/app.html` | | 4 | `FileDrop.svelte` → Card + dashed dropzone | `cd web && pnpm vitest run src/lib/App.test.ts` | | 5 | `FileCard.svelte` → shadcn Table row + status badge | `cd web && pnpm vitest run` | | 6 | `CertPicker.svelte` restyle (ids + native select intact) | `cd web && pnpm vitest run src/lib/App.test.ts` | | 7 | `BatchQueue.svelte` → actions card, `Firmar` `h-12 w-full` pinned | `cd web && pnpm vitest run src/lib/batch.test.ts` | | 8 | `App.svelte` → 2/3+1/3 sticky grid | `cd web && pnpm vitest run && pnpm check` | | 9 | `primitives.test.ts` snapshots | `cd web && pnpm vitest run src/lib/components/ui` | | 10 | Gates + production build | `pnpm check && pnpm test && pnpm build` | | 11 | Report + commits | `git log --oneline bullet-develop..HEAD` | ## Open questions → assumptions taken 1. **`SignButton.svelte` / `ResultCard.svelte` do not exist** in this tree; the `Firmar` button and the result list live in `BatchQueue.svelte`, and `src/lib/batch.test.ts` mounts `BatchQueue` standalone and clicks `Firmar` + `Descargar ZIP` inside it. → Assumption: **no split**. The whole `BatchQueue` becomes the right-hand actions card with the primary button pinned at its bottom. Splitting it would have required editing an existing test, which is forbidden. 2. **`src/lib/stores.ts` (#29) and the stored-signature picker are not available.** → Assumption: no stored-signature control is rendered (a disabled placeholder would be a stub). The `select from stored signatures` slot is the existing `<select id="cert-picker">` in `CertPicker.svelte`, which #29 can extend. The `dropdown-menu` primitive is used for the real language switcher instead. 3. **Which container the primitives are used in.** Assumption: `dropdown-menu` → language switcher; `dialog` + `tooltip` → the privacy note (short tooltip text, full text in the dialog); `table` → the selected-file list; `badge` → per-file status + the "pending #N" format chip. 4. **Dark mode.** Convention is a `.dark` class, but the app currently follows `prefers-color-scheme`. Assumption: keep both — `@custom-variant dark` + a 3-line inline script in `app.html` that sets `html.dark` from the media query, so behaviour is unchanged. 5. **CLI vs hand-written primitives.** Assumption: run the real `shadcn-svelte` CLI (network is up, `git.eduard3v.com` and `registry.npmjs.org` both reachable). Fallback if it fights the repo: hand-copy the shadcn source into `src/lib/components/ui/` and add only `bits-ui`, `clsx`, `tailwind-merge`, `tailwind-variants`, `tw-animate-css` (the shadcn-svelte runtime set). ## Risk - **CLI overwrites `app.css` theme tokens** (`ink-50`, `brand-500`, `font-sans`) → those classes are used across components; re-add the `@theme` block after init and re-run `pnpm test`. - **Dependency/peer conflicts** (Svelte 5.57 with `bits-ui`) → if install fails, pin the versions the registry resolves for Svelte 5 and re-run; worst case hand-write the primitives (fallback above). - **DOM order changes break the `input[type="file"]` first-match helper** in `App.test.ts` → keep the left column (with `FileDrop`) before the right column in the DOM. - **Two `role=combobox` elements** would break `screen.getByRole('combobox')` → `dropdown-menu` renders `role=button`, and `CertPicker` keeps the single native `<select>`. - **A11y regressions** from primitive markup → keep `aria-*`, `for`/`id` pairs and native elements (`<select>`, `<input>`, `<fieldset>`) for anything the tests or screen readers query.
Author
Owner

bullet: coder launched on branch issue/27-epic-shadcn-ui-redesign-2-3-dr (model nan/deepseek-v4-flash).

bullet: coder launched on branch `issue/27-epic-shadcn-ui-redesign-2-3-dr` (model `nan/deepseek-v4-flash`).
Author
Owner

bullet: coder session died — relaunched from committed state (branch issue/27-epic-shadcn-ui-redesign-2-3-dr).

bullet: coder session died — relaunched from committed state (branch `issue/27-epic-shadcn-ui-redesign-2-3-dr`).
Author
Owner

Claimed (relaunch after a dead session) — branch issue/27-epic-shadcn-ui-redesign-2-3-dr. The prior session's work is committed (6c37356, b3072ec, d8ced39, 5332ea3). Doing: close the remaining acceptance gap (ui/input has no test), re-verify the gates and a real-browser layout proof, then report.

Claimed (relaunch after a dead session) — branch `issue/27-epic-shadcn-ui-redesign-2-3-dr`. The prior session's work is committed (`6c37356`, `b3072ec`, `d8ced39`, `5332ea3`). Doing: close the remaining acceptance gap (`ui/input` has no test), re-verify the gates and a real-browser layout proof, then report.
Author
Owner

DONE — issue/27-epic-shadcn-ui-redesign-2-3-dr, 5 commits, tree clean, not pushed.

Commits: 6c37356 shadcn-svelte init + dark-mode CSS vars · b3072ec 2/3 drop zone + 1/3 sticky actions panel · d8ced39 primitive snapshot tests (operator-labelled WIP, content is a real deliverable) · 5332ea3 README layer docs · c0312f4 certificate-picker input coverage (this session).

Gates (all exit 0):

  • test -d decompiled → PASS
  • find decompiled -name '*.java' | grep -q . → PASS
  • git diff --check → clean; git status --short → clean
  • cd web && pnpm test → 11 files, 100 tests passed
  • cd web && pnpm check → 1059 files, 0 errors, 0 warnings
  • cd web && pnpm build → Wrote site to "build" (adapter-static)

Browser proof (Chromium vs pnpm preview of the build): 1280×900 → #panel-sign grid 354.656px ×3, children 733 px / 355 px (ratio 2.06), aside position: sticky, Firmar 48 px high × full column width; 390×844 → single 350 px column, aside stacked and static; colorScheme: dark → html.dark, body oklch(0.145 0 0); verify-tab regression + ES/EN toggle clean, tab.errors() empty.

Not done, needs a human call (report §"What a human must decide"): stored-signature combobox (needs #29's src/lib/stores.ts, absent), visible/invisible PAdES options (needs #11's engine — PAdES radio still says pendiente #11), and the actions column only mounts when ≥1 document is selected (pre-existing #5 design).

Flake, unrelated to this branch: pades.test.ts ECDSA P-256 failed once in a full-suite run, passes standalone and on re-run; no commit here touches pades.ts.

**DONE** — `issue/27-epic-shadcn-ui-redesign-2-3-dr`, 5 commits, tree clean, not pushed. Commits: `6c37356` shadcn-svelte init + dark-mode CSS vars · `b3072ec` 2/3 drop zone + 1/3 sticky actions panel · `d8ced39` primitive snapshot tests (operator-labelled WIP, content is a real deliverable) · `5332ea3` README layer docs · `c0312f4` certificate-picker input coverage (this session). Gates (all exit 0): - `test -d decompiled` → PASS - `find decompiled -name '*.java' | grep -q .` → PASS - `git diff --check` → clean; `git status --short` → clean - `cd web && pnpm test` → 11 files, 100 tests passed - `cd web && pnpm check` → 1059 files, 0 errors, 0 warnings - `cd web && pnpm build` → `Wrote site to "build"` (adapter-static) Browser proof (Chromium vs `pnpm preview` of the build): 1280×900 → `#panel-sign` grid `354.656px ×3`, children 733 px / 355 px (ratio 2.06), aside `position: sticky`, `Firmar` 48 px high × full column width; 390×844 → single 350 px column, aside stacked and `static`; `colorScheme: dark` → `html.dark`, body `oklch(0.145 0 0)`; verify-tab regression + ES/EN toggle clean, `tab.errors()` empty. Not done, needs a human call (report §"What a human must decide"): stored-signature combobox (needs #29's `src/lib/stores.ts`, absent), visible/invisible PAdES options (needs #11's engine — PAdES radio still says `pendiente #11`), and the actions column only mounts when ≥1 document is selected (pre-existing #5 design). Flake, unrelated to this branch: `pades.test.ts` ECDSA P-256 failed once in a full-suite run, passes standalone and on re-run; no commit here touches `pades.ts`.
Author
Owner

bullet: coder session died — relaunched from committed state (branch issue/27-epic-shadcn-ui-redesign-2-3-dr).

bullet: coder session died — relaunched from committed state (branch `issue/27-epic-shadcn-ui-redesign-2-3-dr`).
Author
Owner

bullet: implementation finished (DONE: — issue/27-epic-shadcn-ui-redesign-2-3-dr, 5 commits, tree clean, not pushed.) — moving to review.

bullet: implementation finished (DONE: — `issue/27-epic-shadcn-ui-redesign-2-3-dr`, 5 commits, tree clean, not pushed.) — moving to review.
Author
Owner

bullet: reviewer launched (model 9router/reviewer, independent of coder).

bullet: reviewer launched (model `9router/reviewer`, independent of coder).
Author
Owner

Claimed — branch issue/27-epic-shadcn-ui-redesign-2-3-dr. Doing: verify the shadcn redesign already committed on the branch (2/3 drop + 1/3 sticky actions), close the remaining primitive-snapshot gap, run tests/build + browser smoke.

Claimed — branch `issue/27-epic-shadcn-ui-redesign-2-3-dr`. Doing: verify the shadcn redesign already committed on the branch (2/3 drop + 1/3 sticky actions), close the remaining primitive-snapshot gap, run tests/build + browser smoke.
Author
Owner

Plan — issue #27 (shadcn/ui redesign: 2/3 drop zone + 1/3 actions panel)

Claimed — branch issue/27-epic-shadcn-ui-redesign-2-3-dr.

State on arrival (read this first)

The branch already carries five commits of this work (6c37356, b3072ec, d8ced39
"wip: paused by operator", 5332ea3, c0312f4), so the flow is largely built and the tree is
clean. My job is therefore verify → close the remaining acceptance gaps → gates → report,
not a rewrite. Current evidence:

  • web/src/lib/components/ui/{button,card,table,badge,dropdown-menu,dialog,input,tooltip} exist,
    ported shadcn-svelte style with data-slot attributes; web/components.json +
    web/src/lib/utils.ts (cn()) in place.
  • web/src/app.css carries the shadcn token pair in oklch (:root / .dark) with
    @custom-variant dark (&:is(.dark *)); web/src/app.html has the inline
    prefers-color-scheme → .dark bootstrap.
  • web/src/lib/App.svelte renders #panel-sign as grid lg:grid-cols-3, left Card at
    lg:col-span-2 (drop zone + file Table via FileCard), right <aside> at lg:col-span-1
    with lg:sticky lg:top-6 (CertPicker, format fieldset, BatchQueue). Below lg both stack.
  • web/src/lib/components/BatchQueue.svelte ends with the primary Firmar button
    (h-12 w-full), disabled while no signer/hint, with a tooltip carrying the blocking reason.
  • web/src/lib/components/ui/primitives.test.ts snapshots the primitives through their real
    consumers (table row, desktop grid, help dropdown + privacy dialog, tooltip, cert-picker input).
  • pnpm test → 11 files / 100 tests pass; pnpm build → static build OK.

Restated goal

Restyle the signing flow with shadcn-svelte primitives and the neutral default palette, laid out on
desktop (≥1024px) as a 2/3 documents column (dashed drop zone + file table with status badges and
per-row remove) next to a 1/3 sticky actions column (certificate loading, format choice, the queue
and the big Firmar button pinned at the card bottom). Dark mode via shadcn CSS vars. Mobile
stacks. Visual-only: no prop interface of an existing component changes, no crypto/store logic is
touched. Done = that layout observable in a browser at ≥1024px and stacked below it, primitives
initialized, dark vars live, existing + new tests green, pnpm build green.

Scope

Change (this session):

  • web/src/lib/components/ui/primitives.test.ts — one missing primitive-usage snapshot (the drop
    zone's Card, i.e. the card primitive through its real consumer FileDrop).
  • Only if the smoke run shows a defect in the layout: the offending component under
    web/src/lib/components/** or web/src/app.css.

Already-changed files I keep as-is (owned by this issue, reviewed by the fleet):

  • web/src/lib/App.svelte, web/src/lib/components/{FileDrop,FileCard,CertPicker,BatchQueue}.svelte,
    web/src/lib/components/ui/**, web/src/lib/utils.ts, web/src/app.{css,html},
    web/components.json, web/package.json + web/pnpm-lock.yaml, web/README.md.

Do not touch: web/src/lib/{sign,pkcs12,keystore,certs,x509,cms,xades,pades,batch,verify,der,asn1,c14n,zip,ooxml}.ts,
web/src/lib/stores.ts (does not exist yet — issue #29 owns it), web/src/lib/mcp/ (issue #13),
web/test/**, web/src/lib/App.test.ts, and any pre-existing test outside the primitive suite.
Never main/main, never push, never close the issue.

Ordered tasks

  1. Plan + claim comments on #27 (curl per comment-policy).
    Verify: HTTP 201 in the curl response.
  2. Baseline gates — cd web && pnpm test && pnpm build.
    Verify: 100+ tests pass, built in + Wrote site to "build".
  3. Browser smoke at ≥1024px — pnpm dev, open at 1280×800, assert #panel-sign computes to
    three columns with the left card spanning 2 and the actions <aside> sticky; screenshot light
    and dark (system preference emulation).
    Verify: two columns side by side (2/3 + 1/3), Firmar full width h-12 at the aside bottom.
  4. Add the missing Card usage snapshot (drop zone) to primitives.test.ts.
    Verify: pnpm test src/lib/components/ui/primitives.test.ts → green.
  5. Full gates — pnpm test, pnpm build, pnpm check, git diff --check, plus the
    bullet.yaml gates (test -d decompiled, find decompiled -name '*.java' | grep -q .).
    Verify: all exit 0.
  6. Commit + report — web: snapshot the drop-zone card primitive (Refs #27); write
    .bullet/meta/issue-27.report.md; post the Done comment.

Open questions (assumptions I proceed on)

  1. The layout paragraph also names upload existing signature file and visible/invisible PDF sig
    in the actions card. Neither has any backing state in the app (no co-sign flow, PDF visible
    signature options belong to #11) and the acceptance list does not require them, so I am not
    inventing placeholder UI
    — no fake/no-op controls. Recorded in the report as a human decision.
  2. Select from stored signatures (dropdown/combobox, issue #29) — #29 owns the store
    (web/src/lib/stores.ts absent). Out of scope; the certificate list in CertPicker stays a
    native <select>.
  3. SignButton.svelte / ResultCard.svelte from the ownership list do not exist; the button lives
    in BatchQueue.svelte and results in BatchQueue/VerifyReport. Treated as illustrative names.
  4. The "wip: paused by operator" commit is kept (history is never rewritten).

Risk

  • Snapshot brittleness: primitives.test.ts uses an inline snapshot; adding one more is local and
    deterministic (jsdom, no clock/random in FileDrop). Fallback: assert data-slot="card" +
    dashed classes instead of a full snapshot.
  • Browser smoke may need a dev server on a free port; fallback is pnpm preview on the built
    output, and if no browser control is available, the jsdom layout assertions stand with a stated
    visual-proof limit.
# Plan — issue #27 (shadcn/ui redesign: 2/3 drop zone + 1/3 actions panel) Claimed — branch `issue/27-epic-shadcn-ui-redesign-2-3-dr`. ## State on arrival (read this first) The branch already carries five commits of this work (`6c37356`, `b3072ec`, `d8ced39` "wip: paused by operator", `5332ea3`, `c0312f4`), so the flow is largely built and the tree is clean. My job is therefore **verify → close the remaining acceptance gaps → gates → report**, not a rewrite. Current evidence: - `web/src/lib/components/ui/{button,card,table,badge,dropdown-menu,dialog,input,tooltip}` exist, ported shadcn-svelte style with `data-slot` attributes; `web/components.json` + `web/src/lib/utils.ts` (`cn()`) in place. - `web/src/app.css` carries the shadcn token pair in oklch (`:root` / `.dark`) with `@custom-variant dark (&:is(.dark *))`; `web/src/app.html` has the inline `prefers-color-scheme` → `.dark` bootstrap. - `web/src/lib/App.svelte` renders `#panel-sign` as `grid lg:grid-cols-3`, left `Card` at `lg:col-span-2` (drop zone + file `Table` via `FileCard`), right `<aside>` at `lg:col-span-1` with `lg:sticky lg:top-6` (CertPicker, format fieldset, BatchQueue). Below `lg` both stack. - `web/src/lib/components/BatchQueue.svelte` ends with the primary `Firmar` button (`h-12 w-full`), disabled while no signer/hint, with a tooltip carrying the blocking reason. - `web/src/lib/components/ui/primitives.test.ts` snapshots the primitives through their real consumers (table row, desktop grid, help dropdown + privacy dialog, tooltip, cert-picker input). - `pnpm test` → 11 files / 100 tests pass; `pnpm build` → static build OK. ## Restated goal Restyle the signing flow with shadcn-svelte primitives and the neutral default palette, laid out on desktop (≥1024px) as a 2/3 documents column (dashed drop zone + file table with status badges and per-row remove) next to a 1/3 sticky actions column (certificate loading, format choice, the queue and the big `Firmar` button pinned at the card bottom). Dark mode via shadcn CSS vars. Mobile stacks. Visual-only: no prop interface of an existing component changes, no crypto/store logic is touched. **Done** = that layout observable in a browser at ≥1024px and stacked below it, primitives initialized, dark vars live, existing + new tests green, `pnpm build` green. ## Scope Change (this session): - `web/src/lib/components/ui/primitives.test.ts` — one missing primitive-usage snapshot (the drop zone's `Card`, i.e. the card primitive through its real consumer `FileDrop`). - Only if the smoke run shows a defect in the layout: the offending component under `web/src/lib/components/**` or `web/src/app.css`. Already-changed files I keep as-is (owned by this issue, reviewed by the fleet): - `web/src/lib/App.svelte`, `web/src/lib/components/{FileDrop,FileCard,CertPicker,BatchQueue}.svelte`, `web/src/lib/components/ui/**`, `web/src/lib/utils.ts`, `web/src/app.{css,html}`, `web/components.json`, `web/package.json` + `web/pnpm-lock.yaml`, `web/README.md`. Do **not** touch: `web/src/lib/{sign,pkcs12,keystore,certs,x509,cms,xades,pades,batch,verify,der,asn1,c14n,zip,ooxml}.ts`, `web/src/lib/stores.ts` (does not exist yet — issue #29 owns it), `web/src/lib/mcp/` (issue #13), `web/test/**`, `web/src/lib/App.test.ts`, and any pre-existing test outside the primitive suite. Never `main`/`main`, never push, never close the issue. ## Ordered tasks 1. **Plan + claim comments** on #27 (`curl` per comment-policy). Verify: HTTP 201 in the `curl` response. 2. **Baseline gates** — `cd web && pnpm test && pnpm build`. Verify: 100+ tests pass, `built in` + `Wrote site to "build"`. 3. **Browser smoke at ≥1024px** — `pnpm dev`, open at 1280×800, assert `#panel-sign` computes to three columns with the left card spanning 2 and the actions `<aside>` sticky; screenshot light and dark (system preference emulation). Verify: two columns side by side (2/3 + 1/3), `Firmar` full width `h-12` at the aside bottom. 4. **Add the missing `Card` usage snapshot** (drop zone) to `primitives.test.ts`. Verify: `pnpm test src/lib/components/ui/primitives.test.ts` → green. 5. **Full gates** — `pnpm test`, `pnpm build`, `pnpm check`, `git diff --check`, plus the `bullet.yaml` gates (`test -d decompiled`, `find decompiled -name '*.java' | grep -q .`). Verify: all exit 0. 6. **Commit + report** — `web: snapshot the drop-zone card primitive (Refs #27)`; write `.bullet/meta/issue-27.report.md`; post the Done comment. ## Open questions (assumptions I proceed on) 1. The layout paragraph also names *upload existing signature file* and *visible/invisible PDF sig* in the actions card. Neither has any backing state in the app (no co-sign flow, PDF visible signature options belong to #11) and the acceptance list does not require them, so I am **not inventing placeholder UI** — no fake/no-op controls. Recorded in the report as a human decision. 2. *Select from stored signatures (dropdown/combobox, issue #29)* — #29 owns the store (`web/src/lib/stores.ts` absent). Out of scope; the certificate list in `CertPicker` stays a native `<select>`. 3. `SignButton.svelte` / `ResultCard.svelte` from the ownership list do not exist; the button lives in `BatchQueue.svelte` and results in `BatchQueue`/`VerifyReport`. Treated as illustrative names. 4. The "wip: paused by operator" commit is kept (history is never rewritten). ## Risk - Snapshot brittleness: `primitives.test.ts` uses an inline snapshot; adding one more is local and deterministic (jsdom, no clock/random in `FileDrop`). Fallback: assert `data-slot="card"` + dashed classes instead of a full snapshot. - Browser smoke may need a dev server on a free port; fallback is `pnpm preview` on the built output, and if no browser control is available, the jsdom layout assertions stand with a stated visual-proof limit.
Author
Owner

REVIEW: FIXED 2 — findings: card primitive had no snapshot assertion → fixed 0cd1c71; dashed drop-zone card had no test → fixed 6a12ae2; UNFIXED: none

REVIEW: FIXED 2 — findings: card primitive had no snapshot assertion → fixed 0cd1c71; dashed drop-zone card had no test → fixed 6a12ae2; UNFIXED: none
Author
Owner

DONE — Refs #27 (branch issue/27-epic-shadcn-ui-redesign-2-3-dr, tree clean).

Commits: 6c37356 (shadcn primitives + cn + dark vars) · b3072ec (2/3 + 1/3 sticky layout) ·
d8ced39 (wip paused by operator) · 5332ea3 (README) · c0312f4 (input snapshot) ·
0cd1c71 + 6a12ae2 (card/FileDrop snapshot — a second fleet process committed these into the
worktree mid-session; content verified, nothing mangled).

Gates:

  • test -d decompiled → 0
  • find decompiled -name '*.java' | grep -q . → 0 (11487 files)
  • cd web && pnpm test → 0 — 11 files / 101 tests passed
  • cd web && pnpm check → 0 — 0 errors, 0 warnings
  • cd web && pnpm build → 0 — static build written
  • git diff --check → clean

Live Chromium evidence (1280x900, one PDF in the drop zone): #panel-sign = grid with
grid-template-columns: 354.656px x3; left Card 733px (2/3), right <aside> 355px sticky at the
same top; Firmar = h-12 48x323px full-width at the card bottom; at 820px the grid collapses to
one column (780px) and the aside goes static. Dark mode: prefers-color-scheme: dark flips
<html> to .dark with no reload, body bg oklch(0.145 0 0), card oklch(0.205 0 0).
Screenshots: /tmp/br-27-desktop-light.png, /tmp/br-27-desktop-dark.png.

Not implemented (human decision, not a fake control): "upload existing signature file" and
"visible/invisible PDF sig" options in the actions card have no backing state in the app (PAdES
options are #11) and are absent from the acceptance list; the stored-signatures combobox waits on
#29's store. CertPicker keeps the native <select> for container certificates. Full detail in
issue-27.report.md.

**DONE** — Refs #27 (branch `issue/27-epic-shadcn-ui-redesign-2-3-dr`, tree clean). Commits: `6c37356` (shadcn primitives + cn + dark vars) · `b3072ec` (2/3 + 1/3 sticky layout) · `d8ced39` (wip paused by operator) · `5332ea3` (README) · `c0312f4` (input snapshot) · `0cd1c71` + `6a12ae2` (card/FileDrop snapshot — a second fleet process committed these into the worktree mid-session; content verified, nothing mangled). Gates: - `test -d decompiled` → 0 - `find decompiled -name '*.java' | grep -q .` → 0 (11487 files) - `cd web && pnpm test` → 0 — 11 files / 101 tests passed - `cd web && pnpm check` → 0 — 0 errors, 0 warnings - `cd web && pnpm build` → 0 — static build written - `git diff --check` → clean Live Chromium evidence (1280x900, one PDF in the drop zone): `#panel-sign` = grid with `grid-template-columns: 354.656px x3`; left Card 733px (2/3), right `<aside>` 355px sticky at the same top; `Firmar` = `h-12` 48x323px full-width at the card bottom; at 820px the grid collapses to one column (780px) and the aside goes static. Dark mode: `prefers-color-scheme: dark` flips `<html>` to `.dark` with no reload, body bg `oklch(0.145 0 0)`, card `oklch(0.205 0 0)`. Screenshots: `/tmp/br-27-desktop-light.png`, `/tmp/br-27-desktop-dark.png`. Not implemented (human decision, not a fake control): "upload existing signature file" and "visible/invisible PDF sig" options in the actions card have no backing state in the app (PAdES options are #11) and are absent from the acceptance list; the stored-signatures combobox waits on #29's store. `CertPicker` keeps the native `<select>` for container certificates. Full detail in `issue-27.report.md`.
Author
Owner

References

image

image

# References ![image](/attachments/32a739cf-6060-4889-a850-0ff2f362b699) ![image](/attachments/6db2aaaf-117e-44ec-b928-4d48772f2e22)
121 KiB
370 KiB
Author
Owner

bullet: fixer launched (round 1/2).

bullet: fixer launched (round 1/2).
Author
Owner

FIXED: applied 0 — no unfixed finding at HEAD 6a12ae2 (identical to the reviewed head, verdict not stale); the two review findings already carry fix commits + regression tests and were re-proved here, so re-applying them would require rewriting the reviewer's commits (forbidden) or duplicating assertions. Proof — finding 7 0cd1c71 + finding 8 6a12ae2 (primitives.test.ts:79 data-slot === 'card'; :52-65 dashed drop-zone card): mutating the Card primitive's data-slot makes BOTH tests fail (expected 'cardMUTANT' to be 'card'; card null at the border-dashed assert) → assertions are discriminating. Tree restored, clean. UNFIXED: none — caveat only: intermediate commit 0cd1c71 is red standalone (FileDrop rendered without its import; repaired in 6a12ae2), unfixable without amend/rebase per hard-law §4; HEAD is green so only bisect granularity is affected. Checkers at HEAD: pnpm test 101/101 · pnpm check 1059 files 0 errors 0 warnings · pnpm build OK · gates test -d decompiled + find decompiled -name '*.java' | grep -q . exit 0 · git diff --check clean · git status --short empty. No new commits, not pushed. Report: .bullet/meta/issue-27.report.md.

FIXED: applied 0 — no unfixed finding at HEAD `6a12ae2` (identical to the reviewed head, verdict not stale); the two review findings already carry fix commits + regression tests and were re-proved here, so re-applying them would require rewriting the reviewer's commits (forbidden) or duplicating assertions. Proof — finding 7 `0cd1c71` + finding 8 `6a12ae2` (`primitives.test.ts:79` `data-slot === 'card'`; `:52-65` dashed drop-zone card): mutating the Card primitive's `data-slot` makes BOTH tests fail (`expected 'cardMUTANT' to be 'card'`; `card` null at the `border-dashed` assert) → assertions are discriminating. Tree restored, clean. UNFIXED: none — caveat only: intermediate commit `0cd1c71` is red standalone (FileDrop rendered without its import; repaired in `6a12ae2`), unfixable without amend/rebase per hard-law §4; HEAD is green so only bisect granularity is affected. Checkers at HEAD: `pnpm test` 101/101 · `pnpm check` 1059 files 0 errors 0 warnings · `pnpm build` OK · gates `test -d decompiled` + `find decompiled -name '*.java' | grep -q .` exit 0 · `git diff --check` clean · `git status --short` empty. No new commits, not pushed. Report: `.bullet/meta/issue-27.report.md`.
Author
Owner

bullet: reviewer launched (model 9router/reviewer, independent of coder).

bullet: reviewer launched (model `9router/reviewer`, independent of coder).
Author
Owner

REVIEW: CLEAN — commit 6a12ae2: findings none

REVIEW: CLEAN — commit 6a12ae2: findings none
Author
Owner

bullet: review CLEAN — ready to publish.

bullet: review CLEAN — ready to publish.
Author
Owner

bullet: branch issue/27-epic-shadcn-ui-redesign-2-3-dr not on origin — cannot integrate.

bullet: branch `issue/27-epic-shadcn-ui-redesign-2-3-dr` not on origin — cannot integrate.
Author
Owner

bullet: PR #34 open → bullet-develop (auto-merge follows).

bullet: PR #34 open → `bullet-develop` (auto-merge follows).
Author
Owner

bullet: merge blocked (HTTP 405) — conciliation agent merges trunk work into bullet-develop; PR auto-merges next tick.

bullet: merge blocked (HTTP 405) — conciliation agent merges trunk work into `bullet-develop`; PR auto-merges next tick.
Author
Owner

bullet: merge conflicts with bullet-develop — conflict-solver agent owns the worktree until it pushes.

bullet: merge conflicts with `bullet-develop` — conflict-solver agent owns the worktree until it pushes.
Author
Owner

bullet: merge blocked (HTTP 405) — conciliation agent merges trunk work into bullet-develop; PR auto-merges next tick.

bullet: merge blocked (HTTP 405) — conciliation agent merges trunk work into `bullet-develop`; PR auto-merges next tick.
Author
Owner

Claimed (conflict-solver) — replaying issue/27-epic-shadcn-ui-redesign-2-3-dr onto bullet-develop. Doing: resolve the web/→root layout rename + content conflicts, run gates, merge, publish to bullet-develop.

Claimed (conflict-solver) — replaying `issue/27-epic-shadcn-ui-redesign-2-3-dr` onto `bullet-develop`. Doing: resolve the web/→root layout rename + content conflicts, run gates, merge, publish to bullet-develop.
Author
Owner

Claimed — branch bullet-develop. Doing: merge origin/main into bullet-develop for the rolling PR; verification only — origin/main is already an ancestor of bullet-develop, and the live conflict-solver session (i-27) owns this worktree mid-merge, so nothing is written.

Claimed — branch `bullet-develop`. Doing: merge `origin/main` into `bullet-develop` for the rolling PR; verification only — `origin/main` is already an ancestor of `bullet-develop`, and the live conflict-solver session (`i-27`) owns this worktree mid-merge, so nothing is written.
Author
Owner

RECONCILED: no trunk work to merge — origin/main f7dbab8 is already an ancestor of bullet-develop a5c609a (git rev-list --count origin/main ^origin/bullet-develop = 0; git merge-tree HEAD origin/main = HEAD tree 7161703a; git merge origin/main = "Already up to date."), so no commit/ref write/push; rolling PR #30 is mergeable: true; the 405 was PR #34 (issue/27 branch) conflicting with bullet-develop, owned by live conflict-solver i-27; gates green (test -d decompiled 0, find decompiled -name "*.java" | grep -q . 0, git diff --check origin/main origin/bullet-develop 0).

RECONCILED: no trunk work to merge — `origin/main` f7dbab8 is already an ancestor of `bullet-develop` a5c609a (`git rev-list --count origin/main ^origin/bullet-develop` = 0; `git merge-tree HEAD origin/main` = HEAD tree 7161703a; `git merge origin/main` = "Already up to date."), so no commit/ref write/push; rolling PR #30 is `mergeable: true`; the 405 was PR #34 (issue/27 branch) conflicting with `bullet-develop`, owned by live conflict-solver `i-27`; gates green (`test -d decompiled` 0, `find decompiled -name "*.java" | grep -q .` 0, `git diff --check origin/main origin/bullet-develop` 0).
Author
Owner

bullet: merge conflicts with bullet-develop — conflict-solver agent owns the worktree until it pushes.

bullet: merge conflicts with `bullet-develop` — conflict-solver agent owns the worktree until it pushes.
Author
Owner

bullet: merge blocked (HTTP 405) — conciliation agent merges trunk work into bullet-develop; PR auto-merges next tick.

bullet: merge blocked (HTTP 405) — conciliation agent merges trunk work into `bullet-develop`; PR auto-merges next tick.
Author
Owner

RECONCILED: no trunk work to merge — origin/main f7dbab8 is already an ancestor of origin/bullet-develop a5c609a (rev-list count 0, merge-tree = HEAD tree 7161703a); rolling PR #30 is mergeable=true; the HTTP 405 is PR #34 (issue/27 → bullet-develop, mergeable=false), whose conflict is owned by live conflict-solver session bullet-EduarD3V/AutoFirme-i-27 mid-merge of 6a12ae2 in this worktree, so no reset/commit/push; gates green (test -d decompiled 0, find decompiled -name *.java | grep -q . 0, git diff --check origin/main origin/bullet-develop 0).

RECONCILED: no trunk work to merge — origin/main f7dbab8 is already an ancestor of origin/bullet-develop a5c609a (rev-list count 0, merge-tree = HEAD tree 7161703a); rolling PR #30 is mergeable=true; the HTTP 405 is PR #34 (issue/27 → bullet-develop, mergeable=false), whose conflict is owned by live conflict-solver session bullet-EduarD3V/AutoFirme-i-27 mid-merge of 6a12ae2 in this worktree, so no reset/commit/push; gates green (test -d decompiled 0, find decompiled -name *.java | grep -q . 0, git diff --check origin/main origin/bullet-develop 0).
Author
Owner

bullet: merge conflicts with bullet-develop — conflict-solver agent owns the worktree until it pushes.

bullet: merge conflicts with `bullet-develop` — conflict-solver agent owns the worktree until it pushes.
Author
Owner

bullet: merge blocked (HTTP 405) — conciliation agent merges trunk work into bullet-develop; PR auto-merges next tick.

bullet: merge blocked (HTTP 405) — conciliation agent merges trunk work into `bullet-develop`; PR auto-merges next tick.
Author
Owner

Claimed — branch issue/27-epic-shadcn-ui-redesign-2-3-dr. Doing: replay onto bullet-develop, resolve shadcn/web conflicts, run gates, push.

Claimed — branch `issue/27-epic-shadcn-ui-redesign-2-3-dr`. Doing: replay onto bullet-develop, resolve shadcn/web conflicts, run gates, push.
Author
Owner

bullet: merge conflicts with bullet-develop — conflict-solver agent owns the worktree until it pushes.

bullet: merge conflicts with `bullet-develop` — conflict-solver agent owns the worktree until it pushes.
Author
Owner

bullet: merge blocked (HTTP 405) — conciliation agent merges trunk work into bullet-develop; PR auto-merges next tick.

bullet: merge blocked (HTTP 405) — conciliation agent merges trunk work into `bullet-develop`; PR auto-merges next tick.
Author
Owner

bullet: merged into bullet-develop — integration gates green.

bullet: merged into `bullet-develop` — integration gates green.
Author
Owner

bullet: PR #34 closed — work already merged into bullet-develop.

bullet: PR #34 closed — work already merged into `bullet-develop`.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
EduarD3V/AutoFirme#27
No description provided.