Developer-Dashboard

 view release on metacpan or  search on metacpan

doc/problem-report.txt  view on Meta::CPAN


Fresh Docker verification (service dev, 2026-09-30):
`d2 docker compose --project-name dev exec dev sh -c 'cd /work && prove -l t/25-d2-alias.t t/102-skillmanager-coverage.t t/264-pax-removal-contract.t t/14-coverage-closure-extra.t t/15-release-metadata.t'`
Result: PASS, 5 files / 5,574 tests. The three red runs used isolated source
archives at pre-fix refs, then overlaid only the regression tests from the fix
commits; failures were P21 assertions 5, 7–12; P22 assertions 275, 278–280;
and P23 assertions 1–7, 9–10. The current-source P23 CLI check used an isolated
HOME and confirmed the removed command is not dispatched.

Verification caveats (do not turn these into passes): the live dev container's
installed d2/dashboard reports 5.32 and its root HOME contains an old
`~/.developer-dashboard/cli/pax`; this stale installed state is not evidence
about the current source or the 5.30 image. The source-only check therefore
used `/work` with an isolated HOME. The last recorded post-push Scorecard is
8.0/10, with repository-governance actions still open as documented below.
Problem 20's earlier aggregate coverage cycle passed; the active Problem 12 and
32 edits introduced new uncovered paths, so the current full-tree coverage gate
is not green yet. Do not treat that historical Problem 20 result as covering
the current uncommitted tree.

Problem 20: Bring repository-wide Perl coverage to 100% (status: complete; verified 2026-10-03)
Description: The isolated Docker coverage gate passed all 257 test files / 22,259 tests and reported 100.0% statement, branch, condition, and subroutine coverage across `lib/`, with no stale uncoverable annotations.

Problem 26: Preserve full branch labels in `ps1` across all shells (master) (status: complete in release 5.37)
Description: `dashboard ps1` must display complete slash-containing branch names rather than only the final path component. When HEAD is detached at a commit referenced by `origin/<branch>`, display `<branch>` without the `origin/` prefix; if no orig...
Expected outcome: `foo/bar` displays as `foo/bar`; detached `origin/foo/bar` displays as `foo/bar`; an unmatched detached commit continues to display its abbreviated SHA.
Reproduction from `/tmp/capture-379.txt`: in the isolated project Docker service, check out `origin/master` detached and run `dashboard ps1`; the old output uses the commit SHA instead of `master`. Then create/check out `foo/bar` and run `dashboard p...
Root cause: the prompt resolver used `basename` for symbolic refs, which chopped nested branch names, and displayed every detached HEAD as a short SHA without checking local origin tracking refs.
Fix: retain the suffix after `refs/heads/`, recognize remote symbolic refs, and resolve detached commits against loose and packed `refs/remotes/origin/*` entries. The resolver is in the common Perl prompt renderer invoked by all shell adapters; no sh...
Verification: red-first Docker run of `t/74-prompt-coverage.t` failed the two original assertions before implementation (nested symbolic ref was reduced to `bar`; detached `origin/foo/bar` displayed `0123456`). A security review then added two more r...
Final coverage-gate audit (2026-10-01, exact tree in Docker dev): this audit belongs to the separate Problem 20 cycle and is recorded there; it is not part of the Problem 7/26 acceptance or release decision per the user's explicit direction. Problem ...

Problem 26 follow-up: retain `origin/` unless an equivalent local branch exists (master) (status: complete in release 5.38; committed below)
Description: `dashboard ps1` should show a remote branch as `origin/foo/bar` when no local `foo/bar` branch points to the same commit. Omit only the redundant `origin/` prefix when both refs resolve to the identical commit. Apply the rule to symbolic...
Expected outcome: remote-only or differing local refs render `origin/foo/bar`; an exact same-commit local `foo/bar` renders `foo/bar`; unrelated detached commits still render their abbreviated SHA.
Reproduction: Docker-run `prove -lv t/74-prompt-coverage.t`. Before the fix, a detached HEAD at loose `origin/foo/bar`, a packed origin ref, and a different-commit local `foo/bar` each incorrectly rendered `foo/bar` (three red assertions). The same-c...
Root cause: the shared prompt resolver discarded the remote name unconditionally for symbolic remote HEADs and detached origin matches; it did not compare the local branch object id.
Fix: compare the exact local `refs/heads/<branch>` commit against the remote origin ref, preserving `origin/` if absent or different. Read refs directly and reject symlinked paths; shell adapters continue to share the renderer.
Verification: red-first focused Docker run failed the three new origin/local-branch assertions before the fix. After implementation, `t/74-prompt-coverage.t` and `t/21-refactor-coverage.t` passed (2 files / 971 tests); the complete Docker suite passe...

Problem 26 follow-up delivery checklist:
[x] Reproduce the incorrect prefix behavior with red-first Docker regression tests and record the expected output, root cause, and reproduction steps.
[x] Compare the pre-fix behavior with the required same-commit-only prefix omission; implement the comparison for symbolic/detached HEAD and loose/packed refs.
[x] Review Git-ref reads for path traversal and symlink escape; reject symlinked ref paths and packed-ref files. No new shell execution or dependency was introduced.
[x] Run focused and full Docker tests, web security tests, the real `dashboard ps1` CLI scenario, static security scans, POD validation, and documentation synchronization.
[x] Update `Changes`, `FIXED_BUGS.md`, README/main POD, and this problem report; run `dzil clean`, align version 5.38 in `dist.ini` and all 75 library modules, and build the archive.
[x] Install the tarball in a blank Docker environment with `cpanm` and tests enabled; run the blank-environment integration flow; build the Docker image and verify its reported version is 5.38.
[x] Commit the verified Problem 26 follow-up. Push and post-push Scorecard are not performed in this cycle.

Problem 7/26 SDLC completion (2026-10-01): the complete Docker suite passed 206 files / 20,991 tests; focused Problem 7/26 regressions passed 3 files / 1,215 tests; the required web-security trio passed 3 files / 459 tests. README/POD synchronization...

Problem 20 resumed audit (2026-09-30, source commit f56aedc2):
The first full-gate attempt used root with DAC-bypass capabilities dropped while the checkout was mounted as ubuntu-owned; t/110 and t/111 could not create fixtures, so that run was invalid and was stopped. A clean root-owned clone of the same commit...

Resumed coverage iteration (2026-09-30): A non-root Ubuntu test run in the `dev` Docker service passed 204 files / 19,319 tests. `t/09` initially exposed a fixture hard-coded under `/tmp/user`; it now directs state into its temporary HOME. Iteration ...

Iteration 8 used that git-backed isolated clone, passed 204 files / 19,212 tests, and ran `t/139` plus the source-tree guardrails. The strict gate still fails: statement 99.9%, branch 99.6%, condition 99.3%, subroutine 99.9%, aggregate 99.7%. Remaini...

Coverage-gap reproduction exposed an additional bookmark crash: save `//example.test/path` as a bookmark and call `_legacy_app_response`; before the fix it died because `URI::_generic` has no `host` method. The expected result is an HTTP redirect pre...

Scorecard gate (2026-09-30, after pushed commit 93218224): status incomplete, 8.0/10. Live output is from `bash -ic "scorecard --repo=github.com/manif3station/developer-dashboard"`. All checks other than Branch-Protection, CII-Best-Practices, Code-Re...

Problem 25: Complete help and shell-completion coverage for internal CLI commands (status: original help catalog delivered; delegated CLI help regression fixed in 5.42)
Expected outcome: every shipped internal CLI command and each actionable subcommand supports `--help`, `-h`, and/or an explicit `help` form with actionable syntax, exits successfully without performing the command, and appears in relevant TAB complet...
Scope discovered: all 39 assets registered by `Developer::Dashboard::InternalCLI::helper_names()` under `share/private-cli/`, plus the direct switchboard `version` command. This includes direct helpers (`jq`, `yq`, `tomq`, `propq`, `iniq`, `csvq`, `x...
Nested action inventory verified against dispatch: `api` = `ls add rm`; `auth` = `add-user list-users remove-user`; `collector` = `write-result status list job output inspect log run start stop restart`; `config` = `init show`; `docker` = `compose li...
Reproduction in isolated Docker: `d2 docker compose --project-name problem25 run --rm --no-deps dev ...`; use a temporary HOME and invoke `/work/bin/dashboard`. Observed `api --help` reports `Unknown option: help` and continues into API listing; `fil...
Root cause: help behavior was scattered across the top-level POD, `ask`, and `docker`, while many internal helpers only emitted usage on invalid input. Second-level completion was maintained as a separate partial hard-coded list, already out of sync ...

Red-first evidence: the initial Docker subprocess test failed because `api --help` emitted a Getopt warning and continued into the listing, file/path help exited with usage failures, nested action help executed or errored instead of rendering its syn...

Final-audit red/green evidence: the default-`api ls` regression first failed in Docker because root TAB omitted `--key`, `--output`, and `-o`, and root help omitted the long output spelling. The shared catalog change made these pass through both dire...

Final package-gate audit: the first clean-image `cpanm` run without `--notest` exposed that completing `dashboard workspace -` queried tmux before suggesting option flags; in an image without tmux this died after the contract assertions. A red-first ...

Final verification: after the final release-metadata guard, the full Docker suite passed 206 files / 20,788 tests and all six P25-focused files passed (6 files / 7,542 tests in the clean release clone). The required web security trio passed (3 files ...

Problem 25 task list:
[x] Enumerate internal helper assets, shared-dispatch actions, and current completion gaps; reproduce representative failures in an isolated Docker Compose run.
[x] T1: Add red-first contract tests and a shared help catalog for all 39 registered helpers, aliases, and the public `version` command; verify root help returns successfully before command bodies run.
[x] T2: Add per-action help for the nested action inventory, including the nested Docker development actions; verify each action help spelling and synopsis in subprocess integration tests.
[x] T3: Align action TAB candidates with help metadata and add option candidates for parser-backed command/action contexts. The option inventory was audited against each `GetOptionsFromArray` declaration; unsupported `cpan --dry-run` was removed from...
[x] T4 (focused and full): Run all P25 regressions, the full Docker suite, and required web security tests. Final runs passed 6 files / 7,542 focused tests, 206 files / 20,788 total tests, and 3 files / 459 web/security tests. Bash behavior and zsh h...
[x] T4 (final audit): Recheck every registered helper, alias, nested action, parser-declared option, direct `version` command, global-help target, default `api ls` flags, terminal nested-help completion, and concise overview. The workspace option/TAB...
[x] T5a: Synchronize README with main POD; document the CLI contract; update Changes and FIXED_BUGS.
[x] T5b: Run `dzil clean`, bump `dist.ini` and all 75 library modules to 5.35, and build the release archive. `t/15` verifies version synchronization and package contents.
[x] T5c: Install the tarball in a blank Docker image using `cpanm` without `--notest` (116 distributions); run the complete blank-environment integration flow successfully.
[x] T5d: Build the 5.35 Docker image with `d2 docker.images.build`; an isolated one-off run of that image returned `5.35`.
[x] T5e: Commit only Problem 25 files/version hunks; Problem 20 source/test changes remain uncommitted and separate.
Problem 20 remains separate; its existing worktree changes and incomplete aggregate coverage must not be included or claimed complete here.

Problem 12/25 follow-up regression cycle (2026-10-02)

Problem 12 follow-up: Resolve `dashboard workspace <skill>.<alias> -c` through
the skill Folder provider (status: complete; release 5.44)
Expected outcome: configured aliases and skill `lib/Folder.pm` aliases change
the workspace process into the returned directory before tmux session planning.
The behavior works for top-level, nested, and deeper dotted skill names;
configured aliases win collisions with Folder.pm methods, and real resolver
errors remain visible.
Reproduction: in the isolated Compose `dev` container, create skills
`bar`, `bar.baz`, and `bar.baz.qux`, each with `lib/Folder.pm`, a `__list__`
method, and an alias method returning an existing directory. Run
`dashboard workspace bar.root -c`, `dashboard workspace bar.baz.nested -c`,
and `dashboard workspace bar.baz.qux.leaf -c` with tmux stubbed. Before the fix,
`registered_workspace_dir` returned an empty path for Folder.pm aliases and the
CLI rejected the `-c` request as unregistered.
Root cause: the workspace resolver loaded JSON configuration into
PathRegistry but did not invoke the existing secured skill Folder.pm resolver.
Red-first evidence: the new `t/91-cli-ticket-coverage.t` assertions failed for
top-level and nested Folder aliases (`got: ''`), and the public CLI test
reported that the alias was not registered. After implementation, these cases,
the config-first collision guard, and a public CLI invocation verified that the
tmux `new-session -c` target is the deepest alias directory.

Problem 25 follow-up: Preserve native help for delegated CLIs (status: complete;
release 5.44)
Expected outcome: `dashboard of grep --help`, `dashboard docker compose
config --help`, and `dashboard docker compose help` reach grep or Docker
Compose. The Dashboard wrapper still documents itself via
`dashboard docker compose --help` or `dashboard help docker compose`.

doc/problem-report.txt  view on Meta::CPAN

Security review for this change: the command still passes argument vectors to
`system` and does not compose a shell string; config-derived service names only
select existing runtime-root paths. No new dependencies, SQL, HTTP routes,
credentials, or authentication behavior were introduced. The fresh full Docker
gate passed 258 files / 22,609 tests at 100.0% statement, branch, condition,
and subroutine coverage (45,787 detail rows and no stale uncoverable
annotations). The required focused web-security trio passed 459 tests.
`perlsec` was reviewed from the container's `perlsec.pod` with `pod2text`
because `perldoc` has no formatter. The 5.65 archive passed CPANTS kwalitee
(100%, 7/7 assertions) and POD syntax (348 source files, 355 assertions).
`dzil build` produced `Developer-Dashboard-5.65.tar.gz`; its image reported
version 5.65 in a one-off Compose run. A blank-environment container installed
the archive with `cpanm` without `--notest` and passed the full integration
script. Required security searches found no Problem 40 shell-string execution
or production use of a forbidden library; broad matches were existing audit
strings and test fixtures. Devel::Cover warnings for temporary generated
fixtures removed during tests remain visible, while the coverage gate exits
successfully with all four metrics at 100.0%.

Problem 41: Remove Docker from built-in indicators (status: done, version 5.67)

Expected outcome: core indicator refresh does not probe for the docker
executable and does not create a Docker status indicator. Docker status remains
available when the user explicitly configures a Docker collector. A previously
persisted core Docker record is removed, while customized and collector-owned
records named docker are preserved.

Root cause: refresh_core_indicators() called command_in_path('docker') and
persisted a Docker indicator at priority 20. A configured collector named
docker then shared that record, which made Docker appear first in the prompt.

Reproduction: run d2 ps1 without tmux indicator suppression. The old path
probed the Docker executable and created a whale indicator even in a runtime
without a Docker collector. In the Docker dev service, t/95 was changed first
to make the executable probe fatal; its red run exited at that probe. The test
also seeds the old built-in record and verifies migration cleanup while keeping
an explicitly configured collector-owned docker record.

Implementation removes the Docker probe and write from core refresh and adds
signature-based cleanup for the old core record only. Shared-lock cleanup
passes both focused Docker test files (1,042 assertions), preserving custom and
collector-owned statuses.
Three additional red assertions exposed missing writer-lock protection and
lock-failure reporting. Shared-lock cleanup now passes both focused Docker test
files (1,042 assertions), including layered/custom ownership preservation.
The first full run failed four tracked-document assertions because container
Git rejected the /work bind mount's ownership. A disposable test Compose file
sets safe.directory only inside the container. The affected integration asset
and indicator tests passed 491 assertions, and the full gate was restarted.

Final verification: all 258 Docker test files passed (22,645 tests); Devel::Cover
reported 100.0% statement, branch, condition, and subroutine coverage across
the library (45,841 detail rows, no stale uncoverable annotations). Its report
included missing-digest diagnostics for temporary generated helpers already
removed by their tests; the canonical gate exited successfully. The focused
web/security tests passed 459 assertions. Kwalitee, POD, and release metadata
passed 5,783 assertions, including 100% CPANTS kwalitee. The final 5.67 archive
excluded cover_db. The blank Docker environment installed the same 5.67 release
code through cpanm with tests enabled and passed the complete installed-runtime
integration runner. Perl's perlsec documentation was reviewed inside the
runtime container. No new executable, dependency, SQL, endpoint, credential,
or authentication surface was added.

Problem 42: Let skill environment values override home defaults (status: done, 5.68)

Expected outcome: matching values from a skill's `.env` or `.env.pl` override
home runtime values from `~/.d2` or `~/.developer-dashboard`. Deeper project
runtime layers keep final precedence. Non-skill environment behavior is
unchanged.

Root cause: SkillDispatcher loaded skill and skill-CLI files before loading
the whole runtime chain. The final runtime load replayed the home `.env` and
overwrote the skill's value.

Reproduction: in an isolated Docker dev container, create `foo/.env` with
`SKILL_WILL_OVERWRITE_THIS=I am foo`, `bar/.env` with
`SKILL_WILL_OVERWRITE_THIS=I am bar`, and
`~/.developer-dashboard/.env` with `SKILL_WILL_OVERWRITE_THIS=HOME`. Run
`d2 foo.bash -c` and `d2 bar.bash -c` with each command printing the variable.
Before the fix both print `HOME`; after the fix they print their own skill
value. Remove the home file and rerun, then set the key in a deeper project
runtime file and confirm that deeper value wins.

Red/green: the new skill dispatch assertion failed in Docker before the code
change (`got home-runtime`, expected `skill`). Focused skill and EnvLoader
tests pass after implementation, including home `.d2` plus
`.developer-dashboard` ordering and deeper project precedence. The full Docker
suite passed 258 files / 22,656 tests with 100.0% statement, branch, condition,
and subroutine coverage (45,874 detail rows; no stale uncoverable annotations).
The required web/security trio passed 459 tests. Devel::Cover emitted visible
missing-digest diagnostics for temporary fixtures removed during tests, and
existing negative-fixture tests print expected shell/archive diagnostics; the
run is not called warning-free. README and main POD remain synced. The required
security scans found no new forbidden library usage, sensitive information,
unsafe auth behavior, raw SQL, or missing security-header implementation;
perlsec was reviewed in the same runtime image. `dzil build` produced the sole
archive `Developer-Dashboard-5.68.tar.gz`, with no `cover_db` entry. CPANTS
kwalitee passed 7/7 checks at 100%, and POD syntax passed 348 source files / 355
assertions. The blank Perl 5.44 container installed the tarball using `cpanm`
without `--notest`, ran distribution tests, and completed the installed-runtime
integration script. `d2 docker.images.build` completed; a scoped run of its
image reported `d2 version` 5.68. No release upload was performed.

Problem 43: Keep Docker Compose skill env scoped to the selected service
(status: done in 5.71)

Expected outcome: when installed skills `foo` and `bar` each contribute a
Compose service and define the same variable in their skill `.env`,
`d2 docker compose up foo` uses foo's value and a later
`d2 docker compose up bar` uses bar's value. Operations without a selected
service continue to use env from all effective base services. Caller-exported
values keep their higher precedence under Problem 44.

Reproduction from `/tmp/capture-1476.txt`: create `foo/.env` with
`SKILL_WILL_OVERWRITE_THIS=I am foo` and `bar/.env` with
`SKILL_WILL_OVERWRITE_THIS=I am bar`; add a matching
`config/docker/<skill>/compose.yml` whose message interpolation reads that
key. Run `d2 docker compose up foo`, remove the home `.env`, then run
`d2 docker compose up bar`. Before the fix, bar's container printed
`I am foo` despite its own `.env` containing `I am bar`.



( run in 0.728 second using v1.01-cache-2.11-cpan-16aabcbfbcb )