Skip to content

docs(readme): rewrite README with badges, real inventory and a usage guide - #8

Merged
slipalison merged 21 commits into
jdi/pipeline-unificadafrom
jdi/readme
Jul 29, 2026
Merged

docs(readme): rewrite README with badges, real inventory and a usage guide#8
slipalison merged 21 commits into
jdi/pipeline-unificadafrom
jdi/readme

Conversation

@slipalison

Copy link
Copy Markdown
Owner

Phase readme shipped via JDI autonomous chain (/jdi-issue).

Source: pasted card — "Melhore o Readme.md do projeto, adicione as badges deixe bem explicado."

Verdict: APPROVED_WITH_WARNINGS (verify round 3) · Loop: 3 iterations, 0 auto-resets, 2 fix rounds
Base: targets jdi/pipeline-unificada (PR #7) because the pipeline badge points at pipeline.yml, which only exists there. Merge #7 first, then this collapses onto main.

What changed

Six badges (Pipeline, CodeQL, OpenSSF Scorecard, Sonar quality gate, Sonar coverage, Apache-2.0) — all verified HTTP 200, none citing a workflow file that doesn't exist.

The card asked for badges and clarity; the audit found the README was also factually wrong in nine places, so the phase fixed those too:

  • "Licenca: Projeto privado" on a public repo carrying an Apache 2.0 LICENSE
  • The translation feature — the project's namesake — was entirely absent from Funcionalidades and Stack
  • Component table listed 6 of 16 services; now complete (4 Manager / 3 Engine / 6 Access / 3 Utility)
  • Project tree showed one project; the solution has three (Core, app, tests)
  • BookDetailPage/BookDetailPageModel documented as existing — they don't; moved to a Roadmap section pointing at phase detalhe-livro
  • Build commands used solution-level -f <TFM>, which fails NETSDK1005
  • Data models omitted Settings, TranslationCache, BookTranslationJob
  • Structure cited gitignored .idea/; themes said light/dark but ThemeEngine ships Sepia too

New sections: Como usar (import → read → settings → translation, including the 1.6 GB GGUF download users hit before their first translation), security, tests, contributing/JDI, license.

Review caught three false claims I wrote

Round 1 came back BLOCKED. In writing the security, tests and CI sections I had converted rules from .claude/rules/csharp.md and the Semgrep ruleset into descriptions of what the code already does:

  1. Claimed EPUB extraction validates path escape and bounds size — it does not
  2. Claimed unit tests touch no disk and no real SQLite — several do
  3. Claimed pipeline.yml dispatches scorecard.yml — it dispatches 8 jobs, and scorecard has no workflow_call at all

All three fixed, plus a later round corrected the CI trigger table (SBOM was labelled "push only" but has its own Tuesday cron) and scoped the delete-model button claim to session state.

Security finding escalated out of this phase

Verifying claim #1 exposed a real gap, now registered as phase epub-zip-slip (D-2026-07-29-epub-zip-slip-1):

ReadingManager.cs:59-60 builds the output path from EPUB-supplied content and hands it to FileUtility.cs:31-32, which writes with no containment check and no size bound — untrusted input, violating .claude/rules/csharp.md §4.

Worse: the custom Semgrep rule meant to catch exactly this structurally cannot fire on it. The rule requires syntactic access to .FullName; the project extracts through VersOne.Epub and never touches ZipArchiveEntry. Proven with a 4-case probe — canonical patterns detected, the real call path not. The phase therefore locks two deliverables: the code fix and the rule fix, because shipping only the first leaves the defect invisible to CI.

Shipped with warnings

Nine open, none blocking. Notable: IsModelAvailable is a session flag so the delete-model button vanishes after restart despite 1.6 GB on disk; the settings model picker writes TranslationModelName that nothing consumes; model download is not resumable. All three recorded in .jdi/todos.md as a UI-promises-code-doesn't-honor cluster — the same defect class this phase spent three rounds purging from the README, but on screen.

Deferred to PR review

Badge rendering after merge · the subjective "bem explicado" judgment · SonarCloud dashboard values · screenshots (none exist yet).

https://claude.ai/code/session_01BSdgwqZVLeiZfYsGNQ4V9i

Add the offline EN->PT-BR translation capability (LLamaSharp local
inference, GGUF model download, hash-based translation cache, resumable
BookTranslationJob, translated EPUB export) to Funcionalidades, plus the
Windows-only caveat pointing at the llm-mobile phase.

Replace the vague "claro/escuro" theme claim with the real Light/Dark/Sepia
set delivered by ThemeEngine, drop the Bookmarks bullet (the feature has no
Manager surface nor UI yet), and pin real package versions in Stack.

Refs: D-2026-07-29-readme-1 (b), (i), D-2026-07-29-readme-3

Claude-Session: https://claude.ai/code/session_01BSdgwqZVLeiZfYsGNQ4V9i
The Componentes table showed 6 of the 16 services that actually exist.
Add the 10 missing ones (TranslationManager, SettingsManager,
TranslationEngine, ThemeEngine, SettingsAccess, TranslationCacheAccess,
ModelAccess, BookTranslationJobAccess, PromptUtility, HtmlUtility),
reusing the component descriptions from CLAUDE.md verbatim so the two
documents cannot drift.

Redraw the layer diagram with the Managers/Engines split and all three
utilities, state the closed call rules, and extend Casos de Uso with the
settings and translation flows.

Refs: D-2026-07-29-readme-1 (c)

Claude-Session: https://claude.ai/code/session_01BSdgwqZVLeiZfYsGNQ4V9i
The Estrutura do Projeto block described a single project with
Contracts/Business/Access/Models nested under src/TranslateReader, and
listed BookDetailPage.xaml / BookDetailPageModel.cs, which do not exist.
Replace it with the real tree: TranslateReader.Core (net10.0 library),
TranslateReader (MAUI app) and TranslateReader.Tests. Drop the gitignored
.idea/ entry and add the .github/.jdi folders that do exist.

Add a Roadmap section that marks every unbuilt item as planned and maps it
to its JDI phase slug, so BookDetailPage, bookmarks and mobile LLM support
are documented as future work instead of shipped features.

Refs: D-2026-07-29-readme-1 (d), (e), (h)

Claude-Session: https://claude.ai/code/session_01BSdgwqZVLeiZfYsGNQ4V9i
Settings, TranslationCache and BookTranslationJob were missing entirely.
Add them with the fields the ResourceAccess implementations actually
create, including the UNIQUE(BookId, ChapterHRef, OriginalHash) constraint
that makes the translation cache work and the LastCompletedChapterIndex
resume point, and note that Bookmark has no UI yet.

Refs: D-2026-07-29-readme-1 (g)

Claude-Session: https://claude.ai/code/session_01BSdgwqZVLeiZfYsGNQ4V9i
Solution-level "dotnet build -f <TFM>" fails with NETSDK1005 because
TranslateReader.Core and TranslateReader.Tests target plain net10.0.
Point every build/run command at the app csproj instead and explain why.

Add a Testes e Cobertura section with the real test command lines (the
same ones ci.yml runs) and the 90% rule for code after boundary 4285f25,
stating explicitly that the automated gate is planned in the
cobertura-e-ci phase and is not enforced today. Add a Contribuindo
section pointing at CLAUDE.md, the JDI workflow and the C# rules.

Refs: D-2026-07-29-readme-1 (f), D-2026-07-29-readme-4 (2), (3), D-6

Claude-Session: https://claude.ai/code/session_01BSdgwqZVLeiZfYsGNQ4V9i
"Licenca: Projeto privado" was false — the repository is public and ships
an Apache License 2.0 file. Replace it with the real license and a link.

Add a Seguranca section: the private reporting path from SECURITY.md, a
table of the eight scanners wired into pipeline.yml (each mapped to a
workflow file that exists), the supply-chain hardening rules (third-party
actions pinned by full commit SHA, least-privilege permissions,
harden-runner) and the untrusted-input boundaries the code enforces.

Refs: D-2026-07-29-readme-1 (a), D-2026-07-29-readme-4 (1), (4)

Claude-Session: https://claude.ai/code/session_01BSdgwqZVLeiZfYsGNQ4V9i
Pipeline, CodeQL, OpenSSF Scorecard, SonarCloud Quality Gate, SonarCloud
Coverage, License Apache 2.0 — build health, then security scanners, then
supply-chain score, then quality, then license. CodeQL gets its own badge
rather than being folded into Pipeline: codeql.yml also runs on a weekly
cron, outside the orchestrator graph.

Every Actions badge points at a workflow file that exists in
.github/workflows/. All six URLs verified resolvable (HTTP 200).

Refs: D-2026-07-29-readme-2

Claude-Session: https://claude.ai/code/session_01BSdgwqZVLeiZfYsGNQ4V9i
All 7 tasks completed, one commit each, single-writer sequential as the
plan required. Full DoD battery re-run from the repo root after the last
README commit: 10/10 auto-verifiable items pass, all six badge URLs
resolve (HTTP 200), test baseline unchanged (169 passed, 2 skipped).

Four deviations recorded in SUMMARY.md, the notable one being that the
badge resolvability probe had to switch from HEAD to GET: SonarCloud
answers 405 to HEAD on /api/project_badges/measure, so the plan's
"curl -sfI" failed for a reason unrelated to badge validity. The gate
stayed hard and still passes.

Claude-Session: https://claude.ai/code/session_01BSdgwqZVLeiZfYsGNQ4V9i
Review iteration 1 flagged three sentences that turned RULES (from
.claude/rules/csharp.md and the Semgrep ruleset) into DESCRIPTIONS of
behaviour the code does not have. All three are prose in the same file
and are one coherent change -- stop claiming things the repo does not
do -- so they ship as a single commit.

B-1 (security, the serious one): the Seguranca section claimed the code
validates path escape and bounds decompressed size when extracting EPUB
zip entries. It does not. ReadingManager.cs:59-60 builds the output path
straight from EPUB-derived input and FileUtility.cs:31-32 writes it with
no containment check and no size bound; there is no ExtractToFile /
entry.FullName / Path.GetFullPath guard anywhere in src/. The section now
describes what actually exists: the normative rule in
.claude/rules/csharp.md section 4, and the four custom Semgrep rules in
.semgrep/dotnet-security.yml framed explicitly as CI DETECTION rules, not
runtime defenses. The real code gap is recorded in .jdi/todos.md.

B-2 (tests): "isolados: sem rede, sem disco e sem SQLite real" was false
on two of three clauses -- FileUtilityTests, ModelAccessTests,
ParsingEngineTests and HybridWebViewContractTests touch real disk, and
InMemoryDatabase.cs:19 opens a real Microsoft.Data.Sqlite connection. Now
describes the suite as measured (171 tests, 169 passing, 2 skipped for a
missing GGUF model; in-memory SQLite and temp-dir IO where the unit under
test is the resource access itself) and attributes the isolation rule to
.claude/rules/csharp.md section 6 as a convention for NEW code.

B-3 (pipeline topology): the table sat under "pipeline.yml dispatches the
reusable workflows below" and included scorecard.yml, which pipeline.yml
never dispatches and which has no workflow_call at all. The table now
lists the 8 jobs pipeline.yml really dispatches, with their real triggers
(dependency-review on PR only, sbom on push only), and scorecard.yml plus
release.yml moved to a separate table of independent workflows with the
reason each stays out.

W-1: the Android build line failed NETSDK1005 on a machine without an
Android SDK, because TranslateReader.csproj:7 only adds the android TFM
when one is detected. The line now carries that precondition, a dedicated
callout explains it, and the pre-existing solution-level NETSDK1005
callout is relabelled so a reader hitting the Android error is no longer
sent to the wrong explanation. Adds the msbuild -getProperty command to
list the TFMs actually available on the current machine.

Every retained sentence in the touched sections was re-verified against
the repository before commit. DoD 10/10, badges 6/6 GET 200, no accented
characters, dotnet test 169 passed / 2 skipped.

Claude-Session: https://claude.ai/code/session_01BSdgwqZVLeiZfYsGNQ4V9i
SUMMARY.md gains a "Fix round 1" section documenting iteration 2: for each
of the three blockers, what the README falsely claimed, the file:line
evidence that disproved it, and what the text says now. Also records the
common root cause (iteration 1 converted rules from .claude/rules/csharp.md
and the Semgrep ruleset into descriptions of existing behaviour), the W-1
fix, the full validation battery, and the REVIEW warnings deliberately left
untouched.

todos.md gains an entry for the finding B-1 exposed: EPUB image extraction
has no path containment and no decompressed-size bound, which
.claude/rules/csharp.md section 4 requires. Evidence is ReadingManager.cs:59-60
plus FileUtility.cs:31-32, with the grep results showing no guard exists
anywhere in src/. Notes that the translatereader-zip-slip Semgrep rule does
not match this call site -- it patterns on Path.Combine($DEST, $ENTRY.FullName)
while the real code goes through an intermediate variable from the
VersOne.Epub API -- so CI gives false confidence here. Candidate for a
hardening phase.

Claude-Session: https://claude.ai/code/session_01BSdgwqZVLeiZfYsGNQ4V9i
W-10: the Disparo column noted an own weekly cron only on the CodeQL row,
implying the other jobs had none, and called SBOM "somente push" while it
also runs on its own Tuesday cron. Read the on: block of all 8 reusable
workflows and made the column uniformly accurate: codeql (Mon 07:26 UTC),
semgrep (Mon 06:45), sca (Wed 05:50), secret-scan (Sun 04:15) and sbom
(Tue 03:20) declare schedule + workflow_dispatch besides workflow_call;
ci, sonarqube and dependency-review declare workflow_call only.

W-11: re-admit as its own sentence the claim that every book-derived value
is encoded before reaching JavaScript. All 10 EvaluateJavaScriptAsync call
sites in ReaderPage.xaml.cs were audited: chapter HTML, chunks and HRef go
through JsStr (:486, JsonSerializer.Serialize), translated paragraphs
arrive pre-serialized (:305-306), and the rest are constant scripts and
internal function-name literals. The Semgrep rule sits at WARNING because
the pattern cannot prove the two sites that bypass the helper - a detector
limit, not a code hole.

Claude-Session: https://claude.ai/code/session_01BSdgwqZVLeiZfYsGNQ4V9i
Round-2 judgement: the README was precise enough to understand and build the
project but never taught anyone to use the app, and in particular never said
that translation requires downloading a GGUF model through the app first.

Adds a usage section grounded in the source: import via the Importar toolbar
item and the platform EPUB filters (LibraryPageModel.ImportBookAsync); the
library grid with cover, progress bar and the Traduzir livro / Excluir context
menu (LibraryPage.xaml); reader settings - theme, scroll vs paginated, font and
spacing, source/target language - applied live and saved on panel close
(SettingsOverlay, ReaderPage.xaml.cs OnSettingsCloseRequested); reading position
saved on disappear and restored on open (ReaderPageModel.InitializeAsync);
and the translation flow - automatic download of gemma-2-2b-it-Q4_K_M.gguf
(TranslationManager.DefaultModel), visible-paragraph translation via the Aa
button which is paginated-mode only, resumable full-book jobs producing a new
EPUB, and the SHA-256 translation cache. Repeats the Windows-only inference
caveat from phase llm-mobile.

Claude-Session: https://claude.ai/code/session_01BSdgwqZVLeiZfYsGNQ4V9i
Appends a Fix round 2 section covering the autonomous warning-fix pass:
W-10 (CI trigger table), W-11 (WebView encoding claim) and the missing usage
section. Each entry states the warning, the fix, and the file:line evidence
gathered before writing, plus the resulting commit hashes and the validation
run. Also records the two capabilities left undocumented on purpose because
the code does not back them.

Claude-Session: https://claude.ai/code/session_01BSdgwqZVLeiZfYsGNQ4V9i
Security finding escalated from the readme phase: EPUB extraction lacks
path containment and decompression bounds, and the Semgrep rule meant to
catch it structurally cannot match the real call path.

Claude-Session: https://claude.ai/code/session_01BSdgwqZVLeiZfYsGNQ4V9i
ReaderPageModel.IsModelAvailable is a session flag written only on
download/load, never a disk check, and the PageModel is transient — the
button hides after a restart even with the model on disk. Also corrects
the superseded Semgrep diagnosis in todos.md and records the dead model
picker as an adjacent UI/code finding.

Claude-Session: https://claude.ai/code/session_01BSdgwqZVLeiZfYsGNQ4V9i
@sonarqubecloud

Copy link
Copy Markdown

@slipalison
slipalison merged commit 2eb9632 into jdi/pipeline-unificada Jul 29, 2026
13 checks passed
@slipalison
slipalison deleted the jdi/readme branch July 29, 2026 17:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant