OCI_Icons.pptx ships both a full icon group (tag=grpSp, ~0.7" tall)
and a tiny "label strip" (tag=sp, ~0.2" tall) under the same slug for
many services. The previous resolver picked whichever came first in
the index, which for 'mysql' returned the text strip — so the PPTX
diagram showed a label-only shape instead of the dolphin/HeatWave
icon, while drawio rendered the proper stencil.
Two fixes, both persistent (apply to every icon family, not just MySQL):
- TYPE_TO_ICON for mysql/heatwave now lists 'mysql_heatwave' (the
grpSp) before 'mysql' (the strip).
- _select_preferred_ref now filters viable refs to those that are
either grpSp/pic OR have a bbox ≥0.4"x0.4" — text strips fall out
before the scoring function runs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Implements points 3–8 of the post-procedure follow-up.
- Make targets: diagram-lookup, diagram-validate-spec, diagram-spec-audit,
archcenter-descriptions-refresh, archcenter-smoke. Promotes the new
tools out of "remember the CLI" into discoverable build-automation.
- .gitea/workflows/diagram-validators.yaml — runs spec validator across
every absolute_layout spec on push/PR, plus a drawio re-render smoke
test on the canonical example. Hard fail blocks merges.
- archcenter_pattern_lookup --llm-rewrite — opt-in (ANTHROPIC_API_KEY
env var, mirroring DRAWIO_EXE pattern). Rewrites natural-language
queries into canonical OCI terminology before scoring; falls back to
the original query on any error.
- diagram_spec_validator — documents the policy on legacy archcenter
reproductions: LABEL_NEAR_PARENT_EDGE stays a warning so verbatim
reconstructions don't lose pixel-fidelity from cosmetic edits.
- README — documents the asset refresh procedure (downloader +
description fetcher are idempotent, refresh quarterly).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The diagram path now follows a documented standard procedure (lookup
the closest Oracle Architecture Center reference → confirm components
→ author absolute_layout → spec validator → render → visually verify)
and ships persistent guardrails so layout regressions can't recur.
Persistent procedure changes (apply to all users, all sessions):
- tools/diagram_spec_validator.py — geometry checks (CONTAINER_TOO_THIN,
CONTAINER_PADDING_VIOLATION, LABEL_OVERFLOW_PARENT) run BEFORE either
renderer (drawio + PPTX). Catches the subnet-collapse / label-overflow
bugs that the post-render drawio validator missed.
- tools/oci_diagram_gen.py + tools/oci_pptx_diagram_gen.py — call the
spec validator before emitting any output. Adds mysql / mysql_heatwave
type aliases.
- tools/archcenter_pattern_lookup.py — scores against cached page
descriptions (not just the 1-line summary), supports --queries for
multi-fragment composition, and applies synonym expansion via
kb/architecture-center/synonyms.yaml so "LB HA cross AD" matches
"load balancer high availability availability domain".
- kb/architecture-center/synonyms.yaml — canonical synonym table
(load balancer, autonomous database, data guard, …) used by the
lookup scorer.
KB enrichment:
- tools/archcenter_description_fetcher.py + 121 cached _description.md
under kb/diagram/assets/archcenter-refs/<slug>/. Removes the runtime
dependency on docs.oracle.com when authoring specs and feeds the
pattern-lookup scorer.
- 110+ cached .drawio / .svg / .png references for offline reuse,
plus the OCI Toolkit v24.2 import (kb/diagram/assets/oci-toolkit-drawio).
Documentation:
- docs/skill/output-formats.md — new "Standard diagram-generation
procedure (MANDATORY)" + geometry rules + the new validator entry.
- SKILL.md option 2 — references the mandatory procedure.
- README.md — describes the spec validator, archcenter_pattern_lookup
and description fetcher, and updates the KB-health table.
Tooling that backs the procedure (cumulative across recent sessions):
tools/archcenter_case_runner.py, archcenter_batch_driver.py,
archcenter_zip_downloader.py, drawio_visual_validator.py,
drawio_fidelity_eval.py, harvest_drawio_icon.py, import_oci_library.py,
oci_pptx_diagram_gen.py, oci_pptx_render.py, refresh_pptx_icon_index.py.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The workflow's grep-on-free-text approach was fragile: local run correctly
extracted 162, but in the CI run the 'Open issue' step was skipped, meaning
new_count ended up as 0 after parsing. Likely causes: stdout buffering,
color codes, or shell differences between local and the Gitea runner's
shell.
Fix: tools/refresh_sku_catalog.py --discover now emits a deterministic
last-line marker `DISCOVER_MISSING_COUNT=<n>`. The workflow parses that
with sed (anchored, unambiguous) instead of the human-facing summary
line. Also added a diagnostic echo so the parsed value shows up in CI
logs for future debugging.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- refresh_sku_catalog.py: add --discover to report API SKUs missing from
catalog, filtered to already-curated serviceCategory values. Auto-runs
at end of --validate and --refresh so gaps surface on every maintenance
pass. First run found 162 missing SKUs (Blackwell GPUs, X12 Ax compute,
VMware reserved tiers, WebLogic-on-OKE, Analytics/OIC BYOL).
- oci_bom_gen.py: fix Cost % column being blank. Back-fill was gated on
formula detection but data rows write raw numbers, so the predicate
never matched. Now tracks data_item_rows explicitly.
- .gitea/workflows/sku-catalog-refresh.yaml: monthly automation (1st at
09:00 UTC). Auto-refresh prices → push branch + open PR; detect new
SKUs → open issue with labels. Gated on secrets.GITEA_TOKEN.
- kb/pricing/oci-sku-catalog.yaml: add B95714 / B95715 (Autonomous ATP
Dedicated ECPU, LI + BYOL) — canonical SKUs for ADB-D pricing.
- kb/services/compute.yaml: add X12 family (VM.Standard4.Ax.Flex,
BM.Standard4.Ax.120), E6.Ax and A4.Ax variants. Verified against
docs.oracle.com computeshapes.htm. Bump last_verified + changelog.
- templates/bom-spec.yaml: document 730 hrs/month convention as default
(= real annual billing / 12; 744 overstates by 1.92% on 12-month TCO).
- Makefile: new 'make sku-discover' target.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Service Tiering slide no longer falls back to the workload `name`
field for the tier label, which previously rendered "Bronze Bronze"
when the spec only carried tier names. Uptime/RTO/RPO now fill from
tier defaults when the spec omits them.
Architecture Principles slide enriches caller-supplied items with
name + summary from the KB when only the principle id is given,
instead of rendering bare placeholders like "P-01 P-02".
Architecture Overview slide auto-builds a two-region visual when the
proposal spec names a `dr_region` but doesn't pre-render `architecture.visual`,
so DR is no longer dropped from the deck.
Diagram generator gained a region-level `local_dr` flag that adds a
"Local DR Standby" dormant node inside the region, and now auto-wires
an "RPC (Remote Peering)" edge between DRGs when the spec defines
two or more regions with DRGs but no manual peering connection.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Architecture Overview slide was rendering the DR region with a fallback
label (e.g. "DR STANDBY" with no region name) because _adapt_flat_spec()
only consulted disaster_recovery / architecture.dr — it never looked at
the dr_region / tenancy.regions fields the MCP actually emits. The
adapter now discovers the primary and DR regions from:
- spec.primary_region / spec.region / architecture.primary_region
- spec.dr_region / spec.secondary_region / architecture.dr_region
- tenancy.regions[] entries (strings or {region, role} dicts, with role
in {primary, hub, prod, production} vs {dr, standby, secondary,
failover})
When both regions are known, the adapter emits an architecture.visual
with two labeled region blocks so the DR region renders with its real
name (e.g. "mx-monterrey-1 [DR STANDBY]") instead of the placeholder.
If the spec already supplies architecture.visual or diagram_path, those
are preserved instead of overwritten.
Operational RACI slide kept being skipped for payloads that passed
operational_raci in a non-canonical shape. The from_spec handler now
accepts:
- Top-level key aliases: operational_raci, raci, operations_raci
- Bare string ("fully_managed") → loads KB defaults for that model
- List of dicts → used directly as raci_items
- Dict with raci_items / items / activities and model / engagement_model
- Empty raci_items → falls back to KB defaults by model
The flat adapter also now respects a user-supplied operational_raci
instead of overwriting it with the co_managed default. Verified:
operational_raci: "fully_managed" renders the Fully-Managed RACI table
with 18 activities; bare flat MCP payload still gets the 13-activity
co_managed default.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Regression after the closing-slide removal surfaced a separate bug:
_adapt_flat_spec() only emitted metadata + summary + cost, so decks
generated from the MCP flat payload collapsed to 3-5 slides of title +
summary. The deck generator's ECAL sections (service_tiering,
architecture_principles, environment_catalogue, operational_raci, etc.)
all check top-level spec keys the adapter never produced.
Adapter now also emits, from the flat payload + kb/patterns defaults:
- service_tiering from services[] (preserves any tier/uptime/rto/rpo)
- architecture / architecture_principles (ECAL "always" picks)
- ha_dr tiers derived from the distinct service tiers present
- security baseline (IAM/network/database/monitoring controls)
- environment_catalogue (Prod/Pre-Prod/Dev-Test, +DR if enabled)
- operational_raci co_managed default from the KB
- next_steps skeleton
Flat MCP payload now renders 11 content slides instead of 3-5, and the
proposal-spec.yaml path (non-flat) is unchanged — still 16 slides for
examples/proposal-spec.yaml.
Also documents the new data_services SKUs in docs/bom-cookbook.md as
Recipe 4 (BDS/DS/DF) so MCP payloads can use the catalog codes directly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- oci_deck_gen / oci_bizcase_gen: stop appending the Thank You + Oracle
logo-only closing slides at the end of every generated deck.
- oci_bizcase_gen: Business Drivers now reads primary_driver at the
drivers-level and at the top level, and renders natural-language values
verbatim (only snake_case enum tokens are Title-cased). A spec-provided
drivers.items / additional / secondary list replaces the hardcoded
"Financial Impact of Inaction" + "Operational Impact" fallback cards.
- oci-sku-catalog.yaml: add data_services category with the four real
Big Data Service SKUs (B91128/B91129/B91130/B93555) plus EST-DS-NOTEBOOK,
EST-DS-MODEL, EST-DF-SPARK as estimate placeholders (OCI Data Science /
Data Flow have no dedicated SKUs in the public pricing API — they are
billed via the underlying compute shape).
- oci_bom_gen: resolver now prints a stderr warning and tags estimate/
unknown line items with an explicit note; the xlsx writer renders
"other" category items under an "Uncategorized — confirm SKUs" section
at the end instead of silently dropping them.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Harden bizcase, bom, deck, and diagram generators to tolerate payload
shape variants (metadata/cover/summary/line_item aliases, current_state
as string, alternate pillar keys) so MCP and CLI flat specs render
consistently. Add input-alias tests per generator.
Also loosen KB governance tests to handle multi-document service YAMLs
with optional changelogs, untrack the customer demo output under
examples/output-demo-pharma-mx/ (matches .gitignore), and ship an
ADB-S vs Aurora 500GB sample deck.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
generate_deck on the MCP server passes a flat spec (customer_name, title,
workload_type, services, cost_summary, ...) — but from_spec only understood
the proposal-spec YAML shape (metadata/summary/architecture/...). With no
matching keys, only the title and closing layouts rendered, both populated
with empty strings, producing a deck that looked blank.
Detect the flat shape in from_spec and adapt it into the proposal-spec
fields that the existing slide builders already consume. Title, summary
(target state + current-state bullets) and cost slides now render from
whatever the MCP tool sends; the richer proposal-spec path is untouched.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6 improvements based on Oracle Architecture Center reference diagrams:
1. Edge label offset — labels pushed 15px away from edge midpoint via
mxGeometry offset injection, prevents overlap with icons
2. Auto-sizing containers — regions, VCNs, tenancy calculate dimensions
from content instead of using fixed sizes (DR region: 540→260px)
3. jettySize=auto on all edges — clean stubs leaving/entering shapes
4. Dual connection merging — duplicate from/to pairs merged into single
edge with combined label (e.g., dual FastConnect)
5. DRG placed OUTSIDE VCN, INSIDE region — matches Oracle ref arch
pattern where DRG is the central hub between external and VCN
6. container=1;collapsible=0 injected into container XML styles
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Root cause: elbow=vertical conflicted with orthogonalEdgeStyle + port
constraints, causing arrows to route backwards and cross content.
Changes to oci_diagram_gen.py (generic, all diagrams):
- Remove elbow=vertical from edge base style
- Use edgeStyle=orthogonalEdgeStyle explicitly in extra_style
- Add jumpStyle=arc;jumpSize=8 — crossing edges show arc, not overlap
- Remove drawpyo waypoints="orthogonal" (now controlled via extra_style
to avoid style merging conflicts)
- Vertical edges with labels: align=left so text doesn't overlap icons
- Regression tested with PharmaCorp (dual-region) and MELI (single-region)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Edges now auto-detect exit/entry ports based on relative positions of
source and target services. Uses absolute coordinates from the layout
engine to determine whether connections should exit right→left,
top→bottom, etc.
- exitX/exitY/entryX/entryY added to every edge style
- 1.5x threshold favors vertical routing over horizontal when positions
are diagonal — matches Oracle ref arch top-down subnet flow
- Eliminates crossing arrows in multi-subnet, multi-region diagrams
- Verified with both PharmaCorp (dual-region) and MELI (single-region)
Generic code fix — applies to all diagrams, not just this spec.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
oci_diagram_gen.py auto-layout improvements:
- Gateways now placed FIRST, vertically centered on VCN left edge
- Subnets offset RIGHT by gateway lane width to avoid overlap
- Gateway lane width auto-calculated from widest gateway + padding
- Network edges: teal color, thicker (2px) for visual hierarchy
- Internal edges: gray dashed for management connections
- Data edges: solid charcoal (unchanged, default)
These are generic code fixes — apply to any diagram spec, not just
the PharmaCorp demo. Verified with both PharmaCorp and MELI specs.
Also regenerated all PharmaCorp deliverables with prior fixes:
- Business case: PharmaCorp (was MELI), correct TCO/ROI/value schema
- BOM: verified SKUs from catalog, 45% global discount applied
- PDF: environment catalogue with new schema
- Diagram: clean layout with gateway offset
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
oci_bom_gen.py from_spec now reads metadata.discount_pct as fallback
when individual line items don't specify a discount. This means
discount_pct: 0.45 in the spec metadata applies 45% to every SKU.
Previously, global discount was silently ignored — only per-item
discount fields were read (defaulting to 0.0).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- oci_pdf_gen.py: add_environment_catalogue now auto-detects new schema
(name/sizing/cost_pct) vs legacy (environment/tier/databases/ocpus),
same fix as oci_deck_gen.py. Also normalizes cost_notes string to list.
- business-case-spec.yaml: created PharmaCorp spec (was using MELI).
Fixed schema: risks as {migration_risks, do_nothing_risks}, roadmap
as {phases, total_duration}, recommendation as {summary, next_steps}.
- diagram-spec.yaml: rewrote to match generator format
(tenancy.regions[].vcns[].subnets[].services[] with explicit IDs).
Now generates 231 cells, 11 containers, 15 services, 10 connections.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Skill repo: git.tech-lad.com.br/diegoecab/oci-deal-accelerator
- MCP repo: github.com/Diegoecab/arch-mcp-oracle
- Both links on Get Started slide and closing slide
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Slide 10: MCP Server — zero setup, 14 tools over HTTP, supported
clients (Claude, Codex, Cursor, Windsurf), 1-command connection.
"Zero Python. Zero repo cloning. SA opens IDE and starts working."
- Slide 12: Get Started — Option A (MCP, recommended), Option B
(clone repo), link to github.com/Diegoecab/arch-mcp-oracle.
Placeholder for final get-started link.
- Updated closing slide with MCP repo URL.
- Takeaways now include MCP as differentiator.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New slide 4: side-by-side table comparing Generic LLM vs OCI Deal
Accelerator across 8 dimensions (pricing, architecture, field gotchas,
competitive, WA validation, compliance, output format, improves over
time). Red header for generic LLM, green for skill.
Key message: "The LLM is the engine. The KB + tools are the fuel.
The SA is the driver."
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two new slides replace the generic "Under the Hood":
- Slide 8: The Knowledge Base Is the Moat — 40+ YAML files of field
knowledge, auto-refreshed pricing, 123 reference architectures,
honest competitive mapping. Without KB = chatbot, with KB = domain expert.
- Slide 9: Self-Updating KB + Collaborative Field Intelligence —
auto-refresh (SKU API, Arch Center crawler), collaborative model
(findings_cli add/confirm with attribution), governance (health
dashboard, staleness detection, domain owners).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Why this set of changes:
- KB pricing was drifting silently — domain files (database.yaml,
storage.yaml, etc.) had prices 30-800% off the live Oracle API and
nobody read them. The skill was auditing as stale on every check
with no path to fix it.
- The skill itself violated Anthropic's spec (`name` field had
uppercase/spaces) and was over the 500-line guideline (647 lines),
hurting discovery and load performance.
- Welcome flow occasionally improvised the menu instead of reading
SKILL.md, missing options.
Pricing — single source of truth, fully automated:
- Extend tools/refresh_sku_catalog.py with --refresh-domain compute,
pulls shape-level prices from the Oracle public pricing API
(apexapps.oracle.com), preserves manual fields (notes, GPU specs,
free-tier annotations, estimation_helpers), recomputes derived
monthly values, and protects $0 free-tier prices from overwrite.
- Delete 12 redundant pricing/<domain>.yaml files. They duplicated
oci-sku-catalog.yaml with worse abstractions and were nobody's
source of truth (no tool consumed them).
- Migrate the genuinely valuable knowledge from those 12 files
(billing models, BYOL rules, free-tier rules, ECPU vs OCPU,
X11M elastic model, hyperscaler comparisons, service nuances)
into kb/field-knowledge/pricing-knowledge.yaml — non-numeric,
no refresh needed.
- Result: pricing freshness check goes from 13 stale files to 0.
KB freshness automation:
- Add tools/kb_freshness.py — wrapper around kb_linter.check_freshness()
with --check, --auto-refresh, --json, --quiet modes. Bridges stale
files to their refresh tools (SKU catalog, compute domain, arch
center). Wired into the welcome flow as a pre-flight banner that
asks the user before refreshing.
- Fix pre-existing kb_linter bug: it crashed on the 45 multi-doc
YAML files (frontmatter + body pattern) because it used safe_load
instead of safe_load_all. Freshness check was effectively dead.
- Standardize timestamp field: linter now accepts last_verified,
last_updated, and last_refreshed; refresh_arch_catalog writes
last_verified instead of last_refreshed.
- Add make freshness / make freshness-refresh targets.
Skill alignment with Anthropic Agent Skills best practices:
- Rename `name: OCI Deal Accelerator` to `oci-deal-accelerator`
to comply with the [a-z0-9-]{1,64} spec.
- Refactor SKILL.md from 674 to 445 lines via progressive disclosure:
extract WA review output format, ECAL readiness format, and output
conventions into docs/skill/*.md referenced from the main file.
- Add scripts/sync-skill.py + make sync-skill: source of truth is
root SKILL.md, .agents/skills/oci-deal-accelerator/SKILL.md is
auto-generated. make lint validates sync.
- Add evaluations/ with 3 manual baseline scenarios (welcome-flow,
full-proposal, wa-review) per the Anthropic best-practices guidance
to "build evaluations first."
Welcome flow hardening:
- Tighten CLAUDE.md to MANDATE reading SKILL.md before showing the
menu (no improvising), and document the freshness pre-flight check
with the ask-before-refresh user flow.
- Update SKILL.md welcome flow to instruct: parse kb_freshness JSON,
show banner with stale count + oldest file, prompt user to refresh
(only when an automated tool exists), fall back silently on errors.
Linter hygiene (zero remaining issues):
- Expand config/kb-tags.yaml taxonomy with features, operations,
metrics, limitations sections covering 31 previously-unknown tags
used in field findings (rac, ecpu, refreshable-clone, hnsw, etc.).
- Assign owners for kb/compatibility/, kb/competitive/,
kb/well-architected/ (Diego Cabrera as default until team grows);
kb/pricing/ marked as "Auto-refreshed" since it no longer needs
human ownership.
- kb_linter accepts top-level `date` as fallback for contributor
block; migrate FF-202603-008 from legacy `reported_by` to
contributor block.
- Result: linter goes from 45 issues to 0.
Other:
- Recompute estimation_helpers monthly values in compute.yaml after
the price refresh (they were derived from the old E5/A1 numbers).
- Add kb/README.md — contributor guide (directory map, frontmatter
spec, refresh tooling, review cadence).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- New tools/oci_bom_gen.py: generates .xlsx BOM from YAML spec with
Oracle Redwood styling, Excel formulas, and Oracle disclaimer.
Supports standard BOM (--output) and AppCA import format (--appca)
- New tools/refresh_sku_catalog.py: refreshes SKU catalog prices from
Oracle's public pricing API (apexapps.oracle.com)
- New kb/pricing/oci-sku-catalog.yaml: ~160 OCI SKUs across 14
categories, validated against Oracle API
- New templates/bom-spec.yaml: input spec template for BOM generation
- Add SA TOOLS section to SKILL.md (options 13-14)
- Register BOM generator in oci_output.py