Plan download #43

Closed
opened 2026-10-06 23:13:49 +02:00 by EduarD3V · 4 comments
Owner

URL: http://192.168.31.41:5173/plans/UUID

I need you to add in part where the "enable", publish and all those buttons are a "Download" button.
this button will open a modal asking the user to select wich version of the plan to download and will download the zip with all the files of that version

URL: http://192.168.31.41:5173/plans/UUID I need you to add in part where the "enable", publish and all those buttons are a "Download" button. this button will open a modal asking the user to select wich version of the plan to download and will download the zip with all the files of that version
gotoi-agent added reference issue/43-plan-download 2026-10-07 07:37:08 +02:00
Collaborator

Claimed — branch issue/43-plan-download. Doing: add plan version download (middleware version-list + archive routes, plan-detail Download modal).

Claimed — branch `issue/43-plan-download`. Doing: add plan version download (middleware version-list + archive routes, plan-detail Download modal).
Collaborator

Issue #43 — Plan download: plan of record

Restated goal

The plan detail page (/plans/{UUID}) gains a Download button next to Enable/Publish/Duplicate.
It opens a modal listing the plan's versions; picking one and confirming downloads that version's
files as a single archive.

"Done" for the operator: on a repo-backed plan they click Download, see the version history
(each version with its provenance), pick one, click Download, and get a file on disk whose contents
are exactly that version's tree. Non-repo (steps) plans show no Download button — there is no tree to
archive.

Format deviation, stated up front: the issue says "zip". The platform already has exactly one
archive helper — archiveCommit() in middleware/src/git.ts, git archive --format=tar.gz — used
by the agent download route (/agent/:id/:token/archive/:planId, UC-AG-63). Adding a zip path means
either a new dependency or re-plumbing that helper, and HARD LAW 7 forbids the former. Decision:
ship .tar.gz
, named <planId>-<version>.tar.gz, reusing archiveCommit. A human can tar xzf it;
git archive also emits zip natively, so the fallback (below) is a one-word change if the operator
insists on zip.

Scope

Files changed

File Change
middleware/src/git.ts add resolveVersionCommit(planId, commit, dir?) (existence check via rev-parse <sha>^{commit})
middleware/src/routes/plans.ts GET /plans/:id/repo/versions?ref= (version list) and GET /plans/:id/versions/:version/archive (download)
middleware/tests/uc-mw-git-plans.test.ts tests for both routes + UC-MW-167 marker describe
dashboard/src/lib/api.ts api.plans.planVersions(id, ref?)
dashboard/src/routes/plans/[id]/+page.svelte Download button in the action row, version Dialog, state + effect load
dashboard/src/lib/usecases-frontend.test.ts UC-FE-95 assertions on the page source
dashboard/src/lib/page-help.ts one line on the /plans/ help entry
docs/use-cases/middleware/UC-MW-167-plan-version-download.md new UC
docs/use-cases/frontend/UC-FE-95-plan-download.md new UC
docs/use-cases/** (UC-FE-41, UC-MW-131, UC-MW-42, UC-MW-59, UC-OP-14) bidirectional related: + Related heading only

Explicitly NOT touched

  • middleware/src/db/schema.ts, middleware/drizzle/* — no schema change. Every version is
    already resolvable to a commit inside the bare repo at <plansDir>/<planId>.git.
  • dashboard/src/lib/types.ts — no new interface on both sides, so the mirror gate is untouched.
    The version shape is declared frontend-locally (like RepoFile already is).
  • middleware/src/routes/agent-api.ts — the agent archive route keeps its shape (UC-AG-63).
  • plans/ — product templates, HARD LAW 6.
  • agent/ — the agent does not download plans.
  • middleware/src/app.ts — routes are registered domain-file-wise already; nothing to register.
  • No new dependency, no Blob/URL.createObjectURL in the dashboard, no <a download> plumbing
    in proxy.ts (the proxy already passes content-type/content-disposition through and drops
    only hop-by-hop headers).

UC decision

Two new UCs, because the behaviour is new on both sides of the wire and docs/use-cases/ is the
behavioural contract:

  • docs/use-cases/middleware/UC-MW-167-plan-version-download.md
    • Implementation: middleware/src/routes/plans.ts (GET /plans/:id/repo/versions,
      GET /plans/:id/versions/:version/archive), middleware/src/git.ts (archiveCommit,
      resolveVersionCommit).
    • Tests: middleware/tests/uc-mw-git-plans.test.ts (contains the UC-MW-167 literal).
    • Related: UC-MW-131, UC-MW-42, UC-MW-59, UC-OP-14.
  • docs/use-cases/frontend/UC-FE-95-plan-download.md
    • Implementation: dashboard/src/routes/plans/[id]/+page.svelte, dashboard/src/lib/api.ts.
    • Tests: dashboard/src/lib/usecases-frontend.test.ts (contains the UC-FE-95 literal).
    • Related: UC-FE-41, UC-MW-167.

ID availability verified at plan time: UC-MW-166 and UC-FE-94 are the current maxima.

Design

Version list — where versions come from

There is no version table. A version is a (version string, commit) pair, assembled from what the
stores already hold, newest first, de-duplicated by version string:

  1. stores.promotions.forPlan(planId) — { version, gitCommit, changeRequestId, approvedBy, approvedAt, target }
    (source: promotion).
  2. stores.changes.all() filtered to this plan with status === 'approved' — { targetVersion, gitCommit }
    (source: change).
  3. The plan's current version ↔ commit (source: current).
  4. plan.runBranch head — labelled by the current version when it equals it, otherwise
    branch (source: branch).

Each candidate commit is confirmed to exist in the bare repo (resolveVersionCommit, which runs
git rev-parse <sha>^{commit}); entries whose commit is absent are dropped, so the modal can only
list downloadable rows. The entry whose commit equals plan.commit is flagged current.

Response: { ref, commit, versions: [{ version, source, commit, target?, changeRequestId?, approvedBy?, at?, current }] }.

Download route

GET /plans/:id/versions/:version/archive

  • requirePlan(req, reply, id, 'read') → 404 for invisible plans.
  • plan.format !== 'repo' → 400 { error: 'plan is not repo format' }.
  • :version validated against /^[0-9A-Za-z._-]{1,64}$/ → 400 { error: 'invalid version' }.
  • Version → commit: same scan as the list, exact version match → 404 { error: 'version not found' }.
  • Bytes: archiveCommit(plan.id, commit, dir) → reply.type('application/gzip') with
    Content-Disposition: attachment; filename="<planId>-<version>.tar.gz".
  • GitError → 500 { error: ... } (existing convention in this file).

No user text ever reaches git: the commit is a SHA taken from the store, and :version is
regex-gated before it is even compared.

Dashboard

  • One Button variant="outline" class="min-h-11" labelled Download in the action row,
    rendered only for plan.format === 'repo'.
  • One Dialog.Root bind:open={downloadOpen} with a Select.Root of versions (label =
    version · source), a read-only note of the resolved commit, and a footer Download button.
  • Submit is a plain <a href="/api/plans/{id}/versions/{version}/archive" download>
    rendered through the existing Button href prop — native platform download, no fetch/Blob code,
    same-origin /api so hooks.server.ts auth applies and proxy.ts passes the attachment headers.
  • Versions are fetched on dialog open (one GET, versionBusy guard), not on page load.
  • motion-reduce: is implicit: reuse of the shared Button/Dialog primitives, which already
    carry their own motion-reduce: paths.

Ordered tasks (each with its verifying command)

  1. Write this plan. — test -s /home/eduardez/workspace/gotoi-wt/meta/issue-43.plan.md
  2. Post the Claim and Plan comments on issue #43. — python3 $FJ comments 43 shows both.
  3. middleware/src/git.ts: add resolveVersionCommit. — cd middleware && bun test tests/uc-mw-git-plans.test.ts (still green) ; commit.
  4. middleware/src/routes/plans.ts: add the two routes. — cd middleware && bun test tests/uc-mw-git-plans.test.ts ; commit.
  5. middleware/tests/uc-mw-git-plans.test.ts: list route 200 + shape, non-repo 400,
    bad version 400, unknown version 404, archive 200 + gzip magic + attachment filename,
    plus the UC-MW-167 marker block. — cd middleware && bun test ; commit.
  6. dashboard/src/lib/api.ts: api.plans.planVersions. — cd dashboard && bun run check ; commit.
  7. dashboard/src/routes/plans/[id]/+page.svelte: button + dialog + state + effect. —
    cd dashboard && bun run check && bun run test ; commit.
  8. dashboard/src/lib/usecases-frontend.test.ts + page-help.ts. — cd dashboard && bun run test ; commit.
  9. Author UC-MW-167, UC-FE-95, and the five bidirectional related: edits. —
    python3 docs/use-cases/_check.py ; commit.
  10. Full gate sweep (UC check, headers, type mirror, middleware tests, dashboard test+check,
    rg 'Showing lines'). — each command exits 0 ; commit any header bumps.
  11. Write /home/eduardez/workspace/gotoi-wt/meta/issue-43.report.md, post the Done comment.

Open questions (proceeding on the stated assumption)

  1. zip or tar.gz? Issue says zip. → tar.gz, reusing archiveCommit; no new dependency.
    Fallback if a human insists: change archiveCommit to --format=zip and the MIME/extension at
    the one call site (agent route keeps tar.gz by passing the format through).
  2. What is a "version"? Nothing stores a file-per-version mapping. → Promotions + approved
    change requests + the current plan version + the run-branch head, each resolved to a commit and
    existence-checked. A version that never reached a commit is not listed rather than listed broken.
  3. Live plant files (GET repo/files) vs archived bytes? The archive is the tree at that
    version's commit, including files the editor view deliberately omits (binary, >256 KB). →
    archive is the source of truth; this is a download, not an editor export.
  4. Which branch's history? → plan.runBranch || 'develop'; the query param ref lets the UI
    ask for a specific hosted branch later, with the same regex gate as /repo/files.
  5. Multi-tenant filter on promotions? promotions has no organizationId column. →
    tenancy is enforced where it already is: requirePlan sees only plans the caller may read.

Risk and fallbacks

Risk Fallback
UC checker: one-way related: between new UCs and existing ones edit both sides in the same commit; if it still resists, drop the new UC files and cite UC-MW-131/UC-FE-41 with the new behaviour added as a Story paragraph (boring path, noted in the report)
svelte-check: unbalanced tags from the new {#if}/Dialog block keep the dialog outside <Page> next to the existing ConfirmDialog blocks; bun run check before commit
git rev-parse on a bare repo with an unknown sha is a hard error resolveVersionCommit swallows the error and returns null; the route 404s
Dashboard proxy mangles the binary response it already drops only hop-by-hop headers; verify by curling /api/plans/<id>/versions/<v>/archive against a running middleware, else PARTIAL with the reason
No component/page test layer in the dashboard the vitest file asserts the page source contains the button label, the dialog, and the download href; a real click-through needs a running stack and is stated as a visual limit if unavailable
# Issue #43 — Plan download: plan of record ## Restated goal The plan detail page (`/plans/{UUID}`) gains a **Download** button next to Enable/Publish/Duplicate. It opens a modal listing the plan's versions; picking one and confirming downloads that version's files as a single archive. "Done" for the operator: on a repo-backed plan they click Download, see the version history (each version with its provenance), pick one, click Download, and get a file on disk whose contents are exactly that version's tree. Non-repo (steps) plans show no Download button — there is no tree to archive. **Format deviation, stated up front:** the issue says "zip". The platform already has exactly one archive helper — `archiveCommit()` in `middleware/src/git.ts`, `git archive --format=tar.gz` — used by the agent download route (`/agent/:id/:token/archive/:planId`, UC-AG-63). Adding a zip path means either a new dependency or re-plumbing that helper, and HARD LAW 7 forbids the former. **Decision: ship `.tar.gz`**, named `<planId>-<version>.tar.gz`, reusing `archiveCommit`. A human can `tar xzf` it; `git archive` also emits zip natively, so the fallback (below) is a one-word change if the operator insists on zip. ## Scope ### Files changed | File | Change | |---|---| | `middleware/src/git.ts` | add `resolveVersionCommit(planId, commit, dir?)` (existence check via `rev-parse <sha>^{commit}`) | | `middleware/src/routes/plans.ts` | `GET /plans/:id/repo/versions?ref=` (version list) and `GET /plans/:id/versions/:version/archive` (download) | | `middleware/tests/uc-mw-git-plans.test.ts` | tests for both routes + `UC-MW-167` marker describe | | `dashboard/src/lib/api.ts` | `api.plans.planVersions(id, ref?)` | | `dashboard/src/routes/plans/[id]/+page.svelte` | Download button in the action row, version Dialog, state + effect load | | `dashboard/src/lib/usecases-frontend.test.ts` | `UC-FE-95` assertions on the page source | | `dashboard/src/lib/page-help.ts` | one line on the `/plans/` help entry | | `docs/use-cases/middleware/UC-MW-167-plan-version-download.md` | new UC | | `docs/use-cases/frontend/UC-FE-95-plan-download.md` | new UC | | `docs/use-cases/**` (`UC-FE-41`, `UC-MW-131`, `UC-MW-42`, `UC-MW-59`, `UC-OP-14`) | bidirectional `related:` + Related heading only | ### Explicitly NOT touched - `middleware/src/db/schema.ts`, `middleware/drizzle/*` — **no schema change**. Every version is already resolvable to a commit inside the bare repo at `<plansDir>/<planId>.git`. - `dashboard/src/lib/types.ts` — no new interface on both sides, so the mirror gate is untouched. The version shape is declared frontend-locally (like `RepoFile` already is). - `middleware/src/routes/agent-api.ts` — the agent archive route keeps its shape (UC-AG-63). - `plans/` — product templates, HARD LAW 6. - `agent/` — the agent does not download plans. - `middleware/src/app.ts` — routes are registered domain-file-wise already; nothing to register. - No new dependency, no Blob/`URL.createObjectURL` in the dashboard, no `<a download>` plumbing in `proxy.ts` (the proxy already passes `content-type`/`content-disposition` through and drops only hop-by-hop headers). ## UC decision Two new UCs, because the behaviour is new on both sides of the wire and `docs/use-cases/` is the behavioural contract: - **`docs/use-cases/middleware/UC-MW-167-plan-version-download.md`** - Implementation: `middleware/src/routes/plans.ts` (`GET /plans/:id/repo/versions`, `GET /plans/:id/versions/:version/archive`), `middleware/src/git.ts` (`archiveCommit`, `resolveVersionCommit`). - Tests: `middleware/tests/uc-mw-git-plans.test.ts` (contains the `UC-MW-167` literal). - Related: `UC-MW-131`, `UC-MW-42`, `UC-MW-59`, `UC-OP-14`. - **`docs/use-cases/frontend/UC-FE-95-plan-download.md`** - Implementation: `dashboard/src/routes/plans/[id]/+page.svelte`, `dashboard/src/lib/api.ts`. - Tests: `dashboard/src/lib/usecases-frontend.test.ts` (contains the `UC-FE-95` literal). - Related: `UC-FE-41`, `UC-MW-167`. ID availability verified at plan time: `UC-MW-166` and `UC-FE-94` are the current maxima. ## Design ### Version list — where versions come from There is no version table. A version is a `(version string, commit)` pair, assembled from what the stores already hold, newest first, de-duplicated by version string: 1. `stores.promotions.forPlan(planId)` — `{ version, gitCommit, changeRequestId, approvedBy, approvedAt, target }` (source: `promotion`). 2. `stores.changes.all()` filtered to this plan with `status === 'approved'` — `{ targetVersion, gitCommit }` (source: `change`). 3. The plan's current `version` ↔ `commit` (source: `current`). 4. `plan.runBranch` head — labelled by the current version when it equals it, otherwise `branch` (source: `branch`). Each candidate commit is confirmed to exist in the bare repo (`resolveVersionCommit`, which runs `git rev-parse <sha>^{commit}`); entries whose commit is absent are dropped, so the modal can only list downloadable rows. The entry whose commit equals `plan.commit` is flagged `current`. Response: `{ ref, commit, versions: [{ version, source, commit, target?, changeRequestId?, approvedBy?, at?, current }] }`. ### Download route `GET /plans/:id/versions/:version/archive` - `requirePlan(req, reply, id, 'read')` → 404 for invisible plans. - `plan.format !== 'repo'` → `400 { error: 'plan is not repo format' }`. - `:version` validated against `/^[0-9A-Za-z._-]{1,64}$/` → `400 { error: 'invalid version' }`. - Version → commit: same scan as the list, exact version match → `404 { error: 'version not found' }`. - Bytes: `archiveCommit(plan.id, commit, dir)` → `reply.type('application/gzip')` with `Content-Disposition: attachment; filename="<planId>-<version>.tar.gz"`. - `GitError` → `500 { error: ... }` (existing convention in this file). No user text ever reaches git: the commit is a SHA taken from the store, and `:version` is regex-gated before it is even compared. ### Dashboard - One `Button variant="outline" class="min-h-11"` labelled **Download** in the action row, rendered only for `plan.format === 'repo'`. - One `Dialog.Root bind:open={downloadOpen}` with a `Select.Root` of versions (label = `version · source`), a read-only note of the resolved commit, and a footer Download button. - Submit is a plain `<a href="/api/plans/{id}/versions/{version}/archive" download>` rendered through the existing `Button href` prop — native platform download, no fetch/Blob code, same-origin `/api` so `hooks.server.ts` auth applies and `proxy.ts` passes the attachment headers. - Versions are fetched on dialog open (one `GET`, `versionBusy` guard), not on page load. - `motion-reduce:` is implicit: reuse of the shared `Button`/`Dialog` primitives, which already carry their own `motion-reduce:` paths. ## Ordered tasks (each with its verifying command) 1. Write this plan. — `test -s /home/eduardez/workspace/gotoi-wt/meta/issue-43.plan.md` 2. Post the Claim and Plan comments on issue #43. — `python3 $FJ comments 43` shows both. 3. `middleware/src/git.ts`: add `resolveVersionCommit`. — `cd middleware && bun test tests/uc-mw-git-plans.test.ts` (still green) ; commit. 4. `middleware/src/routes/plans.ts`: add the two routes. — `cd middleware && bun test tests/uc-mw-git-plans.test.ts` ; commit. 5. `middleware/tests/uc-mw-git-plans.test.ts`: list route 200 + shape, non-repo 400, bad version 400, unknown version 404, archive 200 + gzip magic + attachment filename, plus the `UC-MW-167` marker block. — `cd middleware && bun test` ; commit. 6. `dashboard/src/lib/api.ts`: `api.plans.planVersions`. — `cd dashboard && bun run check` ; commit. 7. `dashboard/src/routes/plans/[id]/+page.svelte`: button + dialog + state + effect. — `cd dashboard && bun run check && bun run test` ; commit. 8. `dashboard/src/lib/usecases-frontend.test.ts` + `page-help.ts`. — `cd dashboard && bun run test` ; commit. 9. Author `UC-MW-167`, `UC-FE-95`, and the five bidirectional `related:` edits. — `python3 docs/use-cases/_check.py` ; commit. 10. Full gate sweep (UC check, headers, type mirror, middleware tests, dashboard test+check, `rg 'Showing lines'`). — each command exits 0 ; commit any header bumps. 11. Write `/home/eduardez/workspace/gotoi-wt/meta/issue-43.report.md`, post the Done comment. ## Open questions (proceeding on the stated assumption) 1. **zip or tar.gz?** Issue says zip. → **tar.gz**, reusing `archiveCommit`; no new dependency. Fallback if a human insists: change `archiveCommit` to `--format=zip` and the MIME/extension at the one call site (agent route keeps tar.gz by passing the format through). 2. **What is a "version"?** Nothing stores a file-per-version mapping. → Promotions + approved change requests + the current plan version + the run-branch head, each resolved to a commit and existence-checked. A version that never reached a commit is not listed rather than listed broken. 3. **Live plant files (`GET repo/files`) vs archived bytes?** The archive is the tree at that version's commit, including files the editor view deliberately omits (binary, >256 KB). → archive is the source of truth; this is a *download*, not an editor export. 4. **Which branch's history?** → `plan.runBranch || 'develop'`; the query param `ref` lets the UI ask for a specific hosted branch later, with the same regex gate as `/repo/files`. 5. **Multi-tenant filter on promotions?** `promotions` has no `organizationId` column. → tenancy is enforced where it already is: `requirePlan` sees only plans the caller may read. ## Risk and fallbacks | Risk | Fallback | |---|---| | UC checker: one-way `related:` between new UCs and existing ones | edit both sides in the same commit; if it still resists, drop the new UC files and cite `UC-MW-131`/`UC-FE-41` with the new behaviour added as a Story paragraph (boring path, noted in the report) | | svelte-check: unbalanced tags from the new `{#if}`/Dialog block | keep the dialog outside `<Page>` next to the existing `ConfirmDialog` blocks; `bun run check` before commit | | `git rev-parse` on a bare repo with an unknown sha is a hard error | `resolveVersionCommit` swallows the error and returns `null`; the route 404s | | Dashboard proxy mangles the binary response | it already drops only hop-by-hop headers; verify by `curl`ing `/api/plans/<id>/versions/<v>/archive` against a running middleware, else `PARTIAL` with the reason | | No component/page test layer in the dashboard | the vitest file asserts the page **source** contains the button label, the dialog, and the download href; a real click-through needs a running stack and is stated as a visual limit if unavailable |
Collaborator

DONE — branch issue/43-plan-download, 9 commits, local only, not pushed.

Resumed on the single non-pre-existing red: UC-MW-167 a superseded version keeps its own commit and files. Diagnosis by driving the real endpoint: the route was correct (1.0.0 → echo "Git Plan", the pre-change tree; 1.0.1 → echo v2); the test asserted toContain('echo "Smoke"'), a literal that exists nowhere in the repo, its history, or the seeds (starterFiles() writes echo ${JSON.stringify(title)}). Fixed the assertion (ed9999f) by capturing the pre-change scripts/main.sh from /repo/files and comparing the archive to exactly that text. No production change was needed.

Commits (all local):

  • 4f10e05 middleware(git): resolve a version commit inside the plan bare repo
  • 228379a middleware(plans): list plan versions and download one as tar.gz
  • b846c20 dashboard(api): plan version list client
  • 7c39a56 dashboard(plans): Download button and version picker on plan detail
  • 06d7beb docs(uc): UC-MW-167 and UC-FE-95 for plan version download
  • b89b749 middleware(plans): keep superseded versions downloadable
  • df075aa docs(uc): renumber plan download frontend UC to UC-FE-96 (UC-FE-95 taken by issue/41)
  • ed9999f middleware(tests): UC-MW-167 archive assertion compares against the pre-change tree
  • ce3259b chore: drop incidental bun.lock re-resolution from the plan-download branch

Gates:

  • python3 docs/use-cases/_check.py → 0 (353 UCs conform)
  • python3 scripts/check-ai-headers.py → 0 (569 ok, 0 missing)
  • python3 scripts/check-type-mirror.py → 0
  • cd middleware && bun run test → RED: 551 pass / 19 fail, all pre-existing. 17 of 19 reproduce identically in a detached worktree at the branch base 5df33bc; the other 2 are run-to-run flaky (UC-MW-19, the known red named in the resume, plus one UC-MW-139 file whose failure count varies even at base). The changed file tests/uc-mw-git-plans.test.ts passes 30/30 serial, all six UC-MW-167 tests included. No failing file is touched by this branch; nothing skipped or silenced.
  • cd dashboard && bun run test → 0 (242 pass)
  • cd dashboard && bun run check → 0 errors, 7 pre-existing warnings
  • cd dashboard && bun run build → 0
  • cd agent && go test ./... && gofmt -l agent → 0 / empty (untouched)
  • rg -n 'Showing lines' → only the rule text in AGENTS.md / RELEASING_INSTRUCTIONS.md / docs/org-tenancy-plan.md, no real footers

Also dropped an incidental bun.lock re-resolution (lockfileVersion 2→1, no package.json change) that a prior bun run had picked up on the branch.

Known limitation left as-is: middleware full-suite has pre-existing infra-race failures (ERR_HTTP_HEADERS_SENT, 401 on Better Auth cookie routes) unrelated to this branch. Report: meta/issue-43.report.md.

Refs #43

DONE — branch `issue/43-plan-download`, 9 commits, local only, not pushed. Resumed on the single non-pre-existing red: `UC-MW-167 a superseded version keeps its own commit and files`. Diagnosis by driving the real endpoint: the route was **correct** (`1.0.0` → `echo "Git Plan"`, the pre-change tree; `1.0.1` → `echo v2`); the test asserted `toContain('echo "Smoke"')`, a literal that exists nowhere in the repo, its history, or the seeds (`starterFiles()` writes `echo ${JSON.stringify(title)}`). Fixed the assertion (`ed9999f`) by capturing the pre-change `scripts/main.sh` from `/repo/files` and comparing the archive to exactly that text. No production change was needed. Commits (all local): - `4f10e05` middleware(git): resolve a version commit inside the plan bare repo - `228379a` middleware(plans): list plan versions and download one as tar.gz - `b846c20` dashboard(api): plan version list client - `7c39a56` dashboard(plans): Download button and version picker on plan detail - `06d7beb` docs(uc): UC-MW-167 and UC-FE-95 for plan version download - `b89b749` middleware(plans): keep superseded versions downloadable - `df075aa` docs(uc): renumber plan download frontend UC to UC-FE-96 (UC-FE-95 taken by issue/41) - `ed9999f` middleware(tests): UC-MW-167 archive assertion compares against the pre-change tree - `ce3259b` chore: drop incidental bun.lock re-resolution from the plan-download branch Gates: - `python3 docs/use-cases/_check.py` → 0 (353 UCs conform) - `python3 scripts/check-ai-headers.py` → 0 (569 ok, 0 missing) - `python3 scripts/check-type-mirror.py` → 0 - `cd middleware && bun run test` → **RED: 551 pass / 19 fail, all pre-existing.** 17 of 19 reproduce identically in a detached worktree at the branch base `5df33bc`; the other 2 are run-to-run flaky (`UC-MW-19`, the known red named in the resume, plus one `UC-MW-139` file whose failure count varies even at base). The changed file `tests/uc-mw-git-plans.test.ts` passes 30/30 serial, all six UC-MW-167 tests included. No failing file is touched by this branch; nothing skipped or silenced. - `cd dashboard && bun run test` → 0 (242 pass) - `cd dashboard && bun run check` → 0 errors, 7 pre-existing warnings - `cd dashboard && bun run build` → 0 - `cd agent && go test ./... && gofmt -l agent` → 0 / empty (untouched) - `rg -n 'Showing lines'` → only the rule text in AGENTS.md / RELEASING_INSTRUCTIONS.md / docs/org-tenancy-plan.md, no real footers Also dropped an incidental `bun.lock` re-resolution (lockfileVersion 2→1, no package.json change) that a prior bun run had picked up on the branch. Known limitation left as-is: middleware full-suite has pre-existing infra-race failures (`ERR_HTTP_HEADERS_SENT`, `401` on Better Auth cookie routes) unrelated to this branch. Report: `meta/issue-43.report.md`. Refs #43
Collaborator

DONE — branch issue/43-plan-download, 11 commits, PR opened against agent-develop: #55 (the run never merges).

Gates: UC catalog 0 (UC-MW-168 + UC-FE-97 authored; renumbered from MW-167/FE-96 — both ids were taken by the #38 and #41 merges while this branch was in flight, rebased onto current agent-develop), ai-headers 0 (571 ok), type-mirror 0, middleware bun test green except the documented pre-existing red UC-MW-19 (plan survives a second buildApp), dashboard test 0 (243 pass), check 0, build 0. agent/ untouched.

Deliberate deviation: issue says zip — shipped tar.gz reusing the platform's single archive helper archiveCommit (UC-AG-63); one-word change if zip is required. Versions are derived (promotions, approved changes, plan state, plan_audit) — no schema change. Details on PR #55 and the thread's plan comment.

DONE — branch issue/43-plan-download, 11 commits, PR opened against agent-develop: https://git.eduard3v.com/EduarD3V/gotoi/pulls/55 (the run never merges). Gates: UC catalog 0 (UC-MW-168 + UC-FE-97 authored; renumbered from MW-167/FE-96 — both ids were taken by the #38 and #41 merges while this branch was in flight, rebased onto current agent-develop), ai-headers 0 (571 ok), type-mirror 0, middleware bun test green except the documented pre-existing red UC-MW-19 (plan survives a second buildApp), dashboard test 0 (243 pass), check 0, build 0. agent/ untouched. Deliberate deviation: issue says zip — shipped tar.gz reusing the platform's single archive helper archiveCommit (UC-AG-63); one-word change if zip is required. Versions are derived (promotions, approved changes, plan state, plan_audit) — no schema change. Details on PR #55 and the thread's plan comment.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
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/gotoi#43
No description provided.