Adversarial re-audit of the current (post-uplift) state found the plugin
internally consistent (no blocker/high issues). Two follow-ups:
README rewrite for clarity (209 -> 122 lines, ~halved):
- Reorder so a newcomer goes what-it-is -> install -> quickstart -> command
reference -> deeper notes, instead of hitting two dense design essays
before the command list.
- Lead with what it produces; add a 3-command teaser.
- Collapse the 'Dynamic workflow orchestration' and 'Untrusted code &
prompt injection' essays and the COCOMO note into short, plain sections at
the bottom; drop the internal 'Bash isn't a tool-lock' hedging and
per-defense enumeration (kept the load-bearing points: untrusted-code
threat model, secrets quarantine, COCOMO-is-not-a-timeline).
- Remove cross-section redundancy (build methods, read-only caveat,
scaffolder write-scope, dir convention each stated once now); gloss
strangler-fig/JOBOL inline.
Path nit from the audit: uplift now writes to modernized/<system>-uplifted/
(mirroring reimagine's -reimagined/) so the three build paths occupy disjoint
roots and status can't mis-detect an uplift copy as transform modules.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Code/security:
- extract-rules.js: guard null agent() verdicts in the verify + P0 loops
(a skipped/dead referee made {rule,v:null} survive .filter(Boolean) and
then crashed on v.injectionSuspected / v.every) — sibling scripts already
had the guard.
- topology viewer XSS: the map injector embedded untrusted JSON (node names
from filenames, etc.) into a <script> island unescaped — a name containing
</script> executed on open. Escape < > & in the injected data and add a CSP
to the template.
- Second-order injection: citation/identifier fields (source / cwe /
source_site / correctedSource) were interpolated UNFENCED into the verifier
prompts that are supposed to be the trust anchor. Fence them in
extract-rules, harden-scan, uplift-deltas.
uplift design (audit of the new feature):
- Working-copy model: copy the WHOLE solution to modernized/ once and edit in
place (relative project refs survive; result is a reviewable git diff) —
the incremental per-project copy broke multi-project builds.
- Dual-run honesty: reframed as 'if both runtimes run here' (net48 needs
Windows; JUnit/pytest don't multi-target); dummy-test gate now binds a real
SUT under both targets; per-stack harness notes.
- Tooling honesty: present/runnable/actually-ran distinction; never fold in a
tool that couldn't run; apiport/2to3 demoted; py2->3 removed from 'preserve'
examples.
- Delta classes: name the high-blast-radius landmines (JPMS strong
encapsulation, .NET trimming/AOT, ICU globalization, hosting/runtime-config,
analyzer/nullable) in the finder briefs + agent.
- Rewrite-vs-uplift signal: weigh by touched sites (siteCount), not delta-card
count; judgment-share demoted to secondary.
Docs/consistency: brief reads topology.json (not TOPOLOGY.html); README
'five commands'; credential-masking claim split (analysts mask+cite vs
code-writers substitute fakes); read-only/write-scope claims softened to
match enforcement (Bash retained -> discipline, not tool-lock); reimagine
nested blockers/pendingRuleIds; status splits transform vs reimagine markers;
portfolio enumeration basenames; plugin.json description updated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds a third build method alongside transform (cross-stack rewrite) and
reimagine (greenfield): uplift, for same-stack version bumps (.NET Framework
4.8 -> .NET 8, Spring Boot 2->3, Python 2->3) where the right move is to
PRESERVE the code and fix only the version deltas, not extract intent and
rewrite.
- commands/modernize-uplift.md: delta-catalog-driven, dual-target test harness
(one suite on both runtimes; baseline-on-old is the oracle), leaf-first build
graph ordering, minimal-diff discipline (architecture-critic flags gratuitous
divergence), and a 'this is a rewrite, use transform' escape hatch.
- agents/version-delta-analyst.md: finds the source->target breaking changes
that THIS code hits; drives the ecosystem migration tool (upgrade-assistant /
OpenRewrite / pyupgrade / ng update) and owns the residue; read-only.
- workflows/uplift-deltas.js: parallel finder per delta category, each verified
against the cited code so deltas that don't apply here are dropped.
- Wired into assess (recommended-pattern routing), brief (per-phase command +
leaf-first ordering), preflight (dual-run + tool readiness), status, README.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
COCOMO's constants encode human-team productivity; presenting its
person-months as how long an agentic modernization will take (or cost) is
a claim we should not make. Reframe COCOMO everywhere as a RELATIVE
complexity/scale index for ranking and sequencing systems only:
- assess: capture COCOMO as a complexity index; explicitly ignore scc's
'Estimated Schedule Effort' and cost-in-dollars; ASSESSMENT 'Effort
Estimation' section becomes 'Relative Scale' with a not-a-timeline note;
portfolio heat-map column renamed Complexity (COCOMO index).
- brief: phase plan uses relative T-shirt sizing, not person-months/weeks;
phases render as a dependency flowchart, not a gantt (gantt = calendar).
- portfolio-assess.js: field cocomoPm -> complexityIndex; return label
carries the not-a-duration caveat.
- README: 'A note on COCOMO' explains the index framing and points at
better intrinsic-complexity proxies.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Addresses automated security review of the workflow conversion:
- Agent-produced text (rule specs, finding descriptions, dedup lists) is
fenced as untrusted data when interpolated into downstream agent prompts,
with embedded fence markers stripped so the fence can't be escaped;
referees and judges are told to re-derive claims from the cited code.
- system/service/subdir names that land in filesystem paths inside prompts
are validated against a strict pattern — traversal-shaped values throw
before any agent spawns.
- Reimagine scaffolding now uses a dedicated 'scaffolder' agent with an
explicit minimal tool list, a single-directory write scope, and the
untrusted-content discipline extended to the generated spec/architecture
docs it builds from (they derive from untrusted legacy code).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Four commands gain a Workflow-tool path (with direct-fan-out fallback for
older builds): extract-rules loops until dry with per-rule citation referees
and a P0 two-judge panel; harden runs class-scoped finders with adversarial
per-finding refutation; assess --portfolio pipelines one survey agent per
system with COCOMO computed uniformly in script; reimagine Phase E drops the
3-service scaffolding cap.
Workflow agents return schema-validated data and only the orchestrating
session writes artifacts — analysis agents are structurally read-only. All
five agents gain an untrusted-content discipline section (source code is
data, never instructions; comment-only claims are findings, not facts), and
the README documents the prompt-injection threat model for analyzed code.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Viewer (assets/topology-viewer.html):
- inline a minified d3 subset (hierarchy/pack, zoom, selection,
interpolateZoom, ease; ISC license) instead of loading from a CDN —
the page is now fully self-contained and works on air-gapped networks
- handle duplicate node ids (unique-suffix; edges bind to the first
occurrence) and store parent references directly, fixing
level-of-detail and selection corruption with messy generated data
- share one reveal rule between drawing, edge culling, and hit-testing
so edges no longer draw into collapsed containers
- pre-bucket edges by kind and keep a per-node adjacency map; the
hover/selection pass no longer scans every edge each frame
- cancel in-flight fly-to animations when a new one starts; clamp
fly-to zoom to the zoom extent; derive max zoom from the smallest
leaf so deep estates stay reachable
- render dead-end candidates (new deadEnds field) with a dashed
outline and a sidebar badge
- clicking a node during a flow walkthrough exits the walkthrough;
search results clear on selection and Escape; surrogate-safe label
truncation; clearer stats line; explicit empty-topology message
Commands:
- new /modernize-status: read-only progress report — artifact inventory
with timestamps, staleness flags, secrets-hygiene checks, next step
- map: deadEnds in the topology schema; datastore names must be logical
identifiers with credentials stripped from URLs/DSNs
- brief: read topology.json + .mmd files (not the interactive HTML);
staleness check against inputs; effort unit aligned to person-months
- transform: secret-safe characterization-test prompt; diff -y fallback
when delta is missing; credential-safe diff selection
- reimagine: target vision is everything after the first argument (was
silently truncated to one word); masking rules in spec/scaffold/
handoff prompts
- brief/transform/reimagine: human-approval gates phrased as explicit
stop-and-wait instead of 'enter plan mode'
- preflight: delta in the tool table; brief added to the verdict list
- README: preflight/status in the workflow; legacy/ deny list also
covers Write; plugin + marketplace descriptions updated
modernize-map previously rendered the call graph and data lineage as
static Mermaid diagrams, which become unreadable once a node has ~10+
edges — exactly the shape of real legacy systems. It now builds an
interactive viewer from a shipped template (assets/topology-viewer.html):
a zoomable circle-pack of domains/modules sized by LOC, rendered to
canvas with level-of-detail reveal, dependency edges with per-kind
toggles, search with fly-to, a per-node detail sidebar, and a flow
walkthrough mode. Small domain-level .mmd exports remain for docs.
- topology.json now has a documented schema (hierarchy + edges + entry
points + observations + flows) consumed by the viewer
- map traces 2-4 business flows anchored to personas (claimant,
operator, auditor), each step in plain business language mapped to
the modules that implement it; the viewer plays them as numbered
paths
- brief gains a Business Walkthroughs section connecting each persona
flow to the phase that replaces it
- new modernize-preflight command: detects the stack, checks analysis
tooling, smoke-compiles a real source file with the legacy toolchain,
inventories missing copybooks/descriptors/binary-only artifacts, and
writes a per-command readiness verdict
- transform now verifies legacy + target toolchains before its plan
gate instead of failing at test time
- README: commands updated, optional-tooling section reframed as 'what
to give Claude'
A red-team pass found four ways credential values still reached
shareable artifacts after the initial redaction:
- the remediation patch: a diff removing a hardcoded secret carries the
raw value on its '-' lines by construction. harden now splits output:
non-credential hunks in the shareable security_remediation.patch,
credential hunks in a gitignored security_remediation.local.patch
with comment-only placeholders in the shareable file
- the other four agents had no secret-handling rules. legacy-analyst
(hardcoded-config evidence in tech-debt findings),
business-rules-extractor (credentials recorded as rule parameters),
test-engineer (legacy literals becoming committed test fixtures), and
architecture-critic (quoted code in notes files) now all mask values
and cite file:line; assess's tech-debt prompt and ASSESSMENT.md
masking now cover every section, not just Security Findings
- non-git projects: a .gitignore protects nothing under SVN/Mercurial.
Both commands now refuse --show-secrets without git and write the
quarantine file to ~/.modernize/<system>/ outside the project tree
- the patch-apply instruction was wrong in both documented layouts
(symlinked legacy/ broke relative paths). Patches are now written
with project-root-relative paths and applied from the project root
Also: --show-secrets is now position-independent in both commands, and
the README documents the full model.
Legacy systems often contain live credentials, and assessment/findings
files get committed and shared. Previously the security-auditor agent
reported hardcoded secrets verbatim into ASSESSMENT.md and
SECURITY_FINDINGS.md.
- security-auditor: mandatory secret-handling rules — mask all credential
values (file:line + 2-4 char preview), redact secrets from echoed tool
output, recommend rotation for anything that looks live
- assess/harden: gitignore-verified SECRETS.local.md quarantine file for
the per-credential inventory; findings files get masked entries and a
pointer only
- new --show-secrets flag opts into raw values in the quarantine file
(and only there)
- README: document the behavior and advise users of earlier versions to
check for already-committed findings and rotate
- modernize-harden: never edits legacy/ anymore. Writes findings plus a
reviewed unified diff to analysis/<system>/security_remediation.patch.
A second security-auditor pass reviews each hunk (RESOLVES / PARTIAL /
INTRODUCES-RISK) before presenting. The user reviews and applies the
patch deliberately, then re-runs to verify. This makes every command
consistent with the recommended deny Edit(legacy/**) workspace setting,
so the README's exception note is gone.
- modernize-map: restructure the parse-target list around three stack-
agnostic principles (dispatcher targets are variables; code-storage
joins live in config; entry points live in deployment descriptors), with
COBOL/Java/web/CLI examples on equal footing rather than COBOL-dominant.
Same protections against false dead-code findings, less stack-specific.
- security-auditor agent: rephrase coverage items in stack-neutral terms
(record layouts/temp datasets, resource ACLs, deployment scripts/job
definitions, batch input records) so the checklist reads naturally for
COBOL, Java EE, .NET, and web targets alike.
- README: drop the harden exception note; describe the patch workflow.
Fixes found by running the discovery workflow against the AWS CardDemo
mainframe sample (~50 KLOC of COBOL/CICS/JCL/BMS/VSAM):
- modernize-assess: add scc -> cloc -> find/wc fallback chain with the
COCOMO-II formula so Step 1 works when scc isn't installed; same for
portfolio-mode cloc/lizard. Drop the reference to a specific
agent-spawning tool name (just "in parallel"). Sharpen the structural-
map subagent prompt: 5-12 domains, subgraph clustering, ~40-edge cap,
repo-relative paths, dangling-reference check.
- modernize-map: expand the parse-target list with the things a
literal-minded reader would miss on a real mainframe codebase — CICS
CSD DEFINE TRANSACTION/FILE for entry points and online file I/O,
EXEC CICS file ops, SELECT...ASSIGN TO joined with JCL DD,
EXEC SQL table refs (not JCL DD), SEND/RECEIVE MAP, dynamic
data-name XCTL resolution, COBOL fixed-format column slicing. Without
these the dead-code list is wrong (most CICS programs look unreachable).
Also write a machine-readable topology.json alongside the summary.
- modernize-extract-rules: add a Priority (P0/P1/P2) field with a
heuristic, and an optional Suspected-defect field. modernize-brief
reads P0 rules to build the behavior contract, but the Rule Card had
no priority slot — the chain was broken.
- modernize-brief: read the new P0 tags; flag low-confidence P0 rules as
SME blockers.
- modernize-reimagine: drop "for the demo" wording.
- security-auditor agent: add mainframe/COBOL coverage items (RACF,
JCL/PROC creds, BMS field validation, DB2 dynamic SQL, copybook PII)
and mark web-only items as such so it adapts to the target stack.
- README: add Optional Tooling section and a symlink example for the
expected layout.
- modernize-brief: read TOPOLOGY.html (what modernize-map actually
produces) instead of nonexistent TOPOLOGY.md, and tell the user which
command produces each missing input.
- README: rewrite the Commands section to match actual command behavior —
correct output filenames, ordering (brief is the synthesis/approval gate
after discovery, not the first step), agent attributions, and required
args. Add a workspace-layout note and an explicit callout that
modernize-harden edits legacy/, which conflicts with the recommended
deny rule. Reconcile the Overview and Typical Workflow sequences.
- modernize-assess: generalize the production-runtime overlay step so it
no longer assumes a specific MCP server/tool; mark it optional. Fix
app/jcl/ -> legacy/$1/jcl/ for layout consistency.
- modernize-map: make TOPOLOGY.html self-contained (load Mermaid from a
CDN) so it renders in any browser; drop assumptions about an external
artifact renderer. Generalize the telemetry annotation note.
- business-rules-extractor agent: fix command cross-reference to the
actual command name.
- plugin.json: include the brief step in the workflow description.