46 Commits

Author SHA1 Message Date
sku-refresh-bot
f95c4c3dc8 chore(pricing): monthly SKU catalog refresh (2026-04-24)
Automated refresh from Oracle public pricing API.
See workflow artifact 'sku-refresh-logs' for the diff.
2026-04-24 15:33:17 +00:00
root
30394ece48 Pin upload-artifact to v3 for Gitea Actions compatibility
All checks were successful
Deploy Skill to OCI / deploy (push) Successful in 21s
Gitea Actions runner does not support actions/upload-artifact v2.0.0+
(error: "@actions/artifact v2.0.0+, upload-artifact@v4+ and
download-artifact@v4+ are not currently supported on GHES").

The v4 release switched to a new artifact API that only GitHub-hosted
runners implement. v3 still uses the v1 API and works on Gitea /
self-hosted / GHES runners.

Downgraded in both sku-catalog-refresh.yaml and kb-health.yaml.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 12:31:58 -03:00
root
480c4bca52 Fix Python setup in Gitea Actions workflows
All checks were successful
Deploy Skill to OCI / deploy (push) Successful in 25s
The oci-mcp-runner uses node:20-bookworm which runs as root and does
NOT ship with sudo installed. Our workflows used 'sudo apt-get' → step
failed with 'sudo: command not found' (exit 127) on first invocation
of sku-catalog-refresh.yaml.

Fix both affected workflows (sku-catalog-refresh + kb-health):
- Drop the `sudo` prefix (we're already root).
- Install Python deps via apt packages (python3-requests, python3-yaml,
  python3-bs4) instead of pip. Avoids PEP 668 / externally-managed
  environment error on Debian 12 and is faster/cacheable by the runner.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 12:24:35 -03:00
root
433b08071b Use auto-provisioned GITHUB_TOKEN in SKU refresh workflow
All checks were successful
Deploy Skill to OCI / deploy (push) Successful in 30s
Switch from manually-configured secrets.GITEA_TOKEN to the auto-provisioned
secrets.GITHUB_TOKEN that Gitea Actions creates per run. Scoped to the repo,
rotates per workflow run, no manual config needed.

Added explicit permissions block (contents:write, pull-requests:write,
issues:write) so the ephemeral token has the scopes required to push a
branch, open the PR, and open the issue for new SKUs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 11:51:00 -03:00
root
874d40d38a Improve SKU catalog hygiene and BOM accuracy
All checks were successful
Deploy Skill to OCI / deploy (push) Successful in 21s
- 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>
2026-04-24 11:40:53 -03:00
root
a22711c065 Update ExaCS X11M KB with authoritative datasheet figures
All checks were successful
Deploy Skill to OCI / deploy (push) Successful in 30s
Source: ADB-D X11M Datasheet v1.0 (Jan 2025), Table 1.

- Add HC storage variant (default): 80 TB usable disk/SS, 264 TB raw, 1.25 TB
  XRMEM + 27.2 TB flash cache per SS. Keep EF variant (52.5 TB usable/SS).
- Add x11m_elastic_base (2 DB + 3 SS): 240 TB total usable disk, 192 TB Max
  DB Size no-backup (what OCI Cost Estimator caps at), 96 TB with backup.
  Include performance metrics (5.6M read IOPS, 300 GB/s flash bw, etc.).
- Add x11m_base_system as distinct SKU: fixed-spec, non-expandable, 192
  ECPUs / 73 TB usable disk / 10 GbE — not the same as elastic 2+3.
- Replace misleading rack_configurations table (mixed X9M figures) with
  elastic per-server model; 'quarter/half/full rack' noted as legacy.
- Add pricing verified against OCI Cost Estimator 2026-04-23: DB and SS at
  \$2.9032/hr each; base config \$10,800/month excluding licenses.
- Add gotcha exacs_x11m_hc_vs_ef: default quotes to EF without
  justification; HC serves hot data from flash cache at same latency and
  far better \$/TB.
- Document the three distinct storage figures (Total Usable Disk vs Max DB
  Size no-backup vs with-backup) to avoid customer confusion.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 10:02:42 -03:00
root
9d5cda8986 Fix BOM workbook monthly totals
All checks were successful
Deploy Skill to OCI / deploy (push) Successful in 21s
2026-04-23 10:54:07 -03:00
root
6de2251e00 Fix slide and diagram bugs in deck/diagram generators
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>
2026-04-23 00:35:10 -03:00
root
77298a471c Read DR region from spec + make operational_raci handler tolerant
All checks were successful
Deploy Skill to OCI / deploy (push) Successful in 19s
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>
2026-04-22 14:32:25 -03:00
root
6209907a63 Enrich MCP flat-spec adapter to emit full ECAL deck content
All checks were successful
Deploy Skill to OCI / deploy (push) Successful in 17s
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>
2026-04-22 13:13:42 -03:00
root
fc550c14bb Drop closing blanks, honor primary_driver, catalog data-services SKUs
All checks were successful
Deploy Skill to OCI / deploy (push) Successful in 23s
- 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>
2026-04-22 12:34:37 -03:00
root
490072a4b7 Accept flat-spec input aliases across generators
All checks were successful
Deploy Skill to OCI / deploy (push) Successful in 20s
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>
2026-04-21 10:22:14 -03:00
root
bcb16795d1 Add BOM cookbook to shortcut SKU mapping for common patterns
All checks were successful
Deploy Skill to OCI / deploy (push) Successful in 24s
Codex sessions burn 10+ tool calls grepping kb/field-knowledge and the SKU
catalog to map standard requirements (ExaCS X11M BYOL, ADB-D, ADB-S + block
+ FastConnect) to the 4-5 SKUs the MCP BOM tools need. Bake the recipes
into docs/bom-cookbook.md so the LLM can skip the exploration loop for
well-known patterns, and link it from SKILL.md between Output Generation
and Knowledge Base (same progressive-disclosure pattern the other docs use).

Recipe 2 (ADB-Dedicated) explicitly calls out the infra-SKU overlap with
ExaCS — one of the specific traps the exploration loop keeps hitting.
Catalog-fallback note keeps the cookbook honest when a requirement does
not match.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 15:29:20 -03:00
root
e57ab57b48 Accept MCP flat payload in deck generator to stop silent-blank decks
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>
2026-04-20 15:27:44 -03:00
root
dc4abf3774 Install Python via apt instead of setup-python in KB health workflow
All checks were successful
Deploy Skill to OCI / deploy (push) Successful in 24s
actions/setup-python@v5 fails on the arm64 Gitea runner with "version '3.12'
with architecture 'arm64' was not found" — the prebuilt Python manifest
doesn't cover this runner/arch combo. Use the system python3 from apt; the
link-check scripts don't require 3.12 specifically.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 11:00:56 -03:00
root
01baff1f5b Ship Oracle FY26 PPTX template in repo so MCP server finds it
The 13MB template was caught by the global *.pptx ignore rule, leaving
generate_deck failing with "Template not found" in any environment that
builds from a fresh clone (MCP server container included). Whitelist it
alongside the existing sample-output exception.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 10:57:02 -03:00
root
aaf0ecc548 Add "New user? Start here" section with MCP setup instructions
Some checks failed
Deploy Skill to OCI / deploy (push) Successful in 18s
KB Health Check / check-links (push) Failing after 50s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 12:40:24 -03:00
root
7cfb5dce2d Route skill pre-flight through Makefile to avoid hardcoded Python
All checks were successful
Deploy Skill to OCI / deploy (push) Successful in 18s
Codex users hit `python: command not found` on the welcome-flow
pre-flight because SKILL.md called `python tools/kb_freshness.py`
directly. Any hardcoded version (python/python3/python3.12) breaks
for somebody — users have 3.8, 3.10, 3.11, 3.12 in the wild.

Fix: channel all skill-initiated Python calls through `make` targets
so the Makefile's single $(PYTHON) variable (auto-detected venv >
3.12 > 3.11 > 3.10 > python3) is the only place Python resolution
lives.

- Makefile: add `kb-check` target emitting JSON for the skill pre-flight
- SKILL.md + .agents/skills/.../SKILL.md: call `make kb-check` and
  `make freshness-refresh` instead of bare `python tools/...`
- CLAUDE.md: same fix in the Welcome Flow instructions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 12:06:15 -03:00
root
98cb570e96 Portable setup: venv, Claude Code + Codex project config
All checks were successful
Deploy Skill to OCI / deploy (push) Successful in 19s
Makes the skill work on any laptop regardless of installed Python version
or LLM harness, without per-command approval prompts or missing deps.

- Makefile: auto-detect Python (venv > 3.12 > 3.11 > 3.10 > python3)
  and new `make venv` target that picks the best Python at creation time
- .claude/settings.json: project-level Claude Code permissions
  (Write to examples/ and output/, common bash commands pre-authorized)
- .codex/config.toml: Codex sandbox config with network_access=true,
  approval_policy=never, sandbox_mode=workspace-write — fixes
  `make venv` failing with "No matching distribution" in Codex
- CLAUDE.md / AGENTS.md: document the `make venv` flow, drop all
  hardcoded python3.12 references in favor of make targets
- CLAUDE.md: add Karpathy-style coding guidelines (think before coding,
  simplicity first, surgical changes, goal-driven execution)
- .gitignore: add .venv/

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 12:03:46 -03:00
root
20be7c297e Diagram generator calibrated from 37 Oracle ref architectures + KB health tooling
All checks were successful
Deploy Skill to OCI / deploy (push) Successful in 25s
Diagram generator (oci_diagram_gen.py):
- Icon sizing calibrated: 63px target height, 45px min width (from 37 Oracle
  Architecture Center .drawio files: 12,617 cells, 234x 63x63 service icons)
- Auto-sizing: containers grow from content, never overflow (validated by script)
- DRG placed outside VCN, inside region (Oracle hub-spoke pattern)
- Gateway stacking uses _calc_service_block_h to prevent label overlap
- Edge labels: mxGeometry offset injection (15-20px away from midpoint)
- Tight icon groups: edges connect to visible icon, not invisible wide group
- VCN/subnet dash pattern corrected to "4 2", stroke to #aa643b (Oracle ref)
- jettySize=auto, dual connection merge, container=1;collapsible=0

New tools:
- scripts/validate-diagram.py: checks icon sizes, overlaps, container overflow
- tools/refresh_arch_catalog.py --check-links: HTTP HEAD check on all 123 URLs
- .gitea/workflows/kb-health.yaml: weekly link + freshness check (Mon 8am UTC)
- kb/diagram/oracle-ref-measurements.md: exact measurements from Oracle refs
- kb/CHANGELOG.md: KB change log shown in welcome banner

SKILL.md:
- Pre-flight: python→python3, silent errors, git fetch check for local users
- Changelog banner in welcome flow
- Anti-hallucination guardrails (from earlier commit, carried forward)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 09:22:33 -03:00
root
886c09ad10 Improve diagram generator: auto-sizing, DRG placement, edge labels
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>
2026-04-14 02:01:09 -03:00
root
4660b93a98 Trigger CI workflow test
All checks were successful
Deploy Skill to OCI / deploy (push) Successful in 21s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 19:48:05 -03:00
root
9db2e59e5b Fix deploy workflow: replace rsync with tar+scp for runner compatibility
Some checks failed
Deploy Skill to OCI / deploy (push) Failing after 9s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 19:46:13 -03:00
root
f6f355c465 Add header comment to deploy workflow (trigger CI test)
Some checks failed
Deploy Skill to OCI / deploy (push) Failing after 8s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 19:44:41 -03:00
root
32d82df197 Add Gitea CI/CD workflow for auto-deploy to OCI on push to main
Some checks failed
Deploy Skill to OCI / deploy (push) Failing after 47s
Syncs skill files via rsync over SSH, restarts MCP containers, and waits
for healthy status. Requires OCI_SSH_KEY and OCI_HOST secrets in Gitea.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 18:13:03 -03:00
root
4e80528d1e Add anti-hallucination guardrails and structured data intake to SKILL.md
Fixes two issues: (1) diagrams adding unrequested components (EBS, WAF, Vault,
Monitoring, etc.) by replacing vague "implied dependencies" with a closed
whitelist of 6 technical dependencies and making pre-generation review mandatory
with 3 sections (REQUESTED/TECHNICAL/OPTIONAL). (2) Unstructured data consumption
by adding mandatory Extraction Receipt (CONFIRMED/INFERRED/MISSING), source
tracking in workload profiles, and completeness gate per engagement tier.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 18:02:08 -03:00
root
635863502d Fix diagram edge routing: remove elbow=vertical, add jumpStyle=arc
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>
2026-04-13 14:22:52 -03:00
root
b4edc2914d Fix diagram generator: auto-port detection for clean edge routing
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>
2026-04-13 11:03:18 -03:00
root
a0feea08bb Fix diagram generator: gateway-aware layout + edge type styling
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>
2026-04-13 09:55:13 -03:00
root
214b1c518e Add opt13-bom.xlsx with 45% global discount applied
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 09:26:40 -03:00
root
8726f14512 Fix BOM: apply global discount_pct from metadata to all line items
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>
2026-04-13 09:21:07 -03:00
root
cd718f8628 Regenerate BOM with verified SKUs (13 line items, ExaCS X11M + ADB-S + networking)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 09:16:30 -03:00
root
4d3b3507f5 Fix deliverable bugs: PDF env catalogue, business case schema, BOM SKUs, drawio
- oci_pdf_gen.py: auto-detect new env catalogue schema (name/sizing/cost_pct)
- business-case-spec.yaml: rewritten to match oci_bizcase_gen.py expected
  schema (tco.current_state/proposed_oci with annual_* fields, roi with
  three_year_roi_pct/total_investment/annual_net_benefit, value_drivers
  with category/driver/quantification, roadmap.phases, recommendation.summary)
- bom-spec.yaml: all SKUs verified against oci-sku-catalog.yaml (B110627
  B110629 B110632 for ExaCS X11M, B95703 for ADB-S BYOL, B88326 for
  FastConnect 10G, B91628 for Object Storage, B92092 for Vault)
- diagram-spec.yaml: full dual-region architecture (231 cells, 15 services)
- Now generates: PharmaCorp business case 11 slides, correct env catalogue
  in PDF, 13 SKU lines in BOM with real prices

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 01:06:00 -03:00
root
b0fcf8d0f3 Fix 3 deliverable bugs: PDF env catalogue, business case, drawio diagram
- 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>
2026-04-13 00:21:26 -03:00
root
d2b153c5ce Fix empty drawio: rewrite diagram-spec to match generator format
The diagram-spec.yaml was using a flat regions/subnets format but
the generator expects tenancy.regions[].vcns[].subnets[].services[]
with explicit IDs. Rewrote with full pharma architecture:

- Queretaro (primary): Hub VCN with 4 subnets (DB, App, Public, Mgmt),
  ExaCS X11M, EBS app tier, WAF, Vault, DRG, monitoring
- Sao Paulo (DR): DR VCN with ExaCS standby, FSDR, Object Storage
- 10 connections: dual FastConnect, Data Guard, FSDR, WAF chain, RMAN

Result: 231 cells, 11 containers, 15 services, 10 connections (was empty)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 00:12:39 -03:00
root
394b821579 Fix repo links in demo deck: skill repo + MCP repo
- 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>
2026-04-12 23:42:07 -03:00
root
5a490c9375 Add MCP server slide + Get Started CTA to demo deck
- 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>
2026-04-12 23:41:09 -03:00
root
a0a862e752 Add "Why not just ChatGPT?" comparison slide to demo deck
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>
2026-04-12 23:29:43 -03:00
root
b478718c90 Add KB-as-moat and collaborative field intelligence slides to demo deck
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>
2026-04-12 23:28:05 -03:00
root
41720a1c2b Regenerate demo deck with LLM-agnostic messaging and improved prompts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 23:25:57 -03:00
root
3c88df33f8 Add demo presentation + 14 deliverables for PharmaCorp Mexico scenario
- gen_demo_deck.py: Generates 11-slide demo presentation using Oracle FY26
  template. LLM-agnostic messaging (works on Claude, Codex, GPT, Gemini).
  Before/After comparison, 14 live prompts in table format.
- examples/output-demo-pharma-mx/: Complete deliverable set for a pharma
  migration scenario (ExaCS X6 → OCI ExaCS X11M, dual-region DR, SOX).
  One file per skill option (1-14): pptx, drawio, pdf, xlsx, json, yaml.
- Improved prompts: richer discovery context (SOX compliance, dual
  FastConnect, Hub-Spoke, OCI Vault), intentionally flawed arch for WA
  review (1/23 passed), DEP field findings, ECAL gap analysis.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 23:24:35 -03:00
root
b48d155c1b CLI improvements: --json output, filters, arch-search, ecal-score, deck fixes
6 CLI improvements from MCP integration testing + deck bug fixes:

- kb_cli.py: --json on search, new arch-search and ecal-score subcommands,
  _load_yaml handles multi-document YAML (fixes health command on 32 files)
- findings_cli.py: --json on search/list/stats, filter flags on search
  (--product, --severity, --tag, --client, --status, --category)
- validate-architecture.py: --profile optional, --output defaults to stdout
- common-objections.yaml + ecal-artefacts-catalog.yaml: merge front matter
- oci_deck_gen.py: fix slide 9 cost_notes char iteration, fix slide 12
  migration field mapping (duration/milestones), dynamic phase spacing
- proposal-spec.yaml: replace real name with fictional Carlos Mendoza

All 14 skill options validated with generated deliverables.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 23:02:40 -03:00
root
ca93a0aa4e Auto-refresh KB pricing, align skill with Anthropic best practices
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>
2026-04-08 23:59:32 -03:00
root
69b0ccb4b8 Fix 30 KB errors: ExaCS storage 3-10x wrong, ECPU transition, IOPS limits, missing shapes
Cross-referenced all 70+ KB files against official Oracle docs. Critical fixes:
- ExaCS: storage was flash cache not usable disk (76.8→190.8 TB QR), added X11M, removed X10M
- ADB-S: OCPU→ECPU migration, 26ai as default, cross-region RTO 15→10 min
- Compute: E5 max 94→126, A2 80→78, added E6/A4/BM shapes, 11 GPU shapes
- Storage: Higher Perf IOPS 35K→50K, UHP 450K→300K, File Storage 25K→50K
- DBCS: E5.Flex max 94→64, storage 80→150 TB, added 26ai
- Networking: FastConnect +400 Gbps, NSG max 120 rules

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 23:59:28 -03:00
root
fabd7254dd Add SA Tools: BOM generator and AppCA export
- 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
2026-03-27 15:21:50 -03:00
root
2b923f1aed Add SA Tools: BOM generator and AppCA export
- 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
2026-03-27 15:19:26 -03:00
111 changed files with 11796 additions and 2013 deletions

View File

@@ -1,8 +1,10 @@
---
name: OCI Deal Accelerator
name: oci-deal-accelerator
description: Compresses the OCI Solutions Architect's cycle from customer discovery to architecture proposal and delivery handover. Aligned with Oracle ECAL framework (Define, Design, Deliver). Use when processing discovery notes, composing OCI architectures, generating proposals, planning solution delivery, or producing handover artifacts.
---
<!-- AUTO-GENERATED FROM /SKILL.md — do not edit directly. Run `python scripts/sync-skill.py` to regenerate. -->
# OCI Deal Accelerator
You are the **OCI Deal Accelerator**, an AI skill that helps OCI Solutions Architects compress the cycle from customer discovery to architecture proposal — from days to hours.
@@ -15,6 +17,33 @@ You follow the **Oracle ECAL framework** (Define → Design → Deliver) to prod
When the user starts a conversation without providing discovery notes or a specific request, present the welcome message and capability menu.
### Pre-flight: KB freshness check
**Before showing the welcome message**, run `make kb-check 2>/dev/null` and parse the JSON output. Behavior based on the result:
- **`stale_count == 0`** → proceed directly to the welcome message. No banner.
- **`stale_count > 0` and at least one file has `refreshable: true`** → prepend this banner above the menu and ask the user inline:
```
⚠️ KB freshness: <N> file(s) outdated (oldest: <file> — <age_days>d).
<M> can be auto-refreshed (SKU catalog, Architecture Center).
Refresh now before showing the menu? [y/N]
```
- If the user replies `y` / `yes` / `` → run `make freshness-refresh`, wait for completion, then show the menu.
- If the user replies `n` / anything else → show the menu immediately, with a one-line compact reminder above it: `⚠️ <N> KB file(s) stale — run /freshness or make freshness-refresh later.`
- **`stale_count > 0` but no file has `refreshable: true`** (only manual files stale) → prepend a non-blocking informational banner above the menu, do NOT ask:
```
⚠️ KB freshness: <N> file(s) need manual review (oldest: <file> — <age_days>d).
No automated refresh available — see kb/README.md for review process.
```
Then show the menu directly.
**Important**: this check is informational, not gating. If `kb_freshness.py` errors out (exit 2 or missing tool), silently fall back to showing the welcome message — never block the user on tooling failures.
### Welcome Message
```
@@ -59,6 +88,11 @@ Present these options as a compact numbered list. Each option has a bold title f
─────────────────
12. 📊 ECAL readiness score — *60-artefact gap analysis*
SA TOOLS
─────────────────
13. 📦 BOM generator — *services + quantities → .xlsx Bill of Materials*
14. 📤 BOM for AppCA — *BOM → .xlsx ready to import into AppCA*
━━━━━━━━━━━━━━━━━━━━━━━
Pick a number, or just describe what you need.
```
@@ -80,64 +114,13 @@ Pick a number, or just describe what you need.
- Save the workload profile YAML to `examples/<customer>-wa-workload-profile.yaml`
6. After the scorecard, offer next actions
**WA Review Output Format:**
The WA review MUST produce **two layers of output**: (a) the formatted terminal scorecard shown to the user, and (b) the structured YAML files saved to disk. The terminal output is the primary deliverable — the YAML is the backing data. Never produce YAML-only output without the formatted scorecard.
```
══════════════════════════════════════════════════════
✅ OCI WELL-ARCHITECTED REVIEW — [Customer Name]
══════════════════════════════════════════════════════
Overall: [STATUS] — X/Y checks passed
HIGH: N │ MEDIUM: N │ LOW: N
══════════════════════════════════════════════════════
[emoji] SECURITY & COMPLIANCE X/Y passed
[emoji] RELIABILITY & RESILIENCE X/Y passed
[emoji] PERFORMANCE & COST X/Y passed
[emoji] OPERATIONAL EFFICIENCY X/Y passed
[emoji] DISTRIBUTED CLOUD X/Y passed | N/A
```
Pillar emoji: 🟢 all passed, 🟡 medium gaps only, 🔴 any HIGH gap, ⬜ N/A
**HIGH Severity Gaps Table:**
Present all HIGH gaps grouped by pillar in a markdown table:
```
### HIGH severity gaps that must be addressed:
**[Pillar Name] (N HIGH)**
| ID | Gap | Fix |
|---|---|---|
| CHECK-ID | Finding description | Recommended action |
```
**MEDIUM gaps:** List as a compact bullet list grouped by pillar (ID + one-line finding + fix). Skip the table format to keep it concise.
**LOW gaps:** Mention count only, list individual items only if ≤ 5.
**Analysis Section:**
After the gap tables, add a "Why so many gaps?" paragraph if total gaps > 20, explaining the root cause (e.g., business case without architecture, missing landing zone, no ops design). This contextualizes the score for the SA.
**Recommended Path Forward:**
3-5 numbered, actionable recommendations that directly map to closing the highest-impact gaps. Reference skill options where applicable (e.g., "Generate the architecture — option 1 or 2").
**After WA Review Menu:**
```
What do you want to do?
→ [A] Generate/fix the architecture to close gaps
→ [B] Deep-dive a specific pillar
→ [C] Export scorecard as a slide (.pptx)
→ [D] Re-run after changes
```
**Option [A] behavior — CRITICAL:** When the user picks [A], remediate the EXISTING architecture by adding the minimum changes needed to close gaps (e.g., add `encryption: true` to a storage block, add `flow_logs: enabled` to networking). NEVER replace the customer's actual architecture with a generic "ideal" one. NEVER add services or components the customer didn't mention (no inventing ExaCS, ADB, regions, etc.). If a gap requires a service the customer doesn't have, flag it as a recommendation and ASK before adding it. The remediated architecture MUST be recognizable as the customer's original architecture with targeted fixes applied.
**WA Review Output Format:** see [docs/skill/wa-review-format.md](docs/skill/wa-review-format.md) for the exact terminal scorecard layout, gap-table format, "after review" menu, and the critical Option [A] remediation behavior. Read that file before producing the scorecard.
- If the user picks **6**, ask: "What feature and deployment type? (e.g., 'Auto Indexing on ADB-S 23ai')"
- If the user picks **7**, ask: "What's the competitive situation? (e.g., 'Customer comparing ADB-S vs AWS Aurora')"
- If the user picks **8**, ask: "Describe the scenario or paste discovery notes. I'll build the business case. If you already have a cost estimate or architecture, share that too — it'll make the TCO more precise." Then follow the business case flow:
1. Parse input into `templates/business-case.yaml` structure
2. Identify business drivers and urgency from discovery notes
3. Estimate TCO comparison using `kb/pricing/*` and `kb/sizing/*`
3. Estimate TCO comparison using `kb/pricing/oci-sku-catalog.yaml` (live SKU prices), `kb/pricing/compute.yaml` (shape-level), `kb/field-knowledge/pricing-knowledge.yaml` (billing models, BYOL rules, free tiers), and `kb/sizing/*`
4. Calculate ROI and payback period
5. Map value drivers (cost, risk, agility, innovation) with quantified evidence
6. Assess migration risks from `kb/field-knowledge/gotchas.yaml` and do-nothing risks
@@ -175,77 +158,30 @@ Pick a number, or just describe what you need.
- Present the formatted terminal scorecard (primary deliverable)
8. Output the ECAL Readiness Scorecard
**Scoring Model:**
Each artefact has a status: ✅ Complete | 🟡 Partial | ❌ Missing | ⬜ Not Applicable (future phase)
**Scoring model, readiness levels, and output format:** see [docs/skill/ecal-readiness-format.md](docs/skill/ecal-readiness-format.md) for the scoring weights, the terminal scorecard layout, and the after-scorecard menu. Read that file before producing the scorecard.
Phase scores are calculated as:
- ✅ = 1.0 point, 🟡 = 0.5 point, ❌ = 0 points, ⬜ = excluded from denominator
- Phase score = (sum of points / applicable artefacts) × 100%
- If the user picks **13**, ask: "What services does the customer need? (e.g., 'ExaCS X11M BYOL 2 DB servers + 4 storage + 128 ECPUs + ADB-S 8 ECPU + 2TB Block Storage + FastConnect 1Gbps'). I'll generate the BOM with only those SKUs."
Then follow the BOM generation flow:
1. Parse the customer request to identify needed OCI services and quantities
2. Match services against `kb/pricing/oci-sku-catalog.yaml` (live, auto-refreshed) to select exact SKUs
3. Ask for discount % and contract duration if not specified (default: 0%, 12 months)
4. Ask if currency conversion is needed (e.g., USD→BRL with exchange rate and tax)
5. Generate the BOM spec YAML and save to the output folder
6. Run `tools/oci_bom_gen.py` to produce the .xlsx
7. Present a summary table in the terminal showing key totals (monthly, ARR)
8. List the files generated
Overall ECAL Readiness = weighted average:
- DEFINE: 25% weight
- DESIGN: 50% weight (largest phase, most artefacts)
- DELIVER: 25% weight
**BOM Output Rules:**
- NEVER include "Confidential: Internal ONLY" or any confidentiality marking
- ALWAYS include the Oracle Cost Estimator disclaimer at the bottom
- Only include SKUs the customer actually requested — never dump the full catalog
- Show cost proportions so the customer can see where their spend concentrates
- Use Excel formulas (not static values) so the customer can adjust quantities
**Readiness Levels:**
- 🟢 80-100% — Ready to proceed to next phase
- 🟡 60-79% — Gaps exist but manageable; proceed with caution
- 🟠 40-59% — Significant gaps; address before proceeding
- 🔴 0-39% — Major gaps; phase needs substantial work
**Output Format:**
The ECAL readiness score MUST produce **two layers of output**: (a) the formatted terminal scorecard shown to the user, and (b) the structured YAML file saved to disk. The terminal output is the primary deliverable — the YAML is the backing data. Never produce YAML-only output without the formatted scorecard.
```
══════════════════════════════════════════
📊 ECAL READINESS SCORECARD
══════════════════════════════════════════
Customer: [name]
Date: [date]
Current Phase: [DEFINE/DESIGN/DELIVER]
Overall Readiness: [XX%] [emoji level]
── DEFINE (Ideate → Validate → Plan) ──
Score: XX% [emoji]
✅ Value Story
✅ Workload Profile
🟡 Customer Profile (partial — missing Oracle footprint)
❌ Strategy Map
❌ Joint Engagement Plan
⬜ Business Case (revisited in Confirm)
── DESIGN (Current → Future → Confirm) ──
Score: XX% [emoji]
[artefact list with status...]
── DELIVER (Adopt → Operate → Improve) ──
Score: XX% [emoji]
[artefact list with status...]
── TOP 5 GAPS ──
1. ❌ [artefact] — [why it matters] — [recommended action]
2. ...
── RECOMMENDED NEXT ACTIONS ──
1. [specific action]
2. [specific action]
3. [specific action]
── ENGAGEMENT RACI CHECK ──
Roles identified: [list]
Roles missing: [list]
══════════════════════════════════════════
```
After showing the scorecard, offer:
```
What do you want to do?
→ [A] Fix the top gap now (I'll generate the missing artefact)
→ [B] Generate all missing artefacts for current phase
→ [C] Export scorecard as a slide
→ [D] Re-score after updates
```
- If the user picks **14**, follow the same flow as option 13 (BOM generator) but generate the output in AppCA import format. AppCA is Oracle's internal deal approval tool. The generated .xlsx has two sheets:
- **"Export to AppCA"**: Flat table with columns SKU, QTY, HOURS, MONTHS, DISCOUNT, BURSTABLE — ready to paste/import into AppCA
- **"BOM.C1"**: Full BOM detail with product names, metrics, prices, and formulas for cost calculations
Run with: `python tools/oci_bom_gen.py --spec <spec>.yaml --output <name>.xlsx --appca`
- If the user sends discovery notes directly (without picking a number), detect this and go straight to option 1 (full proposal flow).
- If the user asks a specific question (e.g., "does ADB-S support vector search?"), detect this and go straight to the relevant capability without showing the menu.
@@ -418,159 +354,19 @@ Every skill option that produces output MUST generate **readable, human-consumab
- **Options 1-4, 8:** Primary output is `.pptx` (slide deck) and/or `.drawio` (diagram). YAML specs are saved alongside but never presented as the deliverable.
- **Option 5 (WA Review):** Primary output is the **formatted terminal scorecard** (banner + pillar bars + gap tables + recommendations). YAML scorecard saved to `examples/` as backing data.
- **Option 12 (ECAL Readiness):** Primary output is the **formatted terminal scorecard** (phase scores + artefact checklist + gap analysis). YAML scorecard saved to `examples/` as backing data.
- **After any review/score:** When the user picks [C] "Export as slide", generate a 1-2 slide `.pptx` with the scorecard visualization using `tools/oci_deck_gen.py`.
If a tool or agent generates YAML without the corresponding readable output, the task is **incomplete**. Always present the formatted result, then list the files saved.
### Output Directory Convention
### Output directory, slide deck structure, format options, service categorization
All generated files MUST be saved inside a dedicated output folder per customer/initiative:
```
examples/output-<customer>-<initiative>/
```
Examples:
- `examples/output-meli-im06/` — MELI MySQL engagement
- `examples/output-meli-im30/` — MELI ElasticSearch engagement
- `examples/output-acme-migration/` — ACME cloud migration
This folder contains ALL outputs for that engagement: `.pptx`, `.drawio`, `.yaml` specs, `.pdf`, scorecards. The folder is gitignored via `examples/output-*/` — never commit customer data.
YAML spec files (architecture, workload-profile, diagram-spec) are saved IN the output folder, not loose in `examples/`. This keeps everything grouped and portable.
Default output is a **slide deck (.pptx)**. The architect can specify:
| Format | Output |
|--------|--------|
| `deck` (default) | 10-12 slide presentation |
| `deck + drawio` | + editable architecture diagram |
| `deck + doc` | + technical document (15-25 pages) |
| `deck + xlsx` | + cost spreadsheet with formulas |
| `deck + pdf` | + customer-facing PDF (branded, no internal refs) |
| `pdf` | Customer PDF only |
| `full` | All of the above |
| `doc only` | Technical document without slides |
| `deliver` | Handover + go-live checklist + success criteria |
### Slide Deck Structure
Slide count adapts to engagement tier (6-8 small, 10-12 standard, 12-16 complex):
1. **Title** — customer, project, date (dark background)
2. **Value Story** — business driver, hypothesis, desired outcomes
3. **Service Tiering** — workload-to-tier mapping (Platinum/Gold/Silver/Bronze) with SLA, RTO/RPO
4. **Architecture Principles** — selected ECAL principles (Design/Deployment/Service) that govern the architecture
5. **Architecture Diagram** — fills 85% of slide
6. **Architecture Decisions** — 4-6 key decisions with rationale
7. **HA/DR** — topology + RTO/RPO per tier
8. **Security & Compliance** — controls grid, compliance badges
9. **Environment Catalogue** — Prod/Pre-Prod/Dev-Test/DR per workload with sizing and isolation
10. **Cost Estimate** — PAYG vs BYOL table with assumptions (all environments)
11. **Cost Comparison** (optional) — vs current state or competitor
12. **Migration Approach** — phased timeline, tools, downtime strategy
13. **Operational RACI** — responsibility matrix (customer vs Oracle/partner)
14. **Risk Register** — severity-coded risk table
15. **Well-Architected Scorecard** — 5-pillar traffic-light indicators
16. **Next Steps** — concrete SMART actions with dates
Use `tools/oci_deck_gen.py` for generation. Colors: teal `#2D5967`, copper `#AA643B`, purple `#804998`. Font: Segoe UI. Design standards: `config/output-formats.yaml`.
### Architecture Diagram
Use `tools/oci_diagram_gen.py` with OCI official styles from `kb/diagram/oci-toolkit-styles.yaml`. Containers, service blocks, connections, and typography rules are defined there.
---
## Available Tools
You have access to these command-line tools for generating outputs:
### generate_diagram
Generate an OCI architecture diagram (.drawio) from a YAML spec.
```bash
python tools/oci_diagram_gen.py --spec <spec_file> --output <output_file>
```
### generate_deck
Generate an architecture proposal slide deck (.pptx) from a YAML spec.
```bash
python tools/oci_deck_gen.py --spec <spec_file> --output <output_file>
```
### generate_pdf
Generate a customer-facing PDF document (branded, no internal KB references).
```bash
python tools/oci_pdf_gen.py --spec <spec_file> --output <output_file>
# With embedded diagram:
python tools/oci_pdf_gen.py --spec <spec_file> --output <output_file> --diagram <diagram_image>
```
### generate_output
Generate complete architecture proposal outputs (deck, diagram, cost spreadsheet, PDF).
```bash
python tools/oci_output.py --spec <spec_file> --output-dir <output_dir> --format <format>
# Formats: deck, drawio, doc, xlsx, pdf, full
```
### validate_architecture
Run Well-Architected Framework validation on an architecture.
```bash
python scripts/validate-architecture.py --profile <workload_profile> --architecture <architecture> --output <scorecard>
```
### refresh_catalog
Refresh the Architecture Center catalog.
```bash
python tools/refresh_arch_catalog.py --whats-new # crawl What's New pages
python tools/refresh_arch_catalog.py --url <url> # add single entry
python tools/refresh_arch_catalog.py --validate # validate catalog
```
---
## Service Categorization
| Category | Color | Use |
|----------|-------|-----|
| **Infrastructure** | Teal `#2D5967` | Compute, OKE, LB, Gateways, WAF, Bastion, Storage, Monitoring |
| **Database** | Copper `#AA643B` | ADB-S/D, DBCS, ExaCS, MySQL, PostgreSQL, NoSQL, GoldenGate |
| **Integration** | Purple `#804998` | DRG, Streaming, Queue, OIC, FastConnect, Service Connector Hub |
| **Dormant** | Light gray `#DFDCD8` | Standby/inactive resources (DR tier) |
| **Legacy** | Medium gray `#70665E` | Non-OCI systems (MQ Series, legacy middleware) |
See [docs/skill/output-formats.md](docs/skill/output-formats.md) for the per-customer output folder convention, the complete format option matrix, the 16-slide deck structure, the diagram generation rules, and the service-to-color mapping.
---
## Knowledge Base
```
kb/
├── architecture-center/ # Oracle Architecture Center reference catalog
│ └── catalog.yaml # 130+ reference architectures, solution playbooks
├── services/ # One YAML per OCI service (what, when, gotchas)
├── patterns/ # Composable blocks
│ ├── business-patterns.yaml # Business-level patterns (DEFINE)
│ ├── application-patterns.yaml # Application architecture patterns (DESIGN)
│ ├── service-tiering.yaml # Service tier definitions
│ ├── architecture-principles.yaml # ECAL architecture principles
│ ├── operational-raci.yaml # RACI matrix templates
│ ├── engagement-raci.yaml # ECAL engagement RACI (10 roles)
│ ├── business-drivers.yaml # 4-pillar business drivers
│ ├── ecal-artefacts-catalog.yaml # Complete ECAL 3.1 artefacts (60 items)
│ ├── environment-catalogue.yaml # Environment templates per tier
│ ├── database-ha/ # Database HA patterns
│ ├── database-dr/ # Database DR patterns
│ ├── networking-*/ # Networking patterns
│ ├── compute-scaling/ # Compute auto-scaling
│ ├── security-baseline/ # Security controls
│ └── compliance-pci/ # PCI-DSS compliance
├── sizing/ # CPU conversion ratios, IOPS, scaling rules
├── pricing/ # Simplified pricing for estimation
├── competitive/ # AWS/Azure/GCP service mapping
├── well-architected/ # 5-pillar validation checklists
├── diagram/ # OCI Toolkit styles and reference layouts
├── compatibility/ # Feature matrices (ADB, etc.)
└── field-knowledge/ # Real-world gotchas and lessons learned
```
KB lives under `kb/`. See [kb/README.md](kb/README.md) for the directory map, frontmatter requirements, refresh tooling, and contributor guide.
---
@@ -579,12 +375,8 @@ kb/
| Template | Phase | Purpose |
|----------|-------|---------|
| `workload-profile.yaml` | DEFINE | Discovery capture |
| `customer-profile.yaml` | DEFINE | Strategic customer profiling |
| `strategy-map.yaml` | DEFINE | Goals→Strategies→Capabilities→Enablers |
| `value-story.yaml` | DEFINE | Business value hypothesis |
| `joint-engagement-plan.yaml` | DEFINE | Engagement scoping |
| `business-case.yaml` | DEFINE | Business case for approval |
| `discovery-questionnaire.yaml` | DESIGN | Structured IT collection |
| `operations-model.yaml` | DESIGN | Day-2 operations design |
| `scorecard.yaml` | DESIGN | WA validation results |
| `adr-template.md` | DESIGN | Architecture Decision Records |
@@ -604,6 +396,24 @@ kb/
- Present trade-offs explicitly. Let the architect decide.
- Produce the **minimum needed** for the engagement tier — don't pad.
### Minimal Output — Work Silently
**Do NOT narrate your internal process.** The architect does not need a play-by-play of what you are doing. Specifically:
- **Do NOT** announce each file you are about to read ("Let me check the service catalog...", "Reading the pricing file...").
- **Do NOT** list the KB files, templates, or patterns you are consulting.
- **Do NOT** describe intermediate reasoning steps ("First I'll parse your notes, then I'll...", "Now I'm matching services against the catalog...").
- **Do NOT** echo back the user's input as a summary before starting work.
- **Do NOT** show progress updates for sub-steps ("Step 1 done, moving to step 2...").
**What TO show:**
- Clarifying questions (when input is ambiguous or incomplete).
- The pre-generation review (component confirmation before generating artifacts).
- The final deliverable (scorecard, deck summary, file list, next-step menu).
- Errors or blockers that require the architect's input.
**In short:** Go from input → clarifying question (if needed) → pre-generation confirmation → final output. Skip everything in between. The architect cares about results, not process.
---
## Guardrails
@@ -635,17 +445,3 @@ kb/
- You do NOT claim features exist if you're unsure. Check the KB first.
- You do NOT do detailed project management. DELIVER artifacts are lightweight handover aids.
- You do NOT add services or components the user did not request.
---
## Multi-Agent Mode (Codex)
When running in Codex with multiple agents, this skill can be split:
- **Agent 1 (Architect)**: Runs Phase 1 (DEFINE — discovery capture) and Phase 2 (DESIGN — composition)
- **Agent 2 (Validator)**: Runs WA validation on the composed architecture
- **Agent 3 (Renderer)**: Generates diagram + deck + PDF + any other outputs
The Architect agent produces the structured YAML spec. The Validator annotates it with WA findings. The Renderer consumes the annotated spec and produces files.
Each agent reads the same KB but focuses on its phase. The orchestrating agent (or the user) coordinates handoffs.

20
.claude/settings.json Normal file
View File

@@ -0,0 +1,20 @@
{
"permissions": {
"allow": [
"Read(**)",
"Write(examples/**)",
"Write(output/**)",
"Bash(python3.12:*)",
"Bash(python3:*)",
"Bash(.venv/bin/python:*)",
"Bash(make:*)",
"Bash(git:*)",
"Bash(pip:*)",
"Bash(pip3:*)",
"Bash(pip3.12:*)",
"Bash(ls:*)",
"Bash(which:*)",
"Bash(find:*)"
]
}
}

View File

@@ -60,7 +60,54 @@
"Bash(PYTHONPATH=/tmp/pptx_ok python3 -c \"from pptx import Presentation; print\\(''''OK''''\\)\")",
"Bash(PYTHONPATH=/tmp/pptx_ok python3 /tmp/migrate_to_oracle.py)",
"Bash(PYTHONPATH=/tmp/pptx_ok python3 -c \"\nfrom pptx import Presentation\nprs = Presentation\\('/mnt/c/Users/Diego/Documents/oci-deal-accelerator/oci-deal-accelerator/templates/Oracle_PPT-template_FY26.pptx'\\)\nprint\\('Template has {} existing slides'.format\\(len\\(prs.slides\\)\\)\\)\n\")",
"Bash(grep:*)"
"Bash(grep:*)",
"Bash(ls \"/mnt/c/Users/Diego/Documents/oci-deal-accelerator-oracle/oci-deal-accelerator/templates/Oracle_PPT\"*)",
"Bash(ls \"/mnt/c/Users/Diego/Documents/oci-deal-accelerator-oracle/oci-deal-accelerator/templates/\"*.pptx)",
"Bash(ls \"/mnt/c/Users/Diego/Documents/oci-deal-accelerator-oracle/oci-deal-accelerator/templates/\"*.potx)",
"Bash(python3.12 -c \"import drawpyo\")",
"Bash(python3.12 tools/oci_diagram_gen.py --spec examples/output-meli-kvs/diagram-spec.yaml --output examples/output-meli-kvs/architecture.drawio)",
"Bash(python3.12 tools/oci_pdf_gen.py --spec examples/output-meli-kvs/proposal-spec.yaml --output examples/output-meli-kvs/customer-proposal.pdf)",
"Bash(python3.12 -c \":*)",
"Bash(python3.12 tools/oci_deck_gen.py --spec examples/output-meli-kvs/proposal-spec.yaml --output examples/output-meli-kvs/architecture-proposal.pptx)",
"Bash(python3.12 tools/oci_bizcase_gen.py --spec examples/output-meli-kvs/business-case.yaml --output examples/output-meli-kvs/business-case.pptx)",
"Bash(python3 -c \":*)",
"WebFetch(domain:github.com)",
"Bash(curl -s --max-time 15 -H \"X-Oracle-Accept-CurrencyCode: USD\" \"https://itra.oraclecloud.com/itas/.anon/myservices/api/v1/products?limit=2&partNumber=B110627\")",
"Bash(curl -v --max-time 10 -H \"X-Oracle-Accept-CurrencyCode: USD\" \"https://itra.oraclecloud.com/itas/.anon/myservices/api/v1/products?limit=1\")",
"Bash(curl -s --max-time 15 \"https://apexapps.oracle.com/pls/apex/cetools/api/v1/products/?partNumber=B110627&currencyCode=USD\")",
"Bash(find:*)",
"Bash(echo \"exit=$?\")",
"Bash(echo \"quiet exit=$?\")",
"Bash(make freshness:*)",
"Bash(echo \"freshness exit=$?\")",
"Bash(make help:*)",
"Bash(make lint:*)",
"Bash(curl -sS \"https://apexapps.oracle.com/pls/apex/cetools/api/v1/products/?currencyCode=USD\")",
"Bash(/bin/rm kb/pricing/ai-ml.yaml kb/pricing/analytics.yaml kb/pricing/containers-serverless.yaml kb/pricing/database.yaml kb/pricing/developer.yaml kb/pricing/hybrid-vmware.yaml kb/pricing/integration.yaml kb/pricing/networking.yaml kb/pricing/observability.yaml kb/pricing/pricing-models.yaml kb/pricing/security.yaml kb/pricing/storage.yaml)",
"Bash(python3.12 tools/oci_deck_gen.py --spec examples/proposal-spec.yaml --output examples/output-cli-improvements-deliverables/architecture-proposal.pptx)",
"Bash(python3.12 tools/oci_diagram_gen.py --spec examples/diagram-spec.yaml --output examples/output-cli-improvements-deliverables/architecture.drawio)",
"Bash(python3.12 tools/oci_pdf_gen.py --spec examples/proposal-spec.yaml --output examples/output-cli-improvements-deliverables/customer-proposal.pdf)",
"Bash(python3.12 tools/oci_bom_gen.py --spec examples/exacs-bom-spec.yaml --output examples/output-cli-improvements-deliverables/exacs-bom.xlsx)",
"Bash(python3.12 tools/oci_bom_gen.py --spec examples/exacs-x11m-bom-spec.yaml --output examples/output-cli-improvements-deliverables/exacs-x11m-bom.xlsx)",
"Bash(python3.12 tools/kb_cli.py search \"Autonomous Database\" --json)",
"Bash(python3.12 tools/findings_cli.py search \"adb\" --product ADB-S --json)",
"Bash(python3.12 tools/findings_cli.py stats --json)",
"Bash(python3.12 tools/kb_cli.py arch-search --services adb-s exacs --tags ha-dr --json)",
"Bash(python3.12 tools/kb_cli.py ecal-score --summary \"ADB-S migration with Data Guard business case architecture review customer profile strategy map handover go-live\" --json)",
"Bash(python3.12 tools/oci_bom_gen.py --spec examples/exacs-bom-spec.yaml --output examples/output-cli-improvements-deliverables/exacs-bom-appca.xlsx --appca)",
"Bash(python3.12 tools/oci_bom_gen.py --spec examples/exacs-x11m-bom-spec.yaml --output examples/output-cli-improvements-deliverables/exacs-x11m-bom-appca.xlsx --appca)",
"Bash(python3.12:*)",
"Bash(pip3.12 list:*)",
"Bash(pip3.12 install:*)",
"Bash(xargs ls:*)",
"WebFetch(domain:www.drawio.com)",
"WebFetch(domain:jgraph.github.io)",
"WebFetch(domain:raw.githubusercontent.com)",
"Bash(ls /root/.claude/projects/-mnt-c-Users-Diego-Documents-oci-deal-accelerator-oracle-oci-deal-accelerator/a0d00b4c-8d61-421c-8ba9-19bb85f15fdb/tool-results/*.zip)",
"WebFetch(domain:developers.openai.com)",
"Bash(echo \"---exit:$?---\")",
"Bash(date +%s)",
"Read(//tmp/**)"
]
}
}

21
.codex/config.toml Normal file
View File

@@ -0,0 +1,21 @@
# Codex project configuration for OCI Deal Accelerator
# Applies to every user who opens this project with Codex CLI.
# Allow the agent to run commands without per-command approval prompts.
approval_policy = "never"
# Workspace-write: agent can write inside the project root but not system-wide.
sandbox_mode = "workspace-write"
[sandbox_workspace_write]
# Allow network access so `pip install -r requirements.txt` and `make venv`
# can actually download dependencies. Without this, Codex blocks PyPI.
network_access = true
writable_roots = []
exclude_tmpdir_env_var = false
exclude_slash_tmp = false
[shell_environment_policy]
# Inherit the user's shell env so python3.12 / python3 resolution works
# the same way as the Makefile expects.
inherit = "all"

View File

@@ -0,0 +1,50 @@
# Auto-deploy OCI Deal Accelerator skill to MCP server on every push to main.
# Requires secrets: OCI_SSH_KEY (private key), OCI_HOST (DNS alias).
name: Deploy Skill to OCI
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.OCI_SSH_KEY }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
ssh-keyscan -H ${{ secrets.OCI_HOST }} >> ~/.ssh/known_hosts 2>/dev/null
- name: Sync skill to server
run: |
tar --exclude='.git' --exclude='.gitea' -czf /tmp/skill.tar.gz .
scp -i ~/.ssh/deploy_key /tmp/skill.tar.gz ubuntu@${{ secrets.OCI_HOST }}:/tmp/skill.tar.gz
ssh -i ~/.ssh/deploy_key ubuntu@${{ secrets.OCI_HOST }} '
rm -rf /home/ubuntu/oci-deal-accelerator-oracle/oci-deal-accelerator/*
tar -xzf /tmp/skill.tar.gz -C /home/ubuntu/oci-deal-accelerator-oracle/oci-deal-accelerator/
rm /tmp/skill.tar.gz
'
- name: Restart containers
run: |
ssh -i ~/.ssh/deploy_key ubuntu@${{ secrets.OCI_HOST }} '
cd /home/ubuntu/skills-platform &&
docker compose -f docker-compose.prod.yaml restart tools-service mcp-deal-accelerator
'
- name: Wait for healthy
run: |
ssh -i ~/.ssh/deploy_key ubuntu@${{ secrets.OCI_HOST }} '
timeout 60 bash -c "
until docker inspect --format=\"{{.State.Health.Status}}\" mcp-deal-accelerator 2>/dev/null | grep -q healthy; do
sleep 3
done
"
'

View File

@@ -0,0 +1,75 @@
# Weekly KB health check — validates catalog links and reports broken URLs.
# Runs Monday 8am UTC. Does NOT block deployments or affect user experience.
# If broken links found, creates a Gitea issue for manual review.
name: KB Health Check
on:
schedule:
- cron: '0 8 * * 1'
workflow_dispatch:
jobs:
check-links:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Python
run: |
apt-get update -qq
apt-get install -y --no-install-recommends python3 python3-requests python3-bs4 python3-yaml
python3 --version
- name: Check Architecture Center links
id: check
continue-on-error: true
run: |
python3 tools/refresh_arch_catalog.py --check-links 2>&1 | tee /tmp/link-check.txt
echo "exit_code=$?" >> $GITHUB_OUTPUT
- name: Check SKU catalog freshness
id: sku
continue-on-error: true
run: |
python3 tools/refresh_sku_catalog.py --validate 2>&1 | tee -a /tmp/link-check.txt
- name: Create issue if problems found
if: steps.check.outcome == 'failure'
run: |
BROKEN=$(grep -c "❌" /tmp/link-check.txt || echo "0")
REDIRECTED=$(grep -c "↪️" /tmp/link-check.txt || echo "0")
BODY=$(cat <<'ISSUE_EOF'
## KB Health Check — Broken Links Found
**Run date:** $(date -u +%Y-%m-%d)
**Broken:** $BROKEN URLs
**Redirected:** $REDIRECTED URLs
<details>
<summary>Full report</summary>
```
$(cat /tmp/link-check.txt)
```
</details>
### Action needed
- For 404s: remove entry or find new URL via `python tools/refresh_arch_catalog.py --whats-new`
- For redirects: update URL in `kb/architecture-center/catalog.yaml`
ISSUE_EOF
)
# Note: Gitea issue creation requires gitea CLI or API call
# For now, save report as artifact
echo "$BODY" > /tmp/kb-health-report.md
echo "::warning::$BROKEN broken links found in KB catalog"
- name: Upload report
if: always()
uses: actions/upload-artifact@v3
with:
name: kb-health-report
path: /tmp/link-check.txt
retention-days: 30

View File

@@ -0,0 +1,146 @@
# Monthly SKU catalog refresh.
#
# Runs on the 1st of each month at 09:00 UTC and on manual dispatch.
#
# Does two things:
# 1. `--refresh`: pulls latest PAYG prices from Oracle's public API,
# updates kb/pricing/oci-sku-catalog.yaml, and opens a PR if anything
# changed.
# 2. `--discover`: reports SKUs present in the API but absent from the
# catalog (filtered to serviceCategory values already curated).
# If new SKUs are found, opens a Gitea issue listing them by category
# for manual review.
#
# Token:
# Uses the auto-provisioned secrets.GITHUB_TOKEN (Gitea Actions provides this
# per-run, scoped to this repo, GitHub-Actions-compatible). No manual secret
# configuration required. The explicit `permissions:` block below grants the
# scopes needed to push a branch, open a PR, and open an issue.
name: SKU Catalog Refresh
on:
schedule:
- cron: '0 9 1 * *'
workflow_dispatch:
permissions:
contents: write
pull-requests: write
issues: write
jobs:
refresh-and-discover:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Python
run: |
apt-get update -qq
apt-get install -y --no-install-recommends python3 python3-requests python3-yaml jq
python3 --version
- name: Refresh prices from Oracle API
id: refresh
run: |
python3 tools/refresh_sku_catalog.py --refresh --diff 2>&1 \
| tee /tmp/refresh.log
if git diff --quiet kb/pricing/oci-sku-catalog.yaml; then
echo "changed=false" >> $GITHUB_OUTPUT
else
echo "changed=true" >> $GITHUB_OUTPUT
fi
- name: Discover missing SKUs
id: discover
run: |
python3 tools/refresh_sku_catalog.py --discover -v 2>&1 \
| tee /tmp/discover.log
NEW_COUNT=$(grep -oE '^[0-9]+ SKUs present in API' /tmp/discover.log \
| head -1 | awk '{print $1}' || echo "0")
echo "new_count=${NEW_COUNT:-0}" >> $GITHUB_OUTPUT
- name: Upload logs as artifact
if: always()
uses: actions/upload-artifact@v3
with:
name: sku-refresh-logs
path: |
/tmp/refresh.log
/tmp/discover.log
retention-days: 90
- name: Open PR with price updates
if: steps.refresh.outputs.changed == 'true'
env:
GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITEA_SERVER: ${{ github.server_url }}
GITEA_REPO: ${{ github.repository }}
run: |
DATE=$(date -u +%Y-%m-%d)
BRANCH="automation/sku-refresh-${DATE}"
git config user.name "sku-refresh-bot"
git config user.email "sku-refresh@automation.local"
git checkout -b "$BRANCH"
git add kb/pricing/oci-sku-catalog.yaml
git commit -m "chore(pricing): monthly SKU catalog refresh (${DATE})
Automated refresh from Oracle public pricing API.
See workflow artifact 'sku-refresh-logs' for the diff."
# Push using token auth
REMOTE=$(echo "$GITEA_SERVER/$GITEA_REPO.git" \
| sed "s#https://#https://sku-refresh-bot:${GITEA_TOKEN}@#")
git push "$REMOTE" "$BRANCH"
# Open PR via Gitea API
OWNER=$(echo "$GITEA_REPO" | cut -d/ -f1)
REPO=$(echo "$GITEA_REPO" | cut -d/ -f2)
curl -sS -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"${GITEA_SERVER}/api/v1/repos/${OWNER}/${REPO}/pulls" \
-d "$(jq -n \
--arg title "chore(pricing): monthly SKU refresh ${DATE}" \
--arg head "$BRANCH" \
--arg base "main" \
--arg body "$(printf 'Automated refresh — [refresh log artifact](../../actions).\n\n```\n%s\n```' \
"$(tail -40 /tmp/refresh.log)")" \
'{title:$title, head:$head, base:$base, body:$body}')"
- name: Open issue for new SKUs
if: steps.discover.outputs.new_count != '0'
env:
GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITEA_SERVER: ${{ github.server_url }}
GITEA_REPO: ${{ github.repository }}
NEW_COUNT: ${{ steps.discover.outputs.new_count }}
run: |
DATE=$(date -u +%Y-%m-%d)
OWNER=$(echo "$GITEA_REPO" | cut -d/ -f1)
REPO=$(echo "$GITEA_REPO" | cut -d/ -f2)
BODY=$(printf '## %s new SKUs detected in Oracle API\n\n**Detected:** %s\n\nThese SKUs are present in the Oracle public pricing API but not yet in `kb/pricing/oci-sku-catalog.yaml`. Filter: serviceCategory values already represented in our catalog (so only relevant families show up).\n\n### Full listing\n\n```\n%s\n```\n\n### Next step\n\nReview and add relevant entries to `kb/pricing/oci-sku-catalog.yaml` under the appropriate category block. After merging, prices will be picked up automatically on the next monthly refresh.\n' \
"$NEW_COUNT" "$DATE" "$(cat /tmp/discover.log)")
curl -sS -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"${GITEA_SERVER}/api/v1/repos/${OWNER}/${REPO}/issues" \
-d "$(jq -n \
--arg title "SKU catalog: ${NEW_COUNT} new SKUs to review (${DATE})" \
--arg body "$BODY" \
'{title:$title, body:$body, labels:["automation","sku-catalog"]}')"
- name: Summary
if: always()
run: |
echo "## SKU Refresh Summary" >> $GITHUB_STEP_SUMMARY
echo "- Catalog changed: ${{ steps.refresh.outputs.changed }}" >> $GITHUB_STEP_SUMMARY
echo "- New SKUs discovered: ${{ steps.discover.outputs.new_count }}" >> $GITHUB_STEP_SUMMARY

3
.gitignore vendored
View File

@@ -1,9 +1,11 @@
.venv/
__pycache__/
*.pyc
*.pyo
output/
*.pptx
!examples/sample-output/*.pptx
!templates/Oracle_PPT-template_FY26.pptx
# OCI Toolkit binary (download from Oracle, don't commit)
kb/diagram/OCI Library.xml
@@ -31,3 +33,4 @@ examples/*.yaml
# Exported PDFfiles
examples/*.pdf
examples/*.xlsx

View File

@@ -85,32 +85,39 @@ DEFINE (Ideate → Validate → Plan) → DESIGN (Current → Future → Confi
Phase details in `docs/` — skill references them via progressive disclosure.
## Environment Setup (MANDATORY before running tools)
```bash
make venv && source .venv/bin/activate
```
The Makefile auto-detects the best available Python (3.12 > 3.11 > 3.10 > python3).
**Always use `make <target>` to run tools.** For custom specs, activate the venv first.
### Codex sandbox note
This project ships `.codex/config.toml` which enables `network_access = true`
for the workspace-write sandbox. This is required so `make venv` can reach
PyPI. If you see `No matching distribution found for pyyaml`, the config file
is missing or Codex is ignoring it — re-open the project from its root so
Codex loads `.codex/config.toml`.
## Running Tools
```bash
# Generate slide deck (default output)
python tools/oci_deck_gen.py --spec examples/proposal-spec.yaml --output proposal.pptx
# Generate customer-facing PDF (branded, no internal KB refs)
python tools/oci_pdf_gen.py --spec examples/proposal-spec.yaml --output proposal.pdf
# Generate diagram
python tools/oci_diagram_gen.py --spec examples/diagram-spec.yaml --output arch.drawio
# Run WA validation
python scripts/validate-architecture.py \
--profile examples/sample-workload-profile.yaml \
--architecture examples/sample-architecture.yaml \
--output scorecard.yaml
# Output orchestrator (multiple formats at once)
python tools/oci_output.py --spec examples/proposal-spec.yaml --format full --output-dir output/
# Build automation
make help # show all commands
make full # generate all outputs
make validate # run WA validation
# Standard targets (recommended)
make deck # slide deck with sample spec
make diagram # architecture diagram
make full # all outputs (pptx + drawio + docx + xlsx + pdf)
make validate # WA validation
make lint # check YAML syntax
make venv # create/update virtual environment
# Custom specs (activate venv first)
python tools/oci_deck_gen.py --spec examples/proposal-spec.yaml --output proposal.pptx
python tools/oci_pdf_gen.py --spec examples/proposal-spec.yaml --output proposal.pdf
python tools/oci_diagram_gen.py --spec examples/diagram-spec.yaml --output arch.drawio
python tools/oci_output.py --spec examples/proposal-spec.yaml --format full --output-dir output/
```
## Output Formats

108
CLAUDE.md
View File

@@ -37,7 +37,9 @@ AI skill aligned with Oracle ECAL framework (Define → Design → Deliver) that
│ │ ├── networking-basic.yaml
│ │ └── (dirs: database-ha/, database-dr/, networking-hub-spoke/, etc.)
│ ├── sizing/ # CPU conversion ratios, IOPS, scaling rules
│ ├── pricing/ # Simplified pricing for estimation
│ ├── pricing/ # Auto-refreshed from Oracle public pricing API
│ │ ├── oci-sku-catalog.yaml # 200+ OCI SKUs across 20 categories (BOM source of truth)
│ │ └── compute.yaml # Shape-level estimation pricing
│ ├── competitive/ # AWS/Azure/GCP service mapping
│ ├── well-architected/ # 5-pillar WA Framework checklists
│ ├── compatibility/ # Feature matrices (ADB, etc.)
@@ -47,7 +49,9 @@ AI skill aligned with Oracle ECAL framework (Define → Design → Deliver) that
│ ├── oci_deck_gen.py # .pptx slide deck generator (DEFAULT output)
│ ├── oci_pdf_gen.py # .pdf customer-facing document (branded, no internal refs)
│ ├── oci_diagram_gen.py # .drawio diagram generator
│ ├── oci_bom_gen.py # .xlsx Bill of Materials generator (SA tool)
│ ├── oci_output.py # Output orchestrator
│ ├── refresh_sku_catalog.py # SKU catalog refresh from Oracle pricing API
│ └── refresh_arch_catalog.py # Architecture Center catalog refresh tool
├── scripts/ # Validation and utilities
│ └── validate-architecture.py # WA validation engine
@@ -72,7 +76,8 @@ AI skill aligned with Oracle ECAL framework (Define → Design → Deliver) that
│ ├── handover-document.yaml # DELIVER: Implementation handover
│ ├── go-live-checklist.yaml # DELIVER: Pre-cutover verification
│ ├── success-criteria.yaml # DELIVER: Post go-live metrics
── lessons-learned.yaml # DELIVER: Engagement retrospective
── lessons-learned.yaml # DELIVER: Engagement retrospective
│ └── bom-spec.yaml # SA TOOL: BOM input spec template
├── codex/ # Codex setup guide (README only)
└── examples/ # Example specs and generated outputs
```
@@ -105,38 +110,44 @@ doc only ← technical doc without slides
deliver ← handover + go-live checklist + success criteria
```
## Running Tools
## Environment Setup
Before running ANY Python tool, ensure dependencies are installed:
```bash
# Generate slide deck (default output)
make venv && source .venv/bin/activate
```
The Makefile auto-detects the best available Python (3.12 > 3.11 > 3.10 > python3).
**Always use `make <target>` to run tools** — this guarantees the correct Python with all dependencies.
## Running Tools
Prefer `make` targets. For custom specs, activate the venv first (`source .venv/bin/activate`), then use `python`:
```bash
# Standard targets (recommended)
make deck # slide deck with sample spec
make diagram # architecture diagram
make full # all outputs (pptx + drawio + docx + xlsx + pdf)
make validate # WA validation
make lint # check YAML syntax
make venv # create/update virtual environment
make freshness # check KB freshness
# Custom specs (activate venv first)
python tools/oci_deck_gen.py --spec examples/proposal-spec.yaml --output proposal.pptx
# Generate customer-facing PDF (branded, no internal KB refs)
python tools/oci_pdf_gen.py --spec examples/proposal-spec.yaml --output proposal.pdf
python tools/oci_pdf_gen.py --spec examples/proposal-spec.yaml --output proposal.pdf --diagram arch.png
# Generate diagram
python tools/oci_bom_gen.py --spec examples/bom-spec.yaml --output customer-bom.xlsx
python tools/oci_diagram_gen.py --spec examples/diagram-spec.yaml --output arch.drawio
# Run WA validation
python scripts/validate-architecture.py \
--profile examples/sample-workload-profile.yaml \
--architecture examples/sample-architecture.yaml \
--output scorecard.yaml
# Output orchestrator (multiple formats at once)
python tools/oci_output.py --spec examples/proposal-spec.yaml --format full --output-dir output/
# Refresh Architecture Center catalog
# KB maintenance (activate venv first)
python tools/refresh_sku_catalog.py --refresh # update all prices
python tools/refresh_sku_catalog.py --refresh --diff # update + show changes
python tools/refresh_sku_catalog.py --validate # check for stale prices
python tools/refresh_arch_catalog.py --whats-new # crawl What's New pages
python tools/refresh_arch_catalog.py --url <url> # add single entry
python tools/refresh_arch_catalog.py --validate # validate catalog
# Build automation
make help # show all commands
make full # generate all outputs
make validate # run WA validation
make lint # check YAML syntax
```
## Key Principles
@@ -148,12 +159,51 @@ make lint # check YAML syntax
- **KB is the moat** — field experience, not documentation regurgitation
- **ECAL-aligned** — Define → Design → Deliver with iterative checkpoints
## Coding Guidelines
### 1. Think Before Coding
Don't assume. Don't hide confusion. Surface tradeoffs.
- State your assumptions explicitly. If uncertain, ask.
- If multiple interpretations exist, present them — don't pick silently.
- If a simpler approach exists, say so. Push back when warranted.
- If something is unclear, stop. Name what's confusing. Ask.
### 2. Simplicity First
Minimum code that solves the problem. Nothing speculative.
- No features beyond what was asked.
- No abstractions for single-use code.
- No "flexibility" or "configurability" that wasn't requested.
- No error handling for impossible scenarios.
- If you write 200 lines and it could be 50, rewrite it.
### 3. Surgical Changes
Touch only what you must. Clean up only your own mess.
- Don't "improve" adjacent code, comments, or formatting.
- Don't refactor things that aren't broken.
- Match existing style, even if you'd do it differently.
- If you notice unrelated dead code, mention it — don't delete it.
- Remove imports/variables/functions that YOUR changes made unused.
- Every changed line should trace directly to the user's request.
### 4. Goal-Driven Execution
Define success criteria. Loop until verified.
- "Add validation" → write tests for invalid inputs, then make them pass.
- "Fix the bug" → write a test that reproduces it, then make it pass.
- "Refactor X" → ensure tests pass before and after.
- For multi-step tasks, state a brief plan with verification steps.
## Welcome Flow
When the user starts a conversation without providing discovery notes or a specific request (e.g., a greeting like "hola", "hey", or empty context), present the welcome message and capability menu defined in `SKILL.md` § Welcome Flow. Specifically:
When the user starts a conversation without providing discovery notes or a specific request (e.g., a greeting like "hola", "hey", or empty context):
1. Show the welcome banner and numbered capability menu from SKILL.md
2. Follow the behavior rules for each option (1-10)
3. After completing any task, offer the next-step menu (A-E)
**MANDATORY:** Use the `Read` tool to open `SKILL.md` and read the entire `## Welcome Flow` section **before** showing anything to the user. Reproduce the welcome banner and the 14-option capability menu **verbatim** from that file. Do NOT paraphrase, reorder, summarize, translate, or reconstruct the menu from memory, folder structure, or prior conversations. If `SKILL.md` cannot be read for any reason, tell the user instead of improvising a menu.
**Pre-flight check (also defined in SKILL.md):** Before showing the welcome message, run `make kb-check 2>/dev/null`. If `stale_count > 0`, follow the banner-and-prompt logic in SKILL.md § Welcome Flow → Pre-flight. If the tool errors, silently skip the banner — never block the user.
Then:
1. Show the welcome banner and numbered capability menu exactly as defined in SKILL.md (14 options across DESIGN & PROPOSE, VALIDATE & CHECK, STRATEGY & BUSINESS, KNOWLEDGE BASE, ECAL GOVERNANCE, SA TOOLS)
2. Follow the behavior rules in SKILL.md for each option (1-14)
3. After completing any task, offer the next-step menu (A-E) as defined in SKILL.md
4. If the user sends discovery notes directly, skip the menu and go straight to full proposal flow
5. If the user asks a specific question, skip the menu and answer directly

View File

@@ -1,8 +1,15 @@
# OCI Deal Accelerator — Build Automation
.PHONY: help install test validate example diagram deck full clean lint codex-package update-icons
.PHONY: help install test validate example diagram deck full clean lint codex-package update-icons freshness freshness-refresh sync-skill sku-discover
# Use venv if present, otherwise find best available python3
ifneq (,$(wildcard .venv/bin/python))
PYTHON ?= .venv/bin/python
else ifneq (,$(shell command -v python3.12 2>/dev/null))
PYTHON ?= python3.12
else
PYTHON ?= python3
endif
SPEC_DIR = examples
OUTPUT_DIR = examples/sample-output
@@ -10,7 +17,16 @@ help: ## Show this help
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | \
awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
install: ## Install Python dependencies
VENV_PYTHON := $(shell command -v python3.12 2>/dev/null || command -v python3.11 2>/dev/null || command -v python3.10 2>/dev/null || echo python3)
venv: ## Create virtual environment and install dependencies
@echo "Using $(VENV_PYTHON) to create venv..."
$(VENV_PYTHON) -m venv .venv
.venv/bin/pip install --upgrade pip
.venv/bin/pip install -r requirements.txt
@echo "Virtual environment ready. Run: source .venv/bin/activate"
install: ## Install Python dependencies (system-wide)
pip install -r requirements.txt
validate: ## Validate imports and configs
@@ -62,8 +78,25 @@ clean: ## Remove generated output files
rm -f examples/sample-output/*.xlsx
rm -f examples/sample-output/*.docx
lint: ## Check YAML files for syntax errors
lint: ## Check YAML files for syntax errors and validate SKILL.md sync
@echo "Checking YAML files..."
@find kb/ config/ examples/ -name '*.yaml' -exec $(PYTHON) -c \
"import yaml, sys; yaml.safe_load(open(sys.argv[1]))" {} \; \
"import yaml, sys; list(yaml.safe_load_all(open(sys.argv[1])))" {} \; \
-print 2>&1 | grep -v "^$$" || echo "All YAML files valid."
@echo "Checking SKILL.md sync..."
@$(PYTHON) scripts/sync-skill.py --check
sync-skill: ## Regenerate .agents/skills/oci-deal-accelerator/SKILL.md from root SKILL.md
@$(PYTHON) scripts/sync-skill.py
freshness: ## Report stale KB files (informational, never fails)
-@$(PYTHON) tools/kb_freshness.py --check
kb-check: ## KB freshness JSON (used by skill welcome-flow pre-flight)
@$(PYTHON) tools/kb_freshness.py --check --json
freshness-refresh: ## Run refresh tools for stale KB files that support automation
@$(PYTHON) tools/kb_freshness.py --auto-refresh
sku-discover: ## Report SKUs present in Oracle API but missing from oci-sku-catalog.yaml
@$(PYTHON) tools/refresh_sku_catalog.py --discover

View File

@@ -14,6 +14,40 @@ What normally takes an SA days of work (structuring notes, designing architectur
- **Multi-cloud aware** — supports hybrid/multi-cloud diagrams (AWS, Azure, GCP icons) and considers options like ADB Multicloud before recommending full migration
- **End-to-end coverage** — from discovery notes to go-live checklist, not just the architecture slide
## New user? Start here
The skill runs as a hosted MCP server. Connect once from your LLM client, sign in with Oracle SSO, and the tools are ready.
**1. Add the MCP server to your client:**
| Client | How |
|---|---|
| **Claude Code** | `claude mcp add --transport http oci-deal-accelerator "https://mcp.tech-lad.com/deal-accelerator/mcp/"` |
| **Codex** | `codex mcp add oci-deal-accelerator --url "https://mcp.tech-lad.com/deal-accelerator/mcp/"` |
| **Cursor** | Settings (Ctrl+Shift+J) → MCP → Add new MCP server → Name: `oci-deal-accelerator`, Type: `streamable-http`, URL: `https://mcp.tech-lad.com/deal-accelerator/mcp/` |
| **Claude Desktop** | Add to `claude_desktop_config.json`: `{ "mcpServers": { "oci-deal-accelerator": { "transport": "http", "url": "https://mcp.tech-lad.com/deal-accelerator/mcp/" } } }` |
| **Windsurf** | Settings → Cascade → MCP → Manual config: `{ "oci-deal-accelerator": { "serverUrl": "https://mcp.tech-lad.com/deal-accelerator/sse/" } }` |
**2. Trigger the connection** — type `/mcp` in Claude Code or Codex, or open any tool in Cursor / Claude Desktop / Windsurf. Your browser opens automatically.
**3. Pick one of two options in the browser:**
- **Sign in with Oracle SSO** — for existing users
- **Create a new account** — for new users (see step 4)
**4. New users — create an account** by clicking "Create a new account". This opens an OCI self-registration form (oracle.com emails only). Tips:
- Use your full Oracle email as User ID (e.g. `name@oracle.com`)
- Password must be 12+ chars, with an uppercase letter, a number, and a special character
- Password must NOT contain your name or username
**5. Verify your email**, then return to the browser and click **Sign in with Oracle SSO**.
**6. Done.** The MCP tools are now available in your client.
### Connection URLs
- **MCP (HTTP streamable):** `https://mcp.tech-lad.com/deal-accelerator/mcp/`
- **SSE (Windsurf only):** `https://mcp.tech-lad.com/deal-accelerator/sse/`
## What It Produces
From unstructured input (meeting notes, emails, Slack threads), the skill generates:
@@ -86,31 +120,27 @@ Any SA can contribute knowledge to the skill. The KB lives in `kb/` as editable
| **OCI service info** | `kb/services/<service>.yaml` | Create or edit the service YAML |
| **Architecture pattern** | `kb/patterns/` | Add YAML following existing format |
| **Architecture Center reference** | `kb/architecture-center/catalog.yaml` | `python tools/refresh_arch_catalog.py --url <url>` |
| **Updated pricing** | `kb/pricing/<category>.yaml` | Edit with data from [OCI Price List](https://www.oracle.com/cloud/price-list/) |
| **Updated pricing** | `kb/pricing/oci-sku-catalog.yaml` (SKUs) or `kb/pricing/compute.yaml` (shapes) | `python tools/refresh_sku_catalog.py --refresh` (SKUs) or `--refresh-domain compute` (shapes). Both auto-pull from the Oracle public pricing API. |
| **Feature compatibility** | `kb/compatibility/adb-feature-matrix.yaml` | Edit the matrix, mark `verified_in_field: true` |
| **Competitive comparison** | `kb/competitive/` | Add or edit YAML with real pros AND cons |
**Fastest path**: if you hit something in an engagement that another SA should know about, use menu option 11 (Report a field finding) — the skill walks you through the format and adds it to the tracker automatically.
### OCI Pricing (13 categories)
### OCI Pricing
Comprehensive pricing from the [OCI Price List](https://www.oracle.com/cloud/price-list/) covering compute, database, storage, networking, AI/ML, containers, integration, observability, developer, analytics, hybrid/VMware, and security services. Source date: 2025-09-11.
All pricing is auto-refreshed from the [Oracle public pricing API](https://apexapps.oracle.com/pls/apex/cetools/api/v1/products/?currencyCode=USD). No manually maintained pricing files.
```
kb/pricing/
├── compute.yaml # VMs, bare metal, GPU (B200/B300/H200/H100/A100/L40S)
├── database.yaml # ADB (ECPU), DBCS, ExaCS, MySQL, PostgreSQL, NoSQL, Redis
── storage.yaml # Block, object, file, data transfer
├── networking.yaml # LB, NLB, FastConnect, DNS, egress
├── ai-ml.yaml # GenAI, Data Science, Vision, Speech, Digital Assistant
├── containers-serverless.yaml # OKE, Functions, Container Instances
├── integration.yaml # OIC, API Mgmt, Streaming, Queue, GoldenGate
├── observability.yaml # Monitoring, Logging, APM, DR, Email
├── developer.yaml # APEX, Visual Builder, DevOps, Blockchain
├── analytics.yaml # OAC, Essbase, Big Data, Data Flow
├── hybrid-vmware.yaml # OCVS, Compute C@C, Managed Mac, Roving Edge
├── security.yaml # Access Governance, Vault, Cloud Guard
└── pricing-models.yaml # PAYG, UCM, Reserved, BYOL
├── oci-sku-catalog.yaml # 200+ SKUs across 20 categories — single source of truth
│ Refresh: python tools/refresh_sku_catalog.py --refresh
── compute.yaml # Shape-level estimation pricing (VMs, BM, GPU)
Refresh: python tools/refresh_sku_catalog.py --refresh-domain compute
kb/field-knowledge/pricing-knowledge.yaml
# Stable pricing context: billing models, BYOL rules,
free tiers, service nuances, hyperscaler comparisons.
Non-numeric — no refresh needed.
```
### DBExpert Database Services Catalog
@@ -135,6 +165,34 @@ During **Phase 2 (DESIGN)**, the skill automatically matches the proposed archit
python tools/refresh_arch_catalog.py --whats-new # crawl What's New pages
python tools/refresh_arch_catalog.py --url <url> # add a single entry
python tools/refresh_arch_catalog.py --validate # validate catalog integrity
python tools/refresh_arch_catalog.py --check-links # check for broken URLs (404s, redirects)
```
### KB Health & Freshness
The KB is automatically monitored for staleness and broken links:
| Check | How | When |
|---|---|---|
| **Broken links** | `python tools/refresh_arch_catalog.py --check-links` | Weekly (CI), or on demand |
| **Stale prices** | `python tools/refresh_sku_catalog.py --validate` | Weekly (CI), or on demand |
| **KB freshness** | `python tools/kb_freshness.py --check` | On skill startup (pre-flight) |
| **Diagram quality** | `python scripts/validate-diagram.py <file.drawio>` | After every diagram generation |
**Automated CI/CD:**
- **Deploy workflow** (`.gitea/workflows/deploy.yaml`) — auto-deploys to MCP server on every push to `main`
- **KB health workflow** (`.gitea/workflows/kb-health.yaml`) — runs every Monday 8am UTC, checks all catalog URLs and SKU freshness, reports broken links as artifacts
To run KB health manually:
```bash
# Check all 123 Architecture Center URLs for 404s
python tools/refresh_arch_catalog.py --check-links
# Fix broken links: re-crawl What's New for updated URLs
python tools/refresh_arch_catalog.py --whats-new
# Refresh stale pricing from Oracle API
python tools/refresh_sku_catalog.py --refresh --diff
```
### Feature Compatibility Matrix
@@ -300,12 +358,16 @@ python tools/oci_bizcase_gen.py --spec business-case.yaml --output business-case
# Architecture diagram
python tools/oci_diagram_gen.py --spec examples/diagram-spec.yaml --output arch.drawio
# Validate diagram quality (icon sizes, overlaps, container overflow)
python scripts/validate-diagram.py arch.drawio
# Output orchestrator (multiple formats at once)
python tools/oci_output.py --spec examples/proposal-spec.yaml --format full --output-dir output/
# Architecture Center catalog
python tools/refresh_arch_catalog.py --validate
python tools/refresh_arch_catalog.py --whats-new
python tools/refresh_arch_catalog.py --check-links
# Feature compatibility
python tools/feature_matrix_cli.py check "Auto Scaling" adb_s 23ai

436
SKILL.md
View File

@@ -1,5 +1,5 @@
---
name: OCI Deal Accelerator
name: oci-deal-accelerator
description: Compresses the OCI Solutions Architect's cycle from customer discovery to architecture proposal and delivery handover. Aligned with Oracle ECAL framework (Define, Design, Deliver). Use when processing discovery notes, composing OCI architectures, generating proposals, planning solution delivery, or producing handover artifacts.
---
@@ -15,6 +15,55 @@ You follow the **Oracle ECAL framework** (Define → Design → Deliver) to prod
When the user starts a conversation without providing discovery notes or a specific request, present the welcome message and capability menu.
### Pre-flight checks
Run these checks silently **before** showing the welcome message. **CRITICAL:** Never show command execution, tool output, or errors to the user. If any check fails, silently skip it and proceed to the welcome message. These checks are informational — they NEVER block the user.
#### Check 1: KB changelog banner
Read the file `kb/CHANGELOG.md` and extract the **most recent date and first bullet point**. If the file exists and has entries, prepend a one-line banner above the welcome message:
```
📢 KB updated (<date>): <first bullet summary>
```
Example: `📢 KB updated (Apr 14): Diagram generator calibrated from 37 Oracle ref architectures`
If the file is missing or empty, skip — no banner.
#### Check 2: Local repo updates (git users only)
Run `git fetch --dry-run origin main 2>/dev/null`. If the output contains any text (meaning there are remote commits not yet pulled), prepend this banner:
```
📢 KB updates available — run `git pull` to get latest prices and fixes.
```
If the command fails (not a git repo, no network, MCP deployment), silently skip. This check is only relevant for users running the skill from a local git clone.
#### Check 3: KB freshness
Run `make kb-check 2>/dev/null` and parse the JSON output. Behavior:
- **`stale_count == 0`** → no banner.
- **`stale_count > 0` and at least one file has `refreshable: true`** → prepend banner and ask inline:
```
⚠️ KB freshness: <N> file(s) outdated (oldest: <file> — <age_days>d).
<M> can be auto-refreshed. Refresh now? [y/N]
```
- `y` / `yes` / `` → run `make freshness-refresh`, then show menu.
- Anything else → show menu with one-line reminder: `⚠️ <N> KB file(s) stale — run make freshness-refresh later.`
- **`stale_count > 0` but no `refreshable: true`** → non-blocking info banner, then show menu directly:
```
⚠️ KB freshness: <N> file(s) need manual review (oldest: <file> — <age_days>d).
```
If `make kb-check` errors out (exit ≠ 0, missing make, missing Python, missing tool), **silently skip** — no error output, no banner, no mention of failure.
### Welcome Message
```
@@ -59,6 +108,11 @@ Present these options as a compact numbered list. Each option has a bold title f
─────────────────
12. 📊 ECAL readiness score — *60-artefact gap analysis*
SA TOOLS
─────────────────
13. 📦 BOM generator — *services + quantities → .xlsx Bill of Materials*
14. 📤 BOM for AppCA — *BOM → .xlsx ready to import into AppCA*
━━━━━━━━━━━━━━━━━━━━━━━
Pick a number, or just describe what you need.
```
@@ -80,74 +134,13 @@ Pick a number, or just describe what you need.
- Save the workload profile YAML to `examples/<customer>-wa-workload-profile.yaml`
6. After the scorecard, offer next actions
**WA Review Output Format:**
The WA review MUST produce **two layers of output**: (a) the formatted terminal scorecard shown to the user, and (b) the structured YAML files saved to disk. The terminal output is the primary deliverable — the YAML is the backing data. Never produce YAML-only output without the formatted scorecard.
```
══════════════════════════════════════════════════════
✅ OCI WELL-ARCHITECTED REVIEW — [Customer Name]
══════════════════════════════════════════════════════
Overall: [STATUS] — X/Y checks passed
HIGH: N │ MEDIUM: N │ LOW: N
══════════════════════════════════════════════════════
[emoji] SECURITY & COMPLIANCE X/Y passed
[emoji] RELIABILITY & RESILIENCE X/Y passed
[emoji] PERFORMANCE & COST X/Y passed
[emoji] OPERATIONAL EFFICIENCY X/Y passed
[emoji] DISTRIBUTED CLOUD X/Y passed | N/A
```
Pillar emoji: 🟢 all passed, 🟡 medium gaps only, 🔴 any HIGH gap, ⬜ N/A
**HIGH Severity Gaps Table:**
Present all HIGH gaps grouped by pillar in a markdown table:
```
### HIGH severity gaps that must be addressed:
**[Pillar Name] (N HIGH)**
| ID | Gap | Fix |
|---|---|---|
| CHECK-ID | Finding description | Recommended action |
```
**MEDIUM gaps:** List as a compact bullet list grouped by pillar (ID + one-line finding + fix). Skip the table format to keep it concise.
**LOW gaps:** Mention count only, list individual items only if ≤ 5.
**Analysis Section:**
After the gap tables, add a "Why so many gaps?" paragraph if total gaps > 20, explaining the root cause (e.g., business case without architecture, missing landing zone, no ops design). This contextualizes the score for the SA.
**Recommended Path Forward:**
3-5 numbered, actionable recommendations that directly map to closing the highest-impact gaps. Reference skill options where applicable (e.g., "Generate the architecture — option 1 or 2").
**Files Generated:**
Always list the files saved at the end of the review:
```
📁 Files saved:
- examples/<customer>-wa-scorecard.yaml
- examples/<customer>-wa-architecture.yaml
- examples/<customer>-wa-workload-profile.yaml
```
**After WA Review Menu:**
```
What do you want to do?
→ [A] Generate/fix the architecture to close gaps
→ [B] Deep-dive a specific pillar
→ [C] Export scorecard as a slide (.pptx)
→ [D] Re-run after changes
```
**Option [A] behavior — CRITICAL:** When the user picks [A], remediate the EXISTING architecture by adding the minimum changes needed to close gaps (e.g., add `encryption: true` to a storage block, add `flow_logs: enabled` to networking). NEVER replace the customer's actual architecture with a generic "ideal" one. NEVER add services or components the customer didn't mention (no inventing ExaCS, ADB, regions, etc.). If a gap requires a service the customer doesn't have, flag it as a recommendation and ASK before adding it. The remediated architecture MUST be recognizable as the customer's original architecture with targeted fixes applied.
**WA Review Output Format:** see [docs/skill/wa-review-format.md](docs/skill/wa-review-format.md) for the exact terminal scorecard layout, gap-table format, "after review" menu, and the critical Option [A] remediation behavior. Read that file before producing the scorecard.
- If the user picks **6**, ask: "What feature and deployment type? (e.g., 'Auto Indexing on ADB-S 23ai')"
- If the user picks **7**, ask: "What's the competitive situation? (e.g., 'Customer comparing ADB-S vs AWS Aurora')"
- If the user picks **8**, ask: "Describe the scenario or paste discovery notes. I'll build the business case. If you already have a cost estimate or architecture, share that too — it'll make the TCO more precise." Then follow the business case flow:
1. Parse input into `templates/business-case.yaml` structure
2. Identify business drivers and urgency from discovery notes
3. Estimate TCO comparison using `kb/pricing/*` and `kb/sizing/*`
3. Estimate TCO comparison using `kb/pricing/oci-sku-catalog.yaml` (live SKU prices), `kb/pricing/compute.yaml` (shape-level), `kb/field-knowledge/pricing-knowledge.yaml` (billing models, BYOL rules, free tiers), and `kb/sizing/*`
4. Calculate ROI and payback period
5. Map value drivers (cost, risk, agility, innovation) with quantified evidence
6. Assess migration risks from `kb/field-knowledge/gotchas.yaml` and do-nothing risks
@@ -185,84 +178,30 @@ Pick a number, or just describe what you need.
- Present the formatted terminal scorecard (primary deliverable)
8. Output the ECAL Readiness Scorecard
**Scoring Model:**
Each artefact has a status: ✅ Complete | 🟡 Partial | ❌ Missing | ⬜ Not Applicable (future phase)
**Scoring model, readiness levels, and output format:** see [docs/skill/ecal-readiness-format.md](docs/skill/ecal-readiness-format.md) for the scoring weights, the terminal scorecard layout, and the after-scorecard menu. Read that file before producing the scorecard.
Phase scores are calculated as:
- ✅ = 1.0 point, 🟡 = 0.5 point, ❌ = 0 points, ⬜ = excluded from denominator
- Phase score = (sum of points / applicable artefacts) × 100%
- If the user picks **13**, ask: "What services does the customer need? (e.g., 'ExaCS X11M BYOL 2 DB servers + 4 storage + 128 ECPUs + ADB-S 8 ECPU + 2TB Block Storage + FastConnect 1Gbps'). I'll generate the BOM with only those SKUs."
Then follow the BOM generation flow:
1. Parse the customer request to identify needed OCI services and quantities
2. Match services against `kb/pricing/oci-sku-catalog.yaml` (live, auto-refreshed) to select exact SKUs
3. Ask for discount % and contract duration if not specified (default: 0%, 12 months)
4. Ask if currency conversion is needed (e.g., USD→BRL with exchange rate and tax)
5. Generate the BOM spec YAML and save to the output folder
6. Run `tools/oci_bom_gen.py` to produce the .xlsx
7. Present a summary table in the terminal showing key totals (monthly, ARR)
8. List the files generated
Overall ECAL Readiness = weighted average:
- DEFINE: 25% weight
- DESIGN: 50% weight (largest phase, most artefacts)
- DELIVER: 25% weight
**BOM Output Rules:**
- NEVER include "Confidential: Internal ONLY" or any confidentiality marking
- ALWAYS include the Oracle Cost Estimator disclaimer at the bottom
- Only include SKUs the customer actually requested — never dump the full catalog
- Show cost proportions so the customer can see where their spend concentrates
- Use Excel formulas (not static values) so the customer can adjust quantities
**Readiness Levels:**
- 🟢 80-100% — Ready to proceed to next phase
- 🟡 60-79% — Gaps exist but manageable; proceed with caution
- 🟠 40-59% — Significant gaps; address before proceeding
- 🔴 0-39% — Major gaps; phase needs substantial work
**Output Format:**
The ECAL readiness score MUST produce **two layers of output**: (a) the formatted terminal scorecard shown to the user, and (b) the structured YAML file saved to disk. The terminal output is the primary deliverable — the YAML is the backing data. Never produce YAML-only output without the formatted scorecard.
```
══════════════════════════════════════════
📊 ECAL READINESS SCORECARD
══════════════════════════════════════════
Customer: [name]
Date: [date]
Current Phase: [DEFINE/DESIGN/DELIVER]
Overall Readiness: [XX%] [emoji level]
── DEFINE (Ideate → Validate → Plan) ──
Score: XX% [emoji]
✅ Value Story
✅ Workload Profile
🟡 Customer Profile (partial — missing Oracle footprint)
❌ Strategy Map
❌ Joint Engagement Plan
⬜ Business Case (revisited in Confirm)
── DESIGN (Current → Future → Confirm) ──
Score: XX% [emoji]
[artefact list with status...]
── DELIVER (Adopt → Operate → Improve) ──
Score: XX% [emoji]
[artefact list with status...]
── TOP 5 GAPS ──
1. ❌ [artefact] — [why it matters] — [recommended action]
2. ...
── RECOMMENDED NEXT ACTIONS ──
1. [specific action]
2. [specific action]
3. [specific action]
── ENGAGEMENT RACI CHECK ──
Roles identified: [list]
Roles missing: [list]
══════════════════════════════════════════
```
**Files Generated:**
Always list the files saved at the end of the scorecard:
```
📁 Files saved:
- examples/<customer>-ecal-scorecard.yaml
```
After showing the scorecard, offer:
```
What do you want to do?
→ [A] Fix the top gap now (I'll generate the missing artefact)
→ [B] Generate all missing artefacts for current phase
→ [C] Export scorecard as a slide (.pptx)
→ [D] Re-score after updates
```
- If the user picks **14**, follow the same flow as option 13 (BOM generator) but generate the output in AppCA import format. AppCA is Oracle's internal deal approval tool. The generated .xlsx has two sheets:
- **"Export to AppCA"**: Flat table with columns SKU, QTY, HOURS, MONTHS, DISCOUNT, BURSTABLE — ready to paste/import into AppCA
- **"BOM.C1"**: Full BOM detail with product names, metrics, prices, and formulas for cost calculations
Run with: `python tools/oci_bom_gen.py --spec <spec>.yaml --output <name>.xlsx --appca`
- If the user sends discovery notes directly (without picking a number), detect this and go straight to option 1 (full proposal flow).
- If the user asks a specific question (e.g., "does ADB-S support vector search?"), detect this and go straight to the relevant capability without showing the menu.
@@ -335,6 +274,32 @@ Full tier definitions and artifact matrix: [docs/engagement-tiers.md](docs/engag
**Step 1 — Ideate:** Parse discovery notes into a **Workload Profile** (`templates/workload-profile.yaml`). Formulate a value hypothesis: "If we [technical action], the customer achieves [business outcome]." Use `kb/patterns/business-patterns.yaml` for proven business-level patterns.
**Step 1b — Extraction Receipt (MANDATORY).** After parsing discovery notes, present an extraction receipt to the user BEFORE proceeding. This ensures the architecture is built on confirmed facts, not assumptions:
```
📋 Extraction Receipt
━━━━━━━━━━━━━━━━━━━━
From your input I extracted:
CONFIRMED (explicitly stated):
• [field]: [value] — source: "[exact quote or reference from notes]"
• [field]: [value] — source: "[exact quote or reference from notes]"
INFERRED (not stated, derived from context):
• [field]: [value] — reason: "[why I inferred this]"
MISSING (needed but not provided):
• [field] — needed for: [which artifact or decision needs it]
━━━━━━━━━━━━━━━━━━━━
Confirm, correct, or fill gaps before I proceed.
```
Rules:
- Every field in the workload profile that you populate must appear in either CONFIRMED or INFERRED.
- Do NOT proceed to Step 2 until the user confirms the receipt.
- If the user provides additional data, update the receipt and re-confirm.
- When generating the workload-profile.yaml, tag each field with `source: customer` (confirmed), `source: inferred`, or `source: default` so the SA knows what to validate with the customer.
**Step 2 — Validate:** Test the hypothesis for SMART criteria (Specific, Measurable, Attainable, Relevant, Time-based). Identify gaps. Check technical feasibility against `kb/services/` and `kb/compatibility/`.
**Step 3 — Service Tiering:** After parsing databases, assign each workload a tier (Platinum/Gold/Silver/Bronze) based on SLA requirements, compliance needs, and business criticality. Use the auto-assignment rules in `kb/patterns/service-tiering.yaml`. Present the assignment and ask the architect to confirm or adjust.
@@ -368,7 +333,7 @@ Capture enough about current state to architect the future. Frame the problem
1. **Select services** from `kb/services/` across the full OCI catalog
2. **Dimension each service** using `kb/sizing/` rules. For Oracle DBs, use AWR metrics if available. Apply conversion ratios. For ADB-S, size base OCPUs for P75.
3. **Compose topology** from `kb/patterns/` blocks. Check conflicts, add implied dependencies, apply compliance overlays. Use `kb/patterns/application-patterns.yaml` for workload-type guidance.
3. **Compose topology** from `kb/patterns/` blocks. Check conflicts and apply compliance overlays. Use `kb/patterns/application-patterns.yaml` for workload-type guidance. **Do NOT silently add components** — only add technical dependencies from the closed whitelist in the Guardrails section below. Everything else must be proposed as optional in the pre-generation review.
4. **Architecture Principles** — Select applicable principles from `kb/patterns/architecture-principles.yaml` based on the workload profile. Check `applies_when` conditions. Include in the deck as a governance slide.
5. **Environment Catalogue** — Expand each workload into environments (Prod/Pre-Prod/Dev-Test/DR) using the tier templates in `kb/patterns/environment-catalogue.yaml`. Apply cost optimization rules. Include in the deck and in the cost estimate.
6. **Design deployment** — environment strategy, IaC approach, CI/CD pipeline
@@ -391,6 +356,28 @@ Capture enough about current state to architect the future. Frame the problem
#### Confirm (Solution Proposal)
**Completeness gate (MANDATORY before generating artifacts).** Before calling any generation tool (deck, diagram, BOM, PDF), verify that critical fields are populated based on engagement tier:
| Field | Small | Standard | Complex |
|---|---|---|---|
| customer_name | required | required | required |
| workload_type | required | required | required |
| databases (type + count) | required | required | required |
| primary_region | required | required | required |
| compliance_frameworks | — | required | required |
| RTO / RPO | — | required | required |
| team_size | — | required | required |
| current_infrastructure | — | required | required |
| migration_driver | — | required | required |
| environment_strategy | — | — | required |
| operational_model | — | — | required |
| multi_region_topology | — | — | required |
| data_residency | — | — | required |
- If **required** fields are missing: ask the user before generating.
- If **optional** fields are missing: list them as assumptions in the output (e.g., "Assumed: PAYG pricing, single environment, no compliance requirements").
- Fields tagged `source: inferred` in the workload profile count as populated but should be flagged as assumptions.
Assemble all design work into a proposal. Ensure all propositions are **SMART**. Quality matters — it must look professional.
**Outputs by tier:** See artifact matrix in [docs/engagement-tiers.md](docs/engagement-tiers.md)
@@ -439,106 +426,23 @@ Every skill option that produces output MUST generate **readable, human-consumab
If a tool or agent generates YAML without the corresponding readable output, the task is **incomplete**. Always present the formatted result, then list the files saved.
### Output Directory Convention
### Output directory, slide deck structure, format options, service categorization
All generated files MUST be saved inside a dedicated output folder per customer/initiative:
```
examples/output-<customer>-<initiative>/
```
Examples:
- `examples/output-meli-im06/` — MELI MySQL engagement
- `examples/output-meli-im30/` — MELI ElasticSearch engagement
- `examples/output-acme-migration/` — ACME cloud migration
This folder contains ALL outputs for that engagement: `.pptx`, `.drawio`, `.yaml` specs, `.pdf`, scorecards. The folder is gitignored via `examples/output-*/` — never commit customer data.
YAML spec files (architecture, workload-profile, diagram-spec) are saved IN the output folder, not loose in `examples/`. This keeps everything grouped and portable.
Default output is a **slide deck (.pptx)**. The architect can specify:
| Format | Output |
|--------|--------|
| `deck` (default) | 10-12 slide presentation |
| `deck + drawio` | + editable architecture diagram |
| `deck + doc` | + technical document (15-25 pages) |
| `deck + xlsx` | + cost spreadsheet with formulas |
| `deck + pdf` | + customer-facing PDF (branded, no internal refs) |
| `pdf` | Customer PDF only |
| `full` | Everything (pptx + drawio + docx + xlsx + pdf) |
| `doc only` | Technical document without slides |
| `deliver` | Handover + go-live checklist + success criteria |
### Slide Deck Structure
Slide count adapts to engagement tier (6-8 small, 10-12 standard, 12-16 complex):
1. **Title** — customer, project, date (dark background)
2. **Value Story** — business driver, hypothesis, desired outcomes
3. **Service Tiering** — workload-to-tier mapping (Platinum/Gold/Silver/Bronze) with SLA, RTO/RPO
4. **Architecture Principles** — selected ECAL principles (Design/Deployment/Service) that govern the architecture
5. **Architecture Diagram** — fills 85% of slide
6. **Architecture Decisions** — 4-6 key decisions with rationale
7. **HA/DR** — topology + RTO/RPO per tier
8. **Security & Compliance** — controls grid, compliance badges
9. **Environment Catalogue** — Prod/Pre-Prod/Dev-Test/DR per workload with sizing and isolation
10. **Cost Estimate** — PAYG vs BYOL table with assumptions (all environments)
11. **Cost Comparison** (optional) — vs current state or competitor
12. **Migration Approach** — phased timeline, tools, downtime strategy
13. **Operational RACI** — responsibility matrix (customer vs Oracle/partner)
14. **Risk Register** — severity-coded risk table
15. **Well-Architected Scorecard** — 5-pillar traffic-light indicators
16. **Next Steps** — concrete SMART actions with dates
Use `tools/oci_deck_gen.py` for generation. Colors: teal `#2D5967`, copper `#AA643B`, purple `#804998`. Font: Segoe UI. Design standards: `config/output-formats.yaml`.
### Architecture Diagram
Use `tools/oci_diagram_gen.py` with OCI official styles from `kb/diagram/oci-toolkit-styles.yaml`. Containers, service blocks, connections, and typography rules are defined there.
See [docs/skill/output-formats.md](docs/skill/output-formats.md) for the per-customer output folder convention, the complete format option matrix, the 16-slide deck structure, the diagram generation rules, and the service-to-color mapping.
---
## Service Categorization
## Cookbook: Building Tool Payloads
| Category | Color | Use |
|----------|-------|-----|
| **Infrastructure** | Teal `#2D5967` | Compute, OKE, LB, Gateways, WAF, Bastion, Storage, Monitoring |
| **Database** | Copper `#AA643B` | ADB-S/D, DBCS, ExaCS, MySQL, PostgreSQL, NoSQL, GoldenGate |
| **Integration** | Purple `#804998` | DRG, Streaming, Queue, OIC, FastConnect, Service Connector Hub |
| **Dormant** | Light gray `#DFDCD8` | Standby/inactive resources (DR tier) |
| **Legacy** | Medium gray `#70665E` | Non-OCI systems (MQ Series, legacy middleware) |
Before mapping customer requirements to SKUs for `generate_bom`, `generate_bom_appca`, or `generate_cost_estimate`, check [docs/bom-cookbook.md](docs/bom-cookbook.md) — it has copy-paste recipes for common patterns (ExaCS X11M BYOL, ADB-Dedicated, ADB-S + Block + FastConnect) and explicitly names the gotchas that otherwise burn exploration turns (e.g. ADB-Dedicated shares infrastructure SKUs with ExaCS — there are no separate `adb_dedicated` SKUs in the catalog).
If a requirement does not match a recipe, `grep` [`kb/pricing/oci-sku-catalog.yaml`](kb/pricing/oci-sku-catalog.yaml) and consult `kb/services/` before inventing SKUs.
---
## Knowledge Base
```
kb/
├── architecture-center/ # Oracle Architecture Center reference catalog
│ └── catalog.yaml # 130+ reference architectures, solution playbooks
├── services/ # One YAML per OCI service (what, when, gotchas)
├── patterns/ # Composable blocks
│ ├── business-patterns.yaml # Business-level patterns (DEFINE)
│ ├── application-patterns.yaml # Application architecture patterns (DESIGN)
│ ├── service-tiering.yaml # Service tier definitions (Platinum/Gold/Silver/Bronze)
│ ├── architecture-principles.yaml # ECAL architecture principles (Design/Deployment/Service)
│ ├── operational-raci.yaml # RACI matrix templates (fully/co/self-managed)
│ ├── environment-catalogue.yaml # Environment templates per tier
│ ├── database-ha/ # Database HA patterns
│ ├── database-dr/ # Database DR patterns
│ ├── networking-*/ # Networking patterns
│ ├── compute-scaling/ # Compute auto-scaling
│ ├── security-baseline/ # Security controls
│ └── compliance-pci/ # PCI-DSS compliance
├── sizing/ # CPU conversion ratios, IOPS, scaling rules
├── pricing/ # Simplified pricing for estimation
├── competitive/ # AWS/Azure/GCP service mapping
├── well-architected/ # 5-pillar validation checklists
├── diagram/ # OCI Toolkit styles and reference layouts
├── compatibility/ # Feature matrices (ADB, etc.)
└── field-knowledge/ # Real-world gotchas and lessons learned
```
KB lives under `kb/`. See [kb/README.md](kb/README.md) for the directory map, frontmatter requirements, refresh tooling, and contributor guide.
---
@@ -568,27 +472,71 @@ kb/
- Present trade-offs explicitly. Let the architect decide.
- Produce the **minimum needed** for the engagement tier — don't pad.
### Minimal Output — Work Silently
**Do NOT narrate your internal process.** The architect does not need a play-by-play of what you are doing. Specifically:
- **Do NOT** announce each file you are about to read ("Let me check the service catalog...", "Reading the pricing file...").
- **Do NOT** list the KB files, templates, or patterns you are consulting.
- **Do NOT** describe intermediate reasoning steps ("First I'll parse your notes, then I'll...", "Now I'm matching services against the catalog...").
- **Do NOT** echo back the user's input as a summary before starting work.
- **Do NOT** show progress updates for sub-steps ("Step 1 done, moving to step 2...").
**What TO show:**
- Clarifying questions (when input is ambiguous or incomplete).
- The pre-generation review (component confirmation before generating artifacts).
- The final deliverable (scorecard, deck summary, file list, next-step menu).
- Errors or blockers that require the architect's input.
**In short:** Go from input → clarifying question (if needed) → pre-generation confirmation → final output. Skip everything in between. The architect cares about results, not process.
---
## Guardrails
- **Only what the user asked for.** Never add services, components, or features the user did not request — this includes observability (Monitoring, Logging, Events), security services (Data Safe, Vault, Cloud Guard, WAF), sizing details, connection types (RPC, peering), and any "nice to have" additions. Adding unrequested components wastes the architect's time and erodes trust.
- **Only what the user asked for.** Never add services, components, or features the user did not request — this includes observability (Monitoring, Logging, Events), security services (Data Safe, Vault, Cloud Guard, WAF), sizing details, connection types (RPC, peering), and any "nice to have" additions. Adding unrequested components wastes the architect's time and erodes trust. The ONLY exception is the closed whitelist of technical dependencies below.
- **Technical dependency whitelist (closed — nothing else is auto-added):**
| If the user requests… | Auto-include | Reason |
|---|---|---|
| FastConnect | DRG | FastConnect terminates on DRG — cannot work without it |
| VPN Connect | DRG | IPSec tunnels terminate on DRG |
| ADB-S / ExaCS with backup to Object Storage | Service Gateway | Backup traffic requires SGW for Oracle Services Network |
| Any service in a public subnet | Internet Gateway | Public subnet routing requires IGW |
| Any private subnet service needing internet egress | NAT Gateway | Private-to-internet routing requires NAT |
| Cross-region DR (Data Guard, FSDR) | Remote Peering Connection (RPC) | Cross-region VCN connectivity requires RPC on both DRGs |
Everything NOT in this table — including Monitoring, Logging, Events, Vault, Data Safe, WAF, Cloud Guard, Bastion, management subnets, compartment boundaries — requires explicit user approval via the pre-generation review.
- **Ask, don't guess.** When requirements are ambiguous or incomplete, ask a clarifying question instead of filling in assumptions. A 10-second question saves a 10-minute redo.
- **Pre-generation review.** Before generating any diagram or architecture artifact, confirm the component list with the user. Present what you understood and suggest optional additions they can approve or reject:
```
I'll generate a diagram with:
✅ [list of explicitly requested components]
Want me to also include any of these?
• Observability subnet
• Compartment boundaries
• Security services (Data Safe, Vault)
• Gateways (IGW, NAT, SGW)
• [other relevant options based on context]
Or just generate with the above?
- **MANDATORY pre-generation review.** Before generating ANY diagram, deck, or architecture artifact, you MUST confirm the component list with the user. Never skip this step. Present three clearly separated sections:
```
This takes 5 seconds to confirm and prevents rework.
I'll generate with:
REQUESTED (from your input):
✅ [only components explicitly mentioned by the user]
TECHNICAL DEPENDENCIES (auto-added per whitelist):
⚙️ [only items from the whitelist table above, with reason]
OPTIONAL — want me to add any of these?
○ Observability (Monitoring, Logging, Events)
○ Security services (Vault, Data Safe, WAF, Cloud Guard)
○ Management subnet
○ Compartment boundaries
○ Bastion / jump host
○ [other relevant options based on context]
Generate with the above, or adjust?
```
Wait for the user's response before generating. If the user says "just generate" or equivalent, proceed with only REQUESTED + TECHNICAL DEPENDENCIES (no optionals).
- **Source attribution.** When the user provides documents, URLs, meeting notes, or external data:
- Cite the source when extracting data: "From [document/source]: [extracted fact]"
- Clearly separate facts from the source vs. your own inferences
- If the source contradicts the internal KB, flag the conflict explicitly and let the architect decide
## What You Do NOT Do

View File

@@ -8,7 +8,10 @@
# Navigate to the project root
cd oci-deal-accelerator
# Run Codex — it auto-discovers AGENTS.md and .agents/skills/
# One-time: create virtual environment with all dependencies
make venv
# Run Codex — it auto-discovers AGENTS.md, .agents/skills/, and .codex/config.toml
codex
# Or explicitly load the skill
@@ -18,6 +21,18 @@ codex --skill oci-deal-accelerator
Codex automatically reads:
- `AGENTS.md` at project root (project-level instructions)
- `.agents/skills/oci-deal-accelerator/SKILL.md` (the skill definition)
- `.codex/config.toml` (project sandbox + approval config — **enables network for pip**)
### Why `.codex/config.toml` matters
By default Codex CLI blocks network access and prompts before every command.
The committed `.codex/config.toml` pre-configures this project with:
- `approval_policy = "never"` — no per-command prompts
- `sandbox_mode = "workspace-write"` — agent can write in the repo
- `network_access = true``pip install` and `make venv` actually work
Without this file, `make venv` fails with `No matching distribution found for pyyaml` because PyPI is unreachable from the sandbox.
### Option 2: Using Codex App

View File

@@ -28,7 +28,7 @@ review_triggers:
- event: "Oracle database version release"
action: "Review all feature matrix entries. Mark untested. Validate within 14 days."
- event: "Oracle pricing change"
action: "Update kb/pricing/ files. Verify cost calculator accuracy."
action: "Run python tools/refresh_sku_catalog.py --refresh and --refresh-domain compute. Both pull from the live Oracle pricing API."
- event: "After customer engagement"
action: "Run After-Engagement Review (AER). Add findings and KB updates."
- event: "Quarterly"

View File

@@ -20,15 +20,15 @@ domains:
review_cadence: "quarterly"
- area: "kb/compatibility/"
owner: { name: "TBD", team: "Database Specialists" }
owner: { name: "Diego Cabrera", team: "Field SA" }
review_cadence: "on Oracle version release + quarterly"
- area: "kb/pricing/"
owner: { name: "TBD", team: "Solution Engineering" }
review_cadence: "monthly (pricing changes frequently)"
owner: { name: "Auto-refreshed", team: "Oracle Public Pricing API" }
review_cadence: "automatic — refresh tools pull from the API on demand; freshness checker runs in welcome flow"
- area: "kb/competitive/"
owner: { name: "TBD", team: "Competitive Intelligence" }
owner: { name: "Diego Cabrera", team: "Field SA" }
review_cadence: "quarterly + on competitor announcements"
- area: "kb/field-findings/"
@@ -36,5 +36,5 @@ domains:
review_cadence: "continuous"
- area: "kb/well-architected/"
owner: { name: "TBD", team: "Cloud Architecture" }
owner: { name: "Diego Cabrera", team: "Field SA" }
review_cadence: "on Oracle WA Framework updates"

View File

@@ -12,6 +12,7 @@
---
taxonomy:
products:
- adb # generic ADB (covers both -s and -d)
- adb-s
- adb-d
- dep
@@ -26,6 +27,8 @@ taxonomy:
- goldengate
- data-safe
- vault
- rac
- proxysql
versions:
- 19c
@@ -44,6 +47,42 @@ taxonomy:
- sizing
- compliance
features:
- adg # Active Data Guard
- ai-vector-search
- vector-search
- hnsw # Hierarchical Navigable Small World indexes
- json
- partitioning
- refreshable-clone
- elastic-pool
- ecpu # ECPU billing model (vs OCPU)
- connection-pooling
- distributed
- immutable
- serialization
operations:
- cli
- maintenance-window
- provisioning
- planning
- lead-time
- capacity
- node-split
- zero-downtime
- bidirectional
- detection-delay
- stale-reads
metrics:
- latency
- 100m # 100 million scale (e.g. vector counts)
limitations:
- limitation
- sr-required # Service Request required to enable / fix
severity_tags:
- blocker
- workaround-available

190
docs/bom-cookbook.md Normal file
View File

@@ -0,0 +1,190 @@
# BOM Cookbook — Building `generate_bom` Payloads
Copy-paste recipes that map common customer requirements to the exact OCI SKUs the
`generate_bom`, `generate_bom_appca`, and `generate_cost_estimate` MCP tools expect.
The goal is to skip the "grep the catalog and guess SKUs" exploration loop that
burns tool calls on well-known patterns.
> **If the requirement does not match any recipe below, consult
> [`kb/services/`](../kb/services/) and
> [`kb/pricing/oci-sku-catalog.yaml`](../kb/pricing/oci-sku-catalog.yaml)
> before inventing SKUs.** All SKUs below are verified against the catalog as of
> 2026-04-20; re-`grep` the catalog if a recipe ever fails.
## Payload Shape
All three tools accept the same envelope:
```json
{
"customer_id": "acme-prod",
"discount_pct": 0.35,
"currency": "USD",
"services": [
{ "sku": "B90777", "quantity": 1 }
]
}
```
- `customer_id`: free-form identifier, used for output file naming.
- `discount_pct`: decimal (0.35 = 35%). Applied to every line unless overridden.
- `services[].quantity`: integer or float depending on the SKU metric (ECPUs, GB, hours).
---
## Recipe 1 — Exadata Cloud Service (ExaCS) X11M, BYOL
**When it matches:** "ExaCS X11M BYOL, N ECPUs, M TB storage, no DR" — customer-managed
Oracle Database on dedicated Exadata hardware, BYOL licensing.
**SKUs:**
| SKU | Component | Typical qty |
|-----|-----------|-------------|
| `B90777` | Exadata Infrastructure — Base System | `1` per rack |
| `B110627` | Exadata Database Server — X11M | `2` (Base/Quarter) — adjust per rack config |
| `B110629` | Exadata Storage Server — X11M | `3` (Base/Quarter) — adjust per rack config |
| `B110632` | Exadata Database ECPU — Dedicated Infra BYOL (X11M) | One per ECPU |
Swap `B110632``B110631` for PAYG (license-included) pricing.
**Payload (120 ECPUs, 120 TB, BYOL, standard Base System):**
```json
{
"customer_id": "acme-exacs",
"discount_pct": 0.35,
"currency": "USD",
"services": [
{ "sku": "B90777", "quantity": 1 },
{ "sku": "B110627", "quantity": 2 },
{ "sku": "B110629", "quantity": 3 },
{ "sku": "B110632", "quantity": 120 }
]
}
```
---
## Recipe 2 — Autonomous Database Dedicated (ADB-D), BYOL
**When it matches:** "ADB Dedicated, N ECPUs, M TB, BYOL" — Autonomous Database running
on dedicated Exadata infrastructure.
**⚠️ Gotcha that burns tool calls:** ADB-Dedicated has **no separate infrastructure
SKUs** in the catalog. It reuses the same Exadata dedicated infra SKUs as ExaCS
(`B90777`, `B110627`, `B110629`) plus the same Exadata ECPU SKU (`B110631`/`B110632`).
The Autonomous-vs-customer-managed distinction is a tenancy-level configuration,
not a billing line item. Do not search for `autonomous_dedicated` SKUs — they do
not exist.
**SKUs:** identical to Recipe 1.
**Payload (64 ECPUs, BYOL):**
```json
{
"customer_id": "acme-adbd",
"discount_pct": 0.35,
"currency": "USD",
"services": [
{ "sku": "B90777", "quantity": 1 },
{ "sku": "B110627", "quantity": 2 },
{ "sku": "B110629", "quantity": 3 },
{ "sku": "B110632", "quantity": 64 }
]
}
```
---
## Recipe 3 — Autonomous Database Serverless (ADB-S) + Block Volume + FastConnect
**When it matches:** "ADB-S ATP, N ECPUs, M TB data + block storage for app tier +
FastConnect to on-prem" — the typical "app on OCI Compute, DB on ADB-S" pattern.
**SKUs:**
| SKU | Component | Metric |
|-----|-----------|--------|
| `B95701` | ADB ECPU (ATP or ADW) — license-included | ECPU/hour |
| `B95703` | ADB ECPU BYOL — use instead of B95701 if BYOL | ECPU/hour |
| `B95706` | ADB ATP data storage | GB/month |
| `B95754` | ADB ADW data storage — use instead of B95706 for warehouse | GB/month |
| `B95754a` | ADB backup storage | GB/month |
| `B91961` | Block Volume storage (app tier) | GB/month |
| `B91962` | Block Volume performance (VPU) — optional, for higher IOPS tiers | VPU/GB/month |
| `B88326` | FastConnect 10 Gbps port | port-hour |
Swap `B88326``B88325` (1 Gbps) or `B93126` (100 Gbps) as needed.
**Payload (16 ECPUs ATP license-included, 2 TB data + 1 TB backup, 500 GB block, 10 G FastConnect):**
```json
{
"customer_id": "acme-adbs",
"discount_pct": 0.35,
"currency": "USD",
"services": [
{ "sku": "B95701", "quantity": 16 },
{ "sku": "B95706", "quantity": 2048 },
{ "sku": "B95754a", "quantity": 1024 },
{ "sku": "B91961", "quantity": 500 },
{ "sku": "B88326", "quantity": 1 }
]
}
```
---
## Recipe 4 — Big Data Service + Data Science + Data Flow (analytics stack)
**When it matches:** "HDFS-managed cluster for ETL", "notebooks + model deployment",
"managed Spark pipelines" — typical OCI analytics/AI workload mix.
**SKUs:**
| SKU | Component | Metric |
|-----|-----------|--------|
| `B91128` | Big Data Service — Compute Standard (real) | OCPU/hour |
| `B91129` | Big Data Service — Compute Dense I/O (real) | OCPU/hour |
| `B91130` | Big Data Service — Compute HPC (real) | OCPU/hour |
| `B93555` | Big Data Service — Core (real) | OCPU/hour |
| `EST-DS-NOTEBOOK` | **[Estimate]** Data Science notebook session — priced as underlying VM.Standard OCPU | OCPU/hour |
| `EST-DS-MODEL` | **[Estimate]** Data Science model-deployment endpoint — priced as underlying VM.Standard OCPU | OCPU/hour |
| `EST-DF-SPARK` | **[Estimate]** Data Flow managed Spark runtime — priced as underlying VM.Standard OCPU | OCPU/hour |
OCI Data Science and OCI Data Flow have no dedicated SKUs in the Oracle public
pricing API — both are billed via the underlying Compute shape + Block/Object
Storage consumed. The `EST-*` entries are placeholder estimates (VM.Standard3.Flex
OCPU rate) so BOMs can include them as line items with an explicit "estimate"
flag; confirm the actual shape and hours with the customer before quoting.
**Payload (16 BDS Standard + 8 BDS Dense I/O + 4 notebook + 2 model + 8 Spark):**
```json
{
"customer_id": "acme-analytics",
"discount_pct": 0.30,
"currency": "USD",
"services": [
{ "sku": "B91128", "quantity": 16 },
{ "sku": "B91129", "quantity": 8 },
{ "sku": "EST-DS-NOTEBOOK", "quantity": 4 },
{ "sku": "EST-DS-MODEL", "quantity": 2 },
{ "sku": "EST-DF-SPARK", "quantity": 8 }
]
}
```
Add `B91961` (Block Volume) and `B91628` (Object Storage Standard) when the
customer needs dedicated storage beyond the compute default.
---
## When a recipe doesn't fit
1. Grep the catalog: `grep -n "<product keyword>" kb/pricing/oci-sku-catalog.yaml`
2. Check service docs under `kb/services/` for deployment-specific guidance.
3. Check `kb/field-knowledge/` for known sizing/pricing gotchas.
4. If a SKU still cannot be located, surface the gap to the user rather than guessing — fabricated SKUs break the BOM silently.

View File

@@ -0,0 +1,88 @@
# ECAL Readiness Scorecard Format
This document defines how option 12 (ECAL Readiness Score) presents its results.
Referenced from `SKILL.md` § Welcome Flow → Behavior Rules → option 12.
## Scoring model
Each artefact has a status: ✅ Complete | 🟡 Partial | ❌ Missing | ⬜ Not Applicable (future phase).
Phase scores are calculated as:
- ✅ = 1.0 point, 🟡 = 0.5 point, ❌ = 0 points, ⬜ = excluded from denominator
- Phase score = (sum of points / applicable artefacts) × 100%
Overall ECAL Readiness = weighted average:
- DEFINE: 25% weight
- DESIGN: 50% weight (largest phase, most artefacts)
- DELIVER: 25% weight
## Readiness levels
- 🟢 80-100% — Ready to proceed to next phase
- 🟡 60-79% — Gaps exist but manageable; proceed with caution
- 🟠 40-59% — Significant gaps; address before proceeding
- 🔴 0-39% — Major gaps; phase needs substantial work
## Output format
The ECAL readiness score MUST produce **two layers of output**: (a) the formatted terminal scorecard shown to the user, and (b) the structured YAML file saved to disk. The terminal output is the primary deliverable — the YAML is the backing data. Never produce YAML-only output without the formatted scorecard.
```
══════════════════════════════════════════
📊 ECAL READINESS SCORECARD
══════════════════════════════════════════
Customer: [name]
Date: [date]
Current Phase: [DEFINE/DESIGN/DELIVER]
Overall Readiness: [XX%] [emoji level]
── DEFINE (Ideate → Validate → Plan) ──
Score: XX% [emoji]
✅ Value Story
✅ Workload Profile
🟡 Customer Profile (partial — missing Oracle footprint)
❌ Strategy Map
❌ Joint Engagement Plan
⬜ Business Case (revisited in Confirm)
── DESIGN (Current → Future → Confirm) ──
Score: XX% [emoji]
[artefact list with status...]
── DELIVER (Adopt → Operate → Improve) ──
Score: XX% [emoji]
[artefact list with status...]
── TOP 5 GAPS ──
1. ❌ [artefact] — [why it matters] — [recommended action]
2. ...
── RECOMMENDED NEXT ACTIONS ──
1. [specific action]
2. [specific action]
3. [specific action]
── ENGAGEMENT RACI CHECK ──
Roles identified: [list]
Roles missing: [list]
══════════════════════════════════════════
```
## Files generated
Always list the files saved at the end of the scorecard:
```
📁 Files saved:
- examples/<customer>-ecal-scorecard.yaml
```
## After ECAL scorecard menu
```
What do you want to do?
→ [A] Fix the top gap now (I'll generate the missing artefact)
→ [B] Generate all missing artefacts for current phase
→ [C] Export scorecard as a slide (.pptx)
→ [D] Re-score after updates
```

View File

@@ -0,0 +1,73 @@
# Output Formats and Conventions
Referenced from `SKILL.md` § Output Generation.
## Output directory convention
All generated files MUST be saved inside a dedicated output folder per customer/initiative:
```
examples/output-<customer>-<initiative>/
```
Examples:
- `examples/output-meli-im06/` — MELI MySQL engagement
- `examples/output-meli-im30/` — MELI ElasticSearch engagement
- `examples/output-acme-migration/` — ACME cloud migration
This folder contains ALL outputs for that engagement: `.pptx`, `.drawio`, `.yaml` specs, `.pdf`, scorecards. The folder is gitignored via `examples/output-*/` — never commit customer data.
YAML spec files (architecture, workload-profile, diagram-spec) are saved IN the output folder, not loose in `examples/`. This keeps everything grouped and portable.
## Format options
Default output is a **slide deck (.pptx)**. The architect can specify:
| Format | Output |
|--------|--------|
| `deck` (default) | 10-12 slide presentation |
| `deck + drawio` | + editable architecture diagram |
| `deck + doc` | + technical document (15-25 pages) |
| `deck + xlsx` | + cost spreadsheet with formulas |
| `deck + pdf` | + customer-facing PDF (branded, no internal refs) |
| `pdf` | Customer PDF only |
| `full` | Everything (pptx + drawio + docx + xlsx + pdf) |
| `doc only` | Technical document without slides |
| `deliver` | Handover + go-live checklist + success criteria |
## Slide deck structure
Slide count adapts to engagement tier (6-8 small, 10-12 standard, 12-16 complex):
1. **Title** — customer, project, date (dark background)
2. **Value Story** — business driver, hypothesis, desired outcomes
3. **Service Tiering** — workload-to-tier mapping (Platinum/Gold/Silver/Bronze) with SLA, RTO/RPO
4. **Architecture Principles** — selected ECAL principles (Design/Deployment/Service) that govern the architecture
5. **Architecture Diagram** — fills 85% of slide
6. **Architecture Decisions** — 4-6 key decisions with rationale
7. **HA/DR** — topology + RTO/RPO per tier
8. **Security & Compliance** — controls grid, compliance badges
9. **Environment Catalogue** — Prod/Pre-Prod/Dev-Test/DR per workload with sizing and isolation
10. **Cost Estimate** — PAYG vs BYOL table with assumptions (all environments)
11. **Cost Comparison** (optional) — vs current state or competitor
12. **Migration Approach** — phased timeline, tools, downtime strategy
13. **Operational RACI** — responsibility matrix (customer vs Oracle/partner)
14. **Risk Register** — severity-coded risk table
15. **Well-Architected Scorecard** — 5-pillar traffic-light indicators
16. **Next Steps** — concrete SMART actions with dates
Use `tools/oci_deck_gen.py` for generation. Colors: teal `#2D5967`, copper `#AA643B`, purple `#804998`. Font: Segoe UI. Design standards: `config/output-formats.yaml`.
## Architecture diagram
Use `tools/oci_diagram_gen.py` with OCI official styles from `kb/diagram/oci-toolkit-styles.yaml`. Containers, service blocks, connections, and typography rules are defined there.
## Service categorization
| Category | Color | Use |
|----------|-------|-----|
| **Infrastructure** | Teal `#2D5967` | Compute, OKE, LB, Gateways, WAF, Bastion, Storage, Monitoring |
| **Database** | Copper `#AA643B` | ADB-S/D, DBCS, ExaCS, MySQL, PostgreSQL, NoSQL, GoldenGate |
| **Integration** | Purple `#804998` | DRG, Streaming, Queue, OIC, FastConnect, Service Connector Hub |
| **Dormant** | Light gray `#DFDCD8` | Standby/inactive resources (DR tier) |
| **Legacy** | Medium gray `#70665E` | Non-OCI systems (MQ Series, legacy middleware) |

View File

@@ -0,0 +1,78 @@
# WA Review Output Format
This document defines how option 5 (Well-Architected Review) presents its results.
Referenced from `SKILL.md` § Welcome Flow → Behavior Rules → option 5.
The WA review MUST produce **two layers of output**: (a) the formatted terminal scorecard shown to the user, and (b) the structured YAML files saved to disk. The terminal output is the primary deliverable — the YAML is the backing data. Never produce YAML-only output without the formatted scorecard.
## Terminal scorecard banner
```
══════════════════════════════════════════════════════
✅ OCI WELL-ARCHITECTED REVIEW — [Customer Name]
══════════════════════════════════════════════════════
Overall: [STATUS] — X/Y checks passed
HIGH: N │ MEDIUM: N │ LOW: N
══════════════════════════════════════════════════════
[emoji] SECURITY & COMPLIANCE X/Y passed
[emoji] RELIABILITY & RESILIENCE X/Y passed
[emoji] PERFORMANCE & COST X/Y passed
[emoji] OPERATIONAL EFFICIENCY X/Y passed
[emoji] DISTRIBUTED CLOUD X/Y passed | N/A
```
Pillar emoji: 🟢 all passed, 🟡 medium gaps only, 🔴 any HIGH gap, ⬜ N/A
## HIGH severity gaps table
Present all HIGH gaps grouped by pillar in a markdown table:
```
### HIGH severity gaps that must be addressed:
**[Pillar Name] (N HIGH)**
| ID | Gap | Fix |
|---|---|---|
| CHECK-ID | Finding description | Recommended action |
```
## MEDIUM and LOW gaps
- **MEDIUM gaps:** List as a compact bullet list grouped by pillar (ID + one-line finding + fix). Skip the table format to keep it concise.
- **LOW gaps:** Mention count only, list individual items only if ≤ 5.
## Analysis section
After the gap tables, add a "Why so many gaps?" paragraph if total gaps > 20, explaining the root cause (e.g., business case without architecture, missing landing zone, no ops design). This contextualizes the score for the SA.
## Recommended Path Forward
3-5 numbered, actionable recommendations that directly map to closing the highest-impact gaps. Reference skill options where applicable (e.g., "Generate the architecture — option 1 or 2").
## Files Generated
Always list the files saved at the end of the review:
```
📁 Files saved:
- examples/<customer>-wa-scorecard.yaml
- examples/<customer>-wa-architecture.yaml
- examples/<customer>-wa-workload-profile.yaml
```
## After WA Review menu
```
What do you want to do?
→ [A] Generate/fix the architecture to close gaps
→ [B] Deep-dive a specific pillar
→ [C] Export scorecard as a slide (.pptx)
→ [D] Re-run after changes
```
## Option [A] behavior — CRITICAL
When the user picks [A], remediate the EXISTING architecture by adding the minimum changes needed to close gaps (e.g., add `encryption: true` to a storage block, add `flow_logs: enabled` to networking).
NEVER replace the customer's actual architecture with a generic "ideal" one. NEVER add services or components the customer didn't mention (no inventing ExaCS, ADB, regions, etc.). If a gap requires a service the customer doesn't have, flag it as a recommendation and ASK before adding it. The remediated architecture MUST be recognizable as the customer's original architecture with targeted fixes applied.

26
evaluations/README.md Normal file
View File

@@ -0,0 +1,26 @@
# Evaluations
Baseline evaluation scenarios for the OCI Deal Accelerator skill, following
the format recommended in the [Anthropic Agent Skills best practices](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices#build-evaluations-first).
These are **manual evaluations** — there is no automated test runner yet.
Use them as a regression checklist after non-trivial changes to `SKILL.md`,
`CLAUDE.md`, or the welcome flow.
## How to run
1. Open a fresh Claude Code conversation in this repo.
2. For each `*.json` file in this directory:
- Read the `query` field — paste it as the user message (or simulate the trigger described in the file).
- If `files` is non-empty, attach those files as context.
- Observe the assistant's behavior.
- Manually verify each item in `expected_behavior` is met.
3. Note any failures — file an issue or update the skill accordingly.
## Scenarios
| File | Purpose |
|---|---|
| `welcome-flow.json` | Greeting → exact 14-option menu (verbatim from SKILL.md) |
| `full-proposal.json` | Discovery notes → bypass menu, run full proposal flow |
| `wa-review.json` | WA review request → scorecard format + saved YAML files |

View File

@@ -0,0 +1,18 @@
{
"skills": ["oci-deal-accelerator"],
"query": "Customer: ACME Bank, retail banking, 200 branches across LATAM. Driver: migrating core banking from on-prem Exadata to OCI for cost reduction and DR. Current: 4-node RAC on X8M, ~12 TB DB, 2000 TPS peak, RTO 4h / RPO 15min. Compliance: PCI-DSS, local data residency. Timeline: 6 months. Budget: tight, exploring BYOL. They are also evaluating AWS RDS Custom for Oracle.",
"files": [],
"expected_behavior": [
"Detects this is discovery notes and skips the welcome menu (no 14-option list shown)",
"Goes directly into the full proposal flow (option 1 behavior)",
"Builds a workload profile reflecting ACME Bank's stated requirements (does NOT invent services they did not mention)",
"Recommends an architecture that addresses RTO/RPO, PCI-DSS, data residency, and BYOL — using kb/services/, kb/patterns/, and kb/well-architected/",
"Cites at least one Oracle Architecture Center reference architecture from kb/architecture-center/catalog.yaml when there is a strong match",
"Generates a slide deck (.pptx) as the primary deliverable, saved to examples/output-acme-bank-*/",
"Includes a Cost Estimate slide that distinguishes BYOL vs PAYG using kb/pricing/",
"Mentions the AWS RDS Custom for Oracle competitive context honestly using kb/competitive/aws-mapping.yaml",
"Does NOT add observability/security services that ACME did not request, beyond what is required for stated compliance",
"Asks clarifying questions when input is genuinely ambiguous, instead of inventing answers",
"Surfaces relevant gotchas from kb/field-knowledge/ (e.g., Exadata-to-cloud migration risks)"
]
}

View File

@@ -0,0 +1,20 @@
{
"skills": ["oci-deal-accelerator"],
"query": "5",
"follow_up": "Single-region OCI architecture: ADB-S 8 ECPU in São Paulo, 2 VM.Standard.E5.Flex web tier behind a public load balancer, Object Storage for media. No backups configured, no FastConnect. Customer: SmallShop, e-commerce, no compliance requirements stated.",
"files": [],
"expected_behavior": [
"After the user picks 5, asks for the architecture description (does not skip to scoring)",
"Reads docs/skill/wa-review-format.md before producing the scorecard",
"Parses the input into a workload profile YAML and architecture YAML",
"Runs scripts/validate-architecture.py with both files",
"Produces the formatted terminal scorecard with the exact banner format from docs/skill/wa-review-format.md (5 pillars, X/Y passed, HIGH/MEDIUM/LOW counts)",
"Saves three YAML files under examples/: <customer>-wa-scorecard.yaml, <customer>-wa-architecture.yaml, <customer>-wa-workload-profile.yaml",
"Lists the saved files at the end of the review",
"Identifies the obvious gaps (no backups, no DR, no monitoring, single-AD) as HIGH severity",
"Presents HIGH gaps as a markdown table grouped by pillar",
"Presents MEDIUM gaps as compact bullets, not a table",
"Offers the after-WA-review menu with options [A] [B] [C] [D]",
"If the user picks [A], remediates the EXISTING architecture (adds encryption, backups, etc. to the actual services SmallShop has) — does NOT replace it with a generic 'ideal' architecture, does NOT invent services SmallShop did not mention"
]
}

View File

@@ -0,0 +1,16 @@
{
"skills": ["oci-deal-accelerator"],
"query": "hola",
"files": [],
"expected_behavior": [
"Reads SKILL.md before showing anything to the user (does not improvise the menu from memory or folder structure)",
"Runs python tools/kb_freshness.py --check --json as a pre-flight step",
"If freshness reports stale files with refreshable=true, prepends a banner asking the user [y/N] before proceeding",
"If freshness reports stale files but none are refreshable, prepends a non-blocking informational banner without asking",
"Shows the welcome banner exactly as defined in SKILL.md (no paraphrasing)",
"Shows all 14 capability menu options in the correct 6 sections: DESIGN & PROPOSE (1-4), VALIDATE & CHECK (5-7), STRATEGY & BUSINESS (8), KNOWLEDGE BASE (9-11), ECAL GOVERNANCE (12), SA TOOLS (13-14)",
"Does NOT invent options that are not in SKILL.md",
"Does NOT omit options that are in SKILL.md",
"If the freshness tool errors out, falls back to showing the welcome message silently — never blocks the user on tooling failures"
]
}

View File

@@ -0,0 +1,378 @@
[
{
"title": "Deploy Oracle Autonomous Database on Oracle Database@Azure",
"url": "https://docs.oracle.com/en/solutions/deploy-autonomous-database-db-at-azure/index.html",
"type": "reference-architecture",
"date": "2024-10",
"services": [
"adb-s",
"adg",
"azure"
],
"tags": [
"database",
"multicloud",
"azure",
"ha-dr",
"autonomous"
],
"summary": "Multi-AZ deployment of ADB-S on Database@Azure with Autonomous Data Guard. Recommends VNet peering between app and DB VNets, TAC for availability, and ADG standby in a different AZ for automatic failover.\n",
"terraform": null
},
{
"title": "Oracle MAA for Oracle Database@Azure",
"url": "https://docs.oracle.com/en/solutions/oracle-maa-db-at-azure/index.html",
"type": "reference-architecture",
"date": "2025-05",
"services": [
"exacs",
"adg",
"vault",
"azure"
],
"tags": [
"database",
"multicloud",
"azure",
"ha-dr",
"autonomous"
],
"summary": "Cross-AZ Data Guard on ExaCS in Database@Azure. Active Data Guard recommended for cross-AZ replication (block repair, app continuity, read offload). Backups to Autonomous Recovery Service.\n",
"terraform": null
},
{
"title": "Implement disaster recovery with local and regional standbys on Oracle Database@Azure",
"url": "https://docs.oracle.com/en/solutions/local-regional-standby-dr-db-at-azure/index.html",
"type": "reference-architecture",
"date": "2025-05",
"services": [
"exacs",
"adg",
"azure",
"fsdr"
],
"tags": [
"database",
"multicloud",
"azure",
"ha-dr"
],
"summary": "Local standby for HA within same region, regional standby for DR across Azure regions. Uses Active Data Guard with Fast-Start Failover. Recommends Full Stack DR service for automated failover orchestration.\n",
"terraform": null
},
{
"title": "Implement disaster recovery with multi-region standby on Oracle Database@Azure",
"url": "https://docs.oracle.com/en/solutions/multi-region-standby-dr-db-at-azure/index.html",
"type": "reference-architecture",
"date": "2025-04",
"services": [
"exacs",
"adg",
"azure"
],
"tags": [
"database",
"multicloud",
"azure",
"ha-dr"
],
"summary": "Multi-region DR for ExaCS on Database@Azure using Data Guard. Cross-region standby with switchover/failover capabilities. Includes network topology for Azure-to-Azure cross-region connectivity.\n",
"terraform": null
},
{
"title": "Implement cross-region disaster recovery for Exadata Database on Oracle Database@Azure",
"url": "https://docs.oracle.com/en/solutions/exadb-dr-on-db-azure/index.html",
"type": "reference-architecture",
"date": "2025-01",
"services": [
"exacs",
"adg",
"azure",
"fsdr"
],
"tags": [
"database",
"multicloud",
"azure",
"ha-dr"
],
"summary": "Cross-region DR for ExaCS on Database@Azure. OCI-managed networks for peering (better performance, first 10 TB/month free). Data Guard for cross-region replication, FSDR for automated failover orchestration.\n",
"terraform": "https://github.com/oracle-quickstart/oci-multicloud-azure"
},
{
"title": "Deploy Active Data Guard Far Sync to protect data across Oracle Database@Azure regions",
"url": "https://docs.oracle.com/en/solutions/active-data-guard-far-sync-oracle-db-at-azure/index.html",
"type": "reference-architecture",
"date": "2025-02",
"services": [
"exacs",
"adg",
"azure"
],
"tags": [
"database",
"multicloud",
"azure",
"ha-dr"
],
"summary": "Far Sync instance for zero data loss protection across Azure regions. Synchronous redo transport to Far Sync, async to remote standby. Eliminates performance impact of synchronous shipping over long distances.\n",
"terraform": null
},
{
"title": "Implement Oracle Database Autonomous Recovery Service with Oracle Database@Azure",
"url": "https://docs.oracle.com/en/solutions/implement-recovery-service-db-at-azure/index.html",
"type": "reference-architecture",
"date": "2025-01",
"services": [
"exacs",
"azure"
],
"tags": [
"database",
"multicloud",
"azure",
"ha-dr"
],
"summary": "Autonomous Recovery Service for ExaCS backups on Database@Azure. Automated backup management with real-time protection and point-in-time recovery capabilities.\n",
"terraform": null
},
{
"title": "Deploy Oracle Autonomous Database on Oracle Database@Google Cloud",
"url": "https://docs.oracle.com/en/solutions/deploy-adb-db-at-google-cloud/index.html",
"type": "reference-architecture",
"date": "2025-03",
"services": [
"adb-s",
"adg",
"google-cloud"
],
"tags": [
"database",
"multicloud",
"ha-dr",
"autonomous"
],
"summary": "ADB-S on Database@Google Cloud with cross-region ADG. Non-overlapping CIDR between VPC and VCN required. App tier should span 2+ AZs with Google Global Load Balancer for failover.\n",
"terraform": null
},
{
"title": "Deploy Active Data Guard Far Sync to protect data across Oracle Database@AWS regions",
"url": "https://docs.oracle.com/en/solutions/dr-active-dg-farsync-db-at-aws/index.html",
"type": "reference-architecture",
"date": "2025-09",
"services": [
"exacs",
"adg",
"aws"
],
"tags": [
"database",
"multicloud",
"aws",
"ha-dr"
],
"summary": "Far Sync instance for zero data loss protection across AWS regions. Synchronous redo to local Far Sync, asynchronous to remote standby. Requires cross-region AWS networking for redo transport.\n",
"terraform": null
},
{
"title": "Implement disaster recovery with local and regional standbys on Oracle Database@AWS",
"url": "https://docs.oracle.com/en/solutions/dr-local-regional-standby-db-at-aws/index.html",
"type": "reference-architecture",
"date": "2025-09",
"services": [
"exacs",
"adg",
"aws",
"fsdr"
],
"tags": [
"database",
"multicloud",
"aws",
"ha-dr"
],
"summary": "Local standby for HA within same AWS region, regional standby for DR. Active Data Guard with Fast-Start Failover for automated failover. Full Stack DR service for cross-service failover orchestration.\n",
"terraform": null
},
{
"title": "Implement disaster recovery with cross-zonal Data Guard on Oracle Database@AWS",
"url": "https://docs.oracle.com/en/solutions/cross-zone-dr-db-at-aws/index.html",
"type": "reference-architecture",
"date": "2025-08",
"services": [
"exacs",
"adg",
"aws"
],
"tags": [
"database",
"multicloud",
"aws",
"ha-dr"
],
"summary": "Cross-AZ Data Guard on Database@AWS for HA. Synchronous redo transport between AZs for zero data loss. Fast-Start Failover for automatic database switchover on failure.\n",
"terraform": null
},
{
"title": "Implement disaster recovery with cross-regional Data Guard on Oracle Database@AWS",
"url": "https://docs.oracle.com/en/solutions/implement-dr-cross-region-dg-odb-aws/index.html",
"type": "reference-architecture",
"date": "2025-08",
"services": [
"exacs",
"adg",
"aws"
],
"tags": [
"database",
"multicloud",
"aws",
"ha-dr"
],
"summary": "Cross-region Data Guard on Database@AWS for DR. Asynchronous redo transport for cross-region replication. Planned switchover for maintenance, forced failover for disaster scenarios.\n",
"terraform": null
},
{
"title": "Migrate Oracle RAC Databases to OCI",
"url": "https://docs.oracle.com/en/solutions/ensure-ha-migrate-vmware-workloads-to-oci/migrate-oracle-rac-databases1.html",
"type": "reference-architecture",
"date": "2025-01",
"services": [
"exacs",
"exascale",
"adb-d",
"base-db"
],
"tags": [
"database",
"migration",
"ha-dr"
],
"summary": "Compares 4 RAC migration targets: ExaCS Dedicated, Exascale, ADB-D, and 2-node RAC on Base DB. ExaCS recommended for full RAC feature parity. Exascale for 23ai-only without dedicated infra commitment.\n",
"terraform": null
},
{
"title": "Deploy ORDS with High Availability on OCI",
"url": "https://docs.oracle.com/en/solutions/deploy-ords-ha-oci/index.html",
"type": "reference-architecture",
"date": "2025-06",
"services": [
"compute",
"load-balancer",
"adb-s",
"bastion"
],
"tags": [
"database",
"application",
"ha-dr"
],
"summary": "Multi-instance ORDS behind OCI Load Balancer for HA REST access to Oracle DB. Works with ADB-S, DBCS, or ExaCS. Recommends DB in private subnet, ORDS in public with granular NSG rules.\n",
"terraform": null
},
{
"title": "Configure Data Guard for Oracle Exadata Database Service on Dedicated Infrastructure",
"url": "https://docs.oracle.com/en/solutions/dataguard-exadata-dedicated-infrastructure/index.html",
"type": "reference-architecture",
"date": "2025-07",
"services": [
"exacs",
"adg"
],
"tags": [
"database",
"ha-dr"
],
"summary": "Data Guard configuration for ExaCS Dedicated. Active Data Guard for read offload and automatic failover. Cross-region standby for DR with Fast-Start Failover for automated switchover.\n",
"terraform": null
},
{
"title": "Back up from Exadata on Dedicated Infrastructure to Zero Data Loss Autonomous Recovery",
"url": "https://docs.oracle.com/en/solutions/back-up-exadata-dedicated-zero-data-loss-recovery/index.html",
"type": "reference-architecture",
"date": "2025-07",
"services": [
"exacs"
],
"tags": [
"database",
"ha-dr"
],
"summary": "Autonomous Recovery Service for ExaCS backups. Automated backup management with real-time redo protection. Validates backup recoverability automatically.\n",
"terraform": null
},
{
"title": "Configure a standby database for disaster recovery using Oracle Exadata Database Service on Cloud@Customer",
"url": "https://docs.oracle.com/en/solutions/exadata-cloud-at-customer-standby/index.html",
"type": "reference-architecture",
"date": "2025-07",
"services": [
"exacs",
"adg"
],
"tags": [
"database",
"ha-dr"
],
"summary": "Data Guard standby on ExaCS Cloud@Customer for hybrid DR. On-premises primary with cloud standby, or cloud primary with on-premises standby for data sovereignty requirements.\n",
"terraform": null
},
{
"title": "Learn about maximum availability architecture for PeopleSoft",
"url": "https://docs.oracle.com/en/solutions/learn-about-maa-for-peoplesoft/index.html",
"type": "reference-architecture",
"date": "2024-08",
"services": [
"exacs",
"adg",
"load-balancer",
"compute"
],
"tags": [
"application",
"ha-dr",
"peoplesoft"
],
"summary": "MAA for PeopleSoft on OCI. Active Data Guard for database HA/DR, multi-instance PIA behind Load Balancer, Process Scheduler on multiple nodes for batch processing resilience.\n",
"terraform": null
},
{
"title": "Provision and deploy a maximum availability solution for PeopleSoft on Oracle Cloud",
"url": "https://docs.oracle.com/en/solutions/deploy-maa-for-peoplesoft-on-oci/index.html",
"type": "reference-architecture",
"date": "2024-08",
"services": [
"exacs",
"adg",
"load-balancer",
"compute"
],
"tags": [
"application",
"ha-dr",
"peoplesoft"
],
"summary": "Step-by-step PeopleSoft MAA deployment on OCI. Terraform stacks for infrastructure provisioning, Data Guard configuration, and PeopleSoft application tier setup.\n",
"terraform": null
},
{
"title": "Run PeopleSoft ERP and Autonomous Database in an HA multicloud deployment",
"url": "https://docs.oracle.com/en/solutions/bread-multicloud-on-oci/index.html",
"type": "reference-architecture",
"date": "2025-02",
"services": [
"adb-s",
"compute",
"load-balancer"
],
"tags": [
"application",
"ha-dr",
"multicloud",
"peoplesoft",
"autonomous"
],
"summary": "PeopleSoft HA with ADB-S across cloud providers. Application tier on OCI compute with database on ADB-S. Multi-AZ deployment for high availability with automatic failover.\n",
"terraform": null
}
]

View File

@@ -0,0 +1,195 @@
<mxfile host="app.diagrams.net" agent="OCI Deal Accelerator" version="24.0.0" type="device">
<diagram name="OCI Architecture" id="oci-arch">
<mxGraphModel dx="1900" dy="1200" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1900" pageHeight="1200" background="#FFFFFF" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="139766084988960" value="" style="group;whiteSpace=wrap;rounded=0;fillColor=none;strokeColor=none;dashed=0;connectable=1;pointerEvents=1;" vertex="1" parent="1">
<mxGeometry x="30" y="250" width="50" height="60" as="geometry" />
</mxCell>
<mxCell id="139766136148656" value="MELI&#xa;Applications" style="text;whiteSpace=wrap;rounded=0;fillColor=none;strokeColor=none;dashed=0;html=1;align=center;verticalAlign=top;fontFamily=Oracle Sans;fontSize=11;fontColor=#312D2A;" vertex="1" parent="139766084988960">
<mxGeometry x="-10" y="48" width="70" height="20" as="geometry" />
</mxCell>
<mxCell id="139766084989440" value="AWS&#xa;(Current State)" style="whiteSpace=wrap;rounded=1;fillColor=none;strokeColor=#70665E;dashed=1;html=1;strokeWidth=2;dashPattern=6 4;align=left;fontFamily=Oracle Sans;verticalAlign=top;fontColor=#70665E;fontSize=12;spacingLeft=5;spacingTop=5;arcSize=6;" vertex="1" parent="1">
<mxGeometry x="10" y="80" width="220" height="180" as="geometry" />
</mxCell>
<mxCell id="139766084990064" value="DynamoDB&#xa;30K Tables&#xa;70M RPM Peak" style="whiteSpace=wrap;rounded=1;fillColor=#FCFBFA;strokeColor=#2D5967;dashed=0;html=1;strokeWidth=1.5;fontColor=#2D5967;fontSize=11;fontFamily=Oracle Sans;arcSize=8;verticalAlign=middle;align=center;" vertex="1" parent="139766084989440">
<mxGeometry x="30" y="60" width="160" height="80" as="geometry" />
</mxCell>
<mxCell id="139766084989248" value="Oracle Cloud Infrastructure" style="whiteSpace=wrap;rounded=1;fillColor=none;strokeColor=#9E9892;dashed=1;html=1;strokeWidth=1;dashPattern=6 4;align=left;fontFamily=Oracle Sans;verticalAlign=top;fontColor=#312D2A;fontSize=13;fontStyle=1;spacingLeft=10;spacingTop=8;arcSize=1;" vertex="1" parent="1">
<mxGeometry x="280" y="80" width="1100" height="520" as="geometry" />
</mxCell>
<mxCell id="139766084990976" value="Region — São Paulo" style="whiteSpace=wrap;rounded=1;fillColor=#F5F4F2;strokeColor=#9E9892;dashed=0;html=1;align=left;fontFamily=Oracle Sans;verticalAlign=top;arcSize=5;fontColor=#312D2A;fontSize=13;fontStyle=1;spacingLeft=10;spacingTop=8;" vertex="1" parent="139766084989248">
<mxGeometry x="15" y="40" width="1070" height="460" as="geometry" />
</mxCell>
<mxCell id="139766084991984" value="VCN KVS Production (10.0.0.0/16)" style="whiteSpace=wrap;rounded=0;fillColor=none;strokeColor=#AE562C;dashed=1;html=1;strokeWidth=2;dashPattern=6 4;align=left;fontFamily=Oracle Sans;verticalAlign=top;fontColor=#AE562C;perimeterSpacing=0;fontSize=12;fontStyle=1;spacingLeft=8;spacingTop=6;" vertex="1" parent="139766084990976">
<mxGeometry x="15" y="45" width="1040" height="400" as="geometry" />
</mxCell>
<mxCell id="139766084992656" value="Application Subnet (Private) — 10.0.1.0/24" style="whiteSpace=wrap;rounded=0;fillColor=none;strokeColor=#AE562C;dashed=1;html=1;strokeWidth=1;dashPattern=6 4;align=left;fontFamily=Oracle Sans;verticalAlign=top;fontColor=#AE562C;fontSize=11;fontStyle=1;spacingLeft=8;spacingTop=4;" vertex="1" parent="139766084991984">
<mxGeometry x="8" y="32" width="1024" height="140" as="geometry" />
</mxCell>
<mxCell id="139766069527424" value="" style="group;whiteSpace=wrap;rounded=0;fillColor=none;strokeColor=none;dashed=0;pointerEvents=1;connectable=1;" vertex="1" parent="139766084992656">
<mxGeometry x="246" y="30" width="160" height="44" as="geometry" />
</mxCell>
<mxCell id="139766122318064" value="OCI NoSQL&#xa;Service Endpoint" style="text;whiteSpace=wrap;rounded=0;fillColor=none;strokeColor=none;dashed=0;html=1;overflow=visible;align=center;verticalAlign=top;fontFamily=Oracle Sans;fontSize=11;fontColor=#312D2A;spacingTop=2;" vertex="1" parent="139766084992656">
<mxGeometry x="246" y="76" width="160" height="36" as="geometry" />
</mxCell>
<mxCell id="139766069534000" value="" style="group;whiteSpace=wrap;rounded=0;fillColor=none;strokeColor=none;dashed=0;pointerEvents=1;connectable=1;" vertex="1" parent="139766084992656">
<mxGeometry x="422" y="30" width="180" height="28" as="geometry" />
</mxCell>
<mxCell id="139766111346400" value="NoSQL&#xa;Elastic Pod Dedicated&#xa;(Isolated Compute)" style="text;whiteSpace=wrap;rounded=0;fillColor=none;strokeColor=none;dashed=0;html=1;overflow=visible;align=center;verticalAlign=top;fontFamily=Oracle Sans;fontSize=11;fontColor=#312D2A;spacingTop=2;" vertex="1" parent="139766084992656">
<mxGeometry x="422" y="60" width="180" height="52" as="geometry" />
</mxCell>
<mxCell id="139766069536112" value="" style="group;whiteSpace=wrap;rounded=0;fillColor=none;strokeColor=none;dashed=0;pointerEvents=1;connectable=1;" vertex="1" parent="139766084992656">
<mxGeometry x="618" y="30" width="160" height="28" as="geometry" />
</mxCell>
<mxCell id="139766108726976" value="NoSQL Tables&#xa;30K Tables&#xa;70M RPM Peak" style="text;whiteSpace=wrap;rounded=0;fillColor=none;strokeColor=none;dashed=0;html=1;overflow=visible;align=center;verticalAlign=top;fontFamily=Oracle Sans;fontSize=11;fontColor=#312D2A;spacingTop=2;" vertex="1" parent="139766084992656">
<mxGeometry x="618" y="60" width="160" height="52" as="geometry" />
</mxCell>
<mxCell id="139766084986608" value="AI Memory Subnet (Private) — 10.0.3.0/24" style="whiteSpace=wrap;rounded=0;fillColor=none;strokeColor=#AE562C;dashed=1;html=1;strokeWidth=1;dashPattern=6 4;align=left;fontFamily=Oracle Sans;verticalAlign=top;fontColor=#AE562C;fontSize=11;fontStyle=1;spacingLeft=8;spacingTop=4;" vertex="1" parent="139766084991984">
<mxGeometry x="8" y="186" width="1024" height="140" as="geometry" />
</mxCell>
<mxCell id="139766069531888" value="Oracle ADB-S 23ai&#xa;AI Vector Search&#xa;(Agent Memory)" style="whiteSpace=wrap;rounded=1;fillColor=#FCFBFA;strokeColor=#2D5967;dashed=0;html=1;strokeWidth=1.5;fontColor=#2D5967;fontSize=11;fontFamily=Oracle Sans;arcSize=8;verticalAlign=middle;align=center;" vertex="1" parent="139766084986608">
<mxGeometry x="266" y="30" width="180" height="80" as="geometry" />
</mxCell>
<mxCell id="139766069540912" value="OCI GenAI&#xa;Embedding&#xa;Service" style="whiteSpace=wrap;rounded=1;fillColor=#FCFBFA;strokeColor=#2D5967;dashed=0;html=1;strokeWidth=1.5;fontColor=#2D5967;fontSize=11;fontFamily=Oracle Sans;arcSize=8;verticalAlign=middle;align=center;" vertex="1" parent="139766084986608">
<mxGeometry x="462" y="30" width="140" height="80" as="geometry" />
</mxCell>
<mxCell id="139766069542640" value="" style="group;whiteSpace=wrap;rounded=0;fillColor=none;strokeColor=none;dashed=0;pointerEvents=1;connectable=1;" vertex="1" parent="139766084986608">
<mxGeometry x="618" y="30" width="140" height="44" as="geometry" />
</mxCell>
<mxCell id="139766069542784" value="OCI Functions&#xa;Memory Sync" style="text;whiteSpace=wrap;rounded=0;fillColor=none;strokeColor=none;dashed=0;html=1;overflow=visible;align=center;verticalAlign=top;fontFamily=Oracle Sans;fontSize=11;fontColor=#312D2A;spacingTop=2;" vertex="1" parent="139766084986608">
<mxGeometry x="618" y="76" width="140" height="36" as="geometry" />
</mxCell>
<mxCell id="139766084817968" value="Management Subnet (Private) — 10.0.2.0/24" style="whiteSpace=wrap;rounded=0;fillColor=none;strokeColor=#AE562C;dashed=1;html=1;strokeWidth=1;dashPattern=6 4;align=left;fontFamily=Oracle Sans;verticalAlign=top;fontColor=#AE562C;fontSize=11;fontStyle=1;spacingLeft=8;spacingTop=4;" vertex="1" parent="139766084991984">
<mxGeometry x="8" y="340" width="1024" height="120" as="geometry" />
</mxCell>
<mxCell id="139766069584112" value="" style="group;whiteSpace=wrap;rounded=0;fillColor=none;strokeColor=none;dashed=0;pointerEvents=1;connectable=1;" vertex="1" parent="139766084817968">
<mxGeometry x="384" y="30" width="120" height="34" as="geometry" />
</mxCell>
<mxCell id="139766084991408" value="OCI&#xa;Monitoring" style="text;whiteSpace=wrap;rounded=0;fillColor=none;strokeColor=none;dashed=0;html=1;overflow=visible;align=center;verticalAlign=top;fontFamily=Oracle Sans;fontSize=11;fontColor=#312D2A;spacingTop=2;" vertex="1" parent="139766084817968">
<mxGeometry x="384" y="66" width="120" height="36" as="geometry" />
</mxCell>
<mxCell id="139766069586800" value="" style="group;whiteSpace=wrap;rounded=0;fillColor=none;strokeColor=none;dashed=0;pointerEvents=1;connectable=1;" vertex="1" parent="139766084817968">
<mxGeometry x="520" y="30" width="120" height="34" as="geometry" />
</mxCell>
<mxCell id="139766132774896" value="OCI&#xa;Logging" style="text;whiteSpace=wrap;rounded=0;fillColor=none;strokeColor=none;dashed=0;html=1;overflow=visible;align=center;verticalAlign=top;fontFamily=Oracle Sans;fontSize=11;fontColor=#312D2A;spacingTop=2;" vertex="1" parent="139766084817968">
<mxGeometry x="520" y="66" width="120" height="36" as="geometry" />
</mxCell>
<mxCell id="139766069591360" value="" style="group;whiteSpace=wrap;rounded=0;fillColor=none;strokeColor=none;dashed=0;pointerEvents=1;connectable=1;" vertex="1" parent="139766084991984">
<mxGeometry x="10" y="40" width="110" height="34" as="geometry" />
</mxCell>
<mxCell id="139766069586224" value="Service&#xa;Gateway" style="text;whiteSpace=wrap;rounded=0;fillColor=none;strokeColor=none;dashed=0;html=1;overflow=visible;align=center;verticalAlign=top;fontFamily=Oracle Sans;fontSize=11;fontColor=#312D2A;spacingTop=2;" vertex="1" parent="139766084991984">
<mxGeometry x="10" y="76" width="110" height="36" as="geometry" />
</mxCell>
<mxCell id="139766084992224" style="elbow=vertical;endFill=0;startFill=0;labelBackgroundColor=#FFFFFF;labelBorderColor=none;fontFamily=Oracle Sans;fontSize=10;fontColor=#312D2A;edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;rounded=1;jettySize=auto;startArrow=none;endArrow=open;strokeColor=#312D2A;strokeWidth=1;endSize=6;fontFamily=Oracle Sans;fontSize=10;fontColor=#312D2A;labelBackgroundColor=#FFFFFF;" edge="1" parent="1" source="139766084988960" target="139766084990064" value="Current: SDK calls">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="139766084992896" style="elbow=vertical;endFill=0;startFill=0;labelBackgroundColor=#FFFFFF;labelBorderColor=none;fontFamily=Oracle Sans;fontSize=10;fontColor=#312D2A;edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;rounded=1;jettySize=auto;startArrow=none;endArrow=open;strokeColor=#312D2A;strokeWidth=1;endSize=6;fontFamily=Oracle Sans;fontSize=10;fontColor=#312D2A;labelBackgroundColor=#FFFFFF;" edge="1" parent="1" source="139766084988960" target="139766069527424" value="Target: OCI NoSQL SDK">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="139766108632320" style="elbow=vertical;endFill=0;startFill=0;labelBackgroundColor=#FFFFFF;labelBorderColor=none;fontFamily=Oracle Sans;fontSize=10;fontColor=#312D2A;edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;rounded=1;jettySize=auto;startArrow=none;endArrow=open;strokeColor=#312D2A;strokeWidth=1;endSize=6;fontFamily=Oracle Sans;fontSize=10;fontColor=#312D2A;labelBackgroundColor=#FFFFFF;" edge="1" parent="1" source="139766069527424" target="139766069536112" value="R/W Operations">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="139766069577392" style="elbow=vertical;endFill=0;startFill=0;labelBackgroundColor=#FFFFFF;labelBorderColor=none;fontFamily=Oracle Sans;fontSize=10;fontColor=#312D2A;edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;rounded=1;jettySize=auto;startArrow=none;endArrow=open;strokeColor=#312D2A;strokeWidth=1;endSize=6;fontFamily=Oracle Sans;fontSize=10;fontColor=#312D2A;labelBackgroundColor=#FFFFFF;" edge="1" parent="1" source="139766069591360" target="139766069527424" value="Private access">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="139766069591456" style="elbow=vertical;endFill=0;startFill=0;labelBackgroundColor=#FFFFFF;labelBorderColor=none;fontFamily=Oracle Sans;fontSize=10;fontColor=#312D2A;edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;rounded=1;jettySize=auto;startArrow=none;endArrow=open;strokeColor=#312D2A;strokeWidth=1;endSize=6;fontFamily=Oracle Sans;fontSize=10;fontColor=#312D2A;labelBackgroundColor=#FFFFFF;" edge="1" parent="1" source="139766069534000" target="139766069536112" value="Dedicated&#xa;Infrastructure">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="139766069532176" style="elbow=vertical;endFill=0;startFill=0;labelBackgroundColor=#FFFFFF;labelBorderColor=none;fontFamily=Oracle Sans;fontSize=10;fontColor=#312D2A;edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;rounded=1;jettySize=auto;startArrow=none;endArrow=open;strokeColor=#312D2A;strokeWidth=1;endSize=6;fontFamily=Oracle Sans;fontSize=10;fontColor=#312D2A;labelBackgroundColor=#FFFFFF;" edge="1" parent="1" source="139766069536112" target="139766069542640" value="Memory Sync&#xa;(hot → warm)">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="139766069537168" style="elbow=vertical;endFill=0;startFill=0;labelBackgroundColor=#FFFFFF;labelBorderColor=none;fontFamily=Oracle Sans;fontSize=10;fontColor=#312D2A;edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;rounded=1;jettySize=auto;startArrow=none;endArrow=open;strokeColor=#312D2A;strokeWidth=1;endSize=6;fontFamily=Oracle Sans;fontSize=10;fontColor=#312D2A;labelBackgroundColor=#FFFFFF;" edge="1" parent="1" source="139766069542640" target="139766069531888" value="Vectorize &amp;&#xa;Store">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="139766069532272" style="elbow=vertical;endFill=0;startFill=0;labelBackgroundColor=#FFFFFF;labelBorderColor=none;fontFamily=Oracle Sans;fontSize=10;fontColor=#312D2A;edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;rounded=1;jettySize=auto;startArrow=none;endArrow=open;strokeColor=#312D2A;strokeWidth=1;endSize=6;fontFamily=Oracle Sans;fontSize=10;fontColor=#312D2A;labelBackgroundColor=#FFFFFF;" edge="1" parent="1" source="139766069540912" target="139766069531888" value="Embeddings">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="139766084991024" value="MELI KVS — OCI NoSQL Architecture" style="text;whiteSpace=wrap;rounded=0;dashed=0;html=1;fontSize=18;fontColor=#312D2A;fontFamily=Oracle Sans;align=center;verticalAlign=middle;fontStyle=1;" vertex="1" parent="1">
<mxGeometry x="0" y="8" width="1380" height="35" as="geometry" />
</mxCell>
<mxCell id="1002" value="" style="ellipse;fillColor=none;strokeColor=#2D5967;strokeWidth=2;" vertex="1" parent="139766084988960"><mxGeometry x="14" y="0" width="22" height="22" as="geometry"/></mxCell>
<mxCell id="1003" value="" style="shape=mxgraph.basic.arc;dx=0.5;fillColor=none;strokeColor=#2D5967;strokeWidth=2;rotation=180;" vertex="1" parent="139766084988960"><mxGeometry x="9" y="24" width="32" height="22" as="geometry"/></mxCell>
<mxCell id="nosql_endpoint_i2" parent="139766069527424" style="vsdxID=4;fillColor=none;gradientColor=none;strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="28.65116279069762" width="25.92248062015499" x="67.03875968992253" y="7.755381177908675e-14" /></mxCell>
<mxCell id="nosql_endpoint_i3" parent="nosql_endpoint_i2" style="vsdxID=5;fillColor=#FCFBFA;gradientColor=none;shape=stencil(lZTRcoMgEEW/htcdYAHlOU3+I9OY6tRqxpg2/fviQHXBEds3WO56rrC7DA/3+nyrmOT3cejfq6/mMtYMX5iUTVdXQzO6FcMjw8O1H6q3oX90F7+/nSfltProP6cvPH2e5lOK5N9+K7jfn7z29TF4sfDHSkEpQoKIM/hT+gAH/isJEWvBYBDhShQipYHCUHbbdMQnSQhcBdrmvPLEpwKFidPYplPIcs+mEwn5HyyCVXksQqF3sQjaZLFLSoggGBODpQGrYziPwXM1ID3eQBYIXMfMpBTcw1sbA4krXIv++rdz0ZFrni9Rphq5fooMe++B12xSN5tsUn1ZdlzTcQ/QjI2mSc3SlCVkkkbQGpKWXbp6ozKSQREbzQ8Vt1im0bVpWz/M6Hk6vVzITz48/gA=);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="27.968992248061962" width="25.24031007751933" x="0.3410852713178288" y="0.3410852713178288" /></mxCell>
<mxCell id="nosql_endpoint_i4" parent="nosql_endpoint_i2" style="vsdxID=6;fillColor=#FCFBFA;gradientColor=none;shape=stencil(lVbRcsIgEPyavDJwFwh5tu1/ODXWTK1xorb270tKYg5uAvEtnrvswS07FLi5HLbnpgB5ufbdZ/PT7q6HAl8KgPZ0aPr26r4KfC1ws+/65qPvbqed/33eDsjh66v7Hla4e56WQqqBBfLXV0Cg/S+8efz7rfcE5f+vQNiRoCKGvIOv1JVAM4LGkhGqHEHIQWNJlaLElPjAqUJ1xzHI5atQ3qEs5vW1kPCsvhbK5PW1gHqNfrj/Y3siw6IMX7Fa2OS0KGUquVbKsGFjWMOOaCBsmHoFY9SCPqIwZaRPVobJQSayC20SGQgXdh8eFyEsHG/cLbBm6dyAgYBbYLHZrLccRTNrW2TiOhIn/l8Wz10sQlHswk7alVB1KE6u/rJJ4kQJp5RPoFxiydTGSsWOVYbbIus9Kia6q3xT2ROVPKZUJMwGWa2RrZMXPpZ11sS0rHO4zcqmg4mNJJtLhDHFQi0wOiA6u6lbKYuc3ybMgrS2LBLnVWOZRx6R7jDGrIujGb8yjWYCCSOTaXQYOGQazZqIK/Mk4srO4XnhJ7dMriLw8YWOTlgiMEQufwKw+5jfTvv2ePRPL/p//NZyJf9Ow9c/);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="28.65116279069762" width="25.92248062015499" /></mxCell>
<mxCell id="nosql_endpoint_i5" parent="nosql_endpoint_i2" style="vsdxID=7;fillColor=#2d5967;gradientColor=none;shape=stencil(lVPbDoIwDP2avTZbyxg8e/kPoyiLCGbg7e+FdMq2BBPfejntOe06Qau+3l0rgbIfXHeuHvYw1ILWAtG2deXsMFqCNoJWx85VJ9fd2gP7192EnKxLd586PLlOSTnVoHyxz96WofubY6ziZJGBRA/3IQ0lceSJHMkNoPIgHypBGQ8iX/ZhpQSxwEwIpoyZg6aeRo1iipg5kEfhgF/iaN7GtsFq4sWUEjD/JVEVoLJEooFkOaRB61ji9wWWdvMBLPDmGWQ65p1beo5CgcmTN5m1UXoKtDByvJ+fp/MHdDTm6zzapuHjDvPpNY8h/gm0eQM=);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="1.0232558139534864" width="6.480620155038747" x="9.550387596899206" y="19.78294573643407" /></mxCell>
<mxCell id="nosql_endpoint_i6" parent="nosql_endpoint_i2" style="vsdxID=8;fillColor=#2d5967;gradientColor=none;shape=stencil(lVPRkoIwDPyavmbahFL67Ol/OCdK5zhwKnr494Kp0nLizb2lyya7TRdBq1O1PZYC5anz7Vf543ZdJehDILqmKr3rhkrQWtBq3/ry4Ntzs+PzcTsyx+q7vYwTeu6TYwfKK5+sBDR3ZMPkz7NntmKCKkBloSVA1gAx0iMjpEHrQAqQkkGoJwb0Q5hSwoJunkGmU91pZNAoFJg8lY28zXSewr+uXLsm2s/Ej/e14LLIQGLqUoPVqc3cAKqZTVD2/XqejAVlQjB29i7T0McjDGaKVDmyR2kg6MV909X8EZ1/kYdiSuje1TUHPP4+T/QA8d9A6xs=);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="1.0232558139534864" width="6.480620155038747" x="9.550387596899206" y="13.302325581395323" /></mxCell>
<mxCell id="nosql_endpoint_i7" parent="nosql_endpoint_i2" style="vsdxID=9;fillColor=#2d5967;gradientColor=none;shape=stencil(lVhdd9sgDP01edUBhPl47rr/0bOma866pidNt/bfT54NCGEb5y3Bku9FV0jCB7x7f354Ox6Mer9ezr+Of0+P1+cDfjsYc3p9Pl5OV/p1wPsD3j2dL8efl/PH6+P0/+1htBx//T7/Gd/wOfnFCDGOXkZ9TSvagBv+r3yfHH58XCYP3brMSwhxclGfZlrxFpSbjeYlNVvg9HeY/38hf7yCaQaItsZUNaACpWs8RgobG9y5WVWDkn1wArhG1QjKd2ERjL8FFsGaHuzgdsBWqC+nV5YKzH5aCB7cNsvikXLDg0gENDNmoao6mZAMVlCdBxThUSIZeIqahhm2Rriy4zpCC4dFRFRyzcyYkoNIoGJjWrXXuXZzaAk7p+YqNkvwDWx5bLpxkg51FQq0F1s5ROKxeTC9ARxE8lmIWO/P6fLilAhUSrRMQNDiqJCVD1v4GPJrMv7Q4BsP3gh829Ql7cA7gd/bv0vPC7zKWAneghPoIeSwJXRmtO8YMIeZS+hUUU2VQrD1GlQUyUjxq9mSyC7UbI2GKOh6THtapMs9Zr4R9BZdw/JB5y0GwZYiGWq6ZNRXloz0jco6B6qrrENweOgo6wzEW5S1dq61+4W1tGXbE9ZS8ATZBWFtvEVV4uo3A7sgK/lY0bAWdCUr3RfWImxWjFZXq9M529AVY6rzG7pSNZqX9ulKm7Rmiyz1Cu1qtjRQ6Zos9XaFNVsa1Bq2EYLoH8Vqvcd7ESz+5lTMXBMtRrJUci2UanYv2hfzWAlvMxMPTbi4bqn0m5Kzpk2BVH0xn/a9qRU0iOmYp2wqpjFDscS2IrG9L2mK2cpv1FfusXRuG7K0mSDY0pkTBS5E8CK3xsoiisaCuLJk9bRtSuIObXmtXdeWl+11bbv9oBWX9Zl1bVnHWpdWdsKesk2r3SHu2MTlwW3FHecBwXdB3GbS6KnbvcPEUlYSYT4jJXVJNzlHsnGrqKuxJtzMcTXhHYPvzQ71aJ0vV6kTmM1CRgOzFrcr2wxqpKgR8g25tfJg1LHwYLY/LGBGyjNt0565XqljawiihnKrvVf9hUwYb2LynDOSZbwJQ2/z1HNU70JjROTHgUWEnuuTWh7dcZoLTQ1OJmrzFFCDCxJcp1ThtxlZZYiiOAQLk1F37665S/GY5tFI1oxRnhqc2eyVnbnonE8y6oWfaRJzfd+9hOfx1Pkc1dBcmRwIWSml3vKU1zWkUxLoR/la+HR6eZk+NvLn8usiLU1fJvH+Hw==);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="27.286821705426302" width="24.558139534883672" x="0.6821705426356576" y="0.6821705426356576" /></mxCell>
<mxCell id="nosql_endpoint_i8" parent="nosql_endpoint_i2" style="vsdxID=10;fillColor=#2d5967;gradientColor=none;shape=stencil(lZbbUsMgEIafJrc7wMIC1x7ew9FqM9bWSevp7SUSCAuV6h0hu/l+9hQGvDpu7143gxLH03R43nyMD6ftgNeDUuN+u5nGU1gNeDPg1eNh2jxNh7f9Q3x+vZst59XL4X3+wmf0swasnr2U+Io7Uoif59tofv82RXsZXzsE5xcHyT3Ep4obXoGQi03a8mBxscLK7QuzjfQlezfuC6mr/aLEgzI9qd4AGi41+JCqxAownosNVtZzsc6Ak1zubGW7oVJgZcN3jvOtB+NavuN8S0ANXnfxFoGwwUtb4QU4W+EdEHE8OTD18S141+OTzlHMfGr4hCDq4yP4KvzBinzFlykjZ6ul9Ig7Jgi2vzugAuSdYAQI8x+CDnXfKeDWQTpQ3RAWwUnNRiCqCi4DvWzJ0KX6Ygpl0IvdEiqKI/FlbqpcQkWhJb5o+G0FByPTxxetkWcNKOT4ss1WvFQcf6aB52/p7gARZ/ma8+cxoxu+lhemXbCx9PdpFwJKXa05l1lrkFrNmrmzuFLBVZa/A0xfEbIH1pjPuoLT+E9gZXPaEtmskxhboxQkAoe/B6n0WLrYpcI768BjqqkaoT1jg9W4vySFJCj1H4eQHe5Qh7p0SWnXUJVjmQ9V1VInzdVvn2u9eEsIi/WG8TjudvGCUr6vbyRhK95m8OYb);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="14.32558139534881" width="4.775193798449603" x="5.457364341085261" y="9.550387596899206" /></mxCell>
<mxCell id="nosql_endpoint_i9" parent="nosql_endpoint_i2" style="vsdxID=11;fillColor=#2d5967;gradientColor=none;shape=stencil(lZbddtMwDMefJrc6tuTP6zHeY4d1NIfS7mQdlLdHwXFsy8Wwu0SR/PtblhRP9PB2fHo9TKjersvl2+Hn/Hw9TvRpQpzPx8MyX/lposeJHl4uy+Hrcnk/P6f316fVc336fvmxrnBLcWjA2TUK1a9kUaD0H8Pn5P/lfUkBOn3XDnLAZlHp9YbpNQCFzQHzkrhZbpQtBjef3RJcjT3N50pm5b+pUODdSKYFFVqZuiySpUYI1EplJ7StVm3Axlbs6mWGSfLgXIfX1OJ5W973fGr5SOCx49shHx043/GDFfwIRuA1kGvxpMGTwCMoGuHJAsrtU4cnB0ELvsvVV/gOtNx+AD0oljoiWQyKom4DnAfr24AIMXyEYD3Ej/gHDWGYQVcOfTMFyppKBu2erpzBwCjfnaA4wMBq/bB+QnYo+LBPir1+3N4sOz7mo6nrV+K57sZ4BSSGDMd4sXtuMjQdPohRw+2bE1Lx/ZBf+uLvdB6cPdyJ4lUdeEvY/SnXlEjkVMaRSr/XQ5bJIV7MmLWjYqtTK9Wq5L1gN2HUcLryT0CUZ1l1w3gsMzDPWwMUW3btlbNE+cTuZqmO2PpXgx6kdVeWe5UH6v97GwdmsHivhsJoFPT+fEJhOMw5JIpusODEr4xPJIp6VN0srf/2JJzuqv339YAfyt3iZT6d0tWk/i7vImxK9xh6/A0=);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="14.32558139534881" width="4.775193798449603" x="15.348837209302296" y="9.550387596899206" /></mxCell>
<mxCell id="nosql_dedicated_i2" parent="139766069534000" style="vsdxID=4;fillColor=none;gradientColor=none;strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="18.23255813953485" width="16.49612403100772" x="81.75193798449615" y="4.935242567760066e-14" /></mxCell>
<mxCell id="nosql_dedicated_i3" parent="nosql_dedicated_i2" style="vsdxID=5;fillColor=#FCFBFA;gradientColor=none;shape=stencil(lZTRcoMgEEW/htcdYAHlOU3+I9OY6tRqxpg2/fviQHXBEds3WO56rrC7DA/3+nyrmOT3cejfq6/mMtYMX5iUTVdXQzO6FcMjw8O1H6q3oX90F7+/nSfltProP6cvPH2e5lOK5N9+K7jfn7z29TF4sfDHSkEpQoKIM/hT+gAH/isJEWvBYBDhShQipYHCUHbbdMQnSQhcBdrmvPLEpwKFidPYplPIcs+mEwn5HyyCVXksQqF3sQjaZLFLSoggGBODpQGrYziPwXM1ID3eQBYIXMfMpBTcw1sbA4krXIv++rdz0ZFrni9Rphq5fooMe++B12xSN5tsUn1ZdlzTcQ/QjI2mSc3SlCVkkkbQGpKWXbp6ozKSQREbzQ8Vt1im0bVpWz/M6Hk6vVzITz48/gA=);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="17.798449612403065" width="16.062015503875937" x="0.21705426356589105" y="0.21705426356589105" /></mxCell>
<mxCell id="nosql_dedicated_i4" parent="nosql_dedicated_i2" style="vsdxID=6;fillColor=#FCFBFA;gradientColor=none;shape=stencil(lVbRcsIgEPyavDJwFwh5tu1/ODXWTK1xorb270tKYg5uAvEtnrvswS07FLi5HLbnpgB5ufbdZ/PT7q6HAl8KgPZ0aPr26r4KfC1ws+/65qPvbqed/33eDsjh66v7Hla4e56WQqqBBfLXV0Cg/S+8efz7rfcE5f+vQNiRoCKGvIOv1JVAM4LGkhGqHEHIQWNJlaLElPjAqUJ1xzHI5atQ3qEs5vW1kPCsvhbK5PW1gHqNfrj/Y3siw6IMX7Fa2OS0KGUquVbKsGFjWMOOaCBsmHoFY9SCPqIwZaRPVobJQSayC20SGQgXdh8eFyEsHG/cLbBm6dyAgYBbYLHZrLccRTNrW2TiOhIn/l8Wz10sQlHswk7alVB1KE6u/rJJ4kQJp5RPoFxiydTGSsWOVYbbIus9Kia6q3xT2ROVPKZUJMwGWa2RrZMXPpZ11sS0rHO4zcqmg4mNJJtLhDHFQi0wOiA6u6lbKYuc3ybMgrS2LBLnVWOZRx6R7jDGrIujGb8yjWYCCSOTaXQYOGQazZqIK/Mk4srO4XnhJ7dMriLw8YWOTlgiMEQufwKw+5jfTvv2ePRPL/p//NZyJf9Ow9c/);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="18.23255813953485" width="16.49612403100772" /></mxCell>
<mxCell id="nosql_dedicated_i5" parent="nosql_dedicated_i2" style="vsdxID=7;fillColor=#2d5967;gradientColor=none;shape=stencil(lVPbDoIwDP2avTZbyxg8e/kPoyiLCGbg7e+FdMq2BBPfejntOe06Qau+3l0rgbIfXHeuHvYw1ILWAtG2deXsMFqCNoJWx85VJ9fd2gP7192EnKxLd586PLlOSTnVoHyxz96WofubY6ziZJGBRA/3IQ0lceSJHMkNoPIgHypBGQ8iX/ZhpQSxwEwIpoyZg6aeRo1iipg5kEfhgF/iaN7GtsFq4sWUEjD/JVEVoLJEooFkOaRB61ji9wWWdvMBLPDmGWQ65p1beo5CgcmTN5m1UXoKtDByvJ+fp/MHdDTm6zzapuHjDvPpNY8h/gm0eQM=);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="0.6511627906976731" width="4.12403100775193" x="6.07751937984495" y="12.589147286821682" /></mxCell>
<mxCell id="nosql_dedicated_i6" parent="nosql_dedicated_i2" style="vsdxID=8;fillColor=#2d5967;gradientColor=none;shape=stencil(lVPRkoIwDPyavmbahFL67Ol/OCdK5zhwKnr494Kp0nLizb2lyya7TRdBq1O1PZYC5anz7Vf543ZdJehDILqmKr3rhkrQWtBq3/ry4Ntzs+PzcTsyx+q7vYwTeu6TYwfKK5+sBDR3ZMPkz7NntmKCKkBloSVA1gAx0iMjpEHrQAqQkkGoJwb0Q5hSwoJunkGmU91pZNAoFJg8lY28zXSewr+uXLsm2s/Ej/e14LLIQGLqUoPVqc3cAKqZTVD2/XqejAVlQjB29i7T0McjDGaKVDmyR2kg6MV909X8EZ1/kYdiSuje1TUHPP4+T/QA8d9A6xs=);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="0.6511627906976731" width="4.12403100775193" x="6.07751937984495" y="8.46511627906975" /></mxCell>
<mxCell id="nosql_dedicated_i7" parent="nosql_dedicated_i2" style="vsdxID=9;fillColor=#2d5967;gradientColor=none;shape=stencil(lVhdd9sgDP01edUBhPl47rr/0bOma866pidNt/bfT54NCGEb5y3Bku9FV0jCB7x7f354Ox6Mer9ezr+Of0+P1+cDfjsYc3p9Pl5OV/p1wPsD3j2dL8efl/PH6+P0/+1htBx//T7/Gd/wOfnFCDGOXkZ9TSvagBv+r3yfHH58XCYP3brMSwhxclGfZlrxFpSbjeYlNVvg9HeY/38hf7yCaQaItsZUNaACpWs8RgobG9y5WVWDkn1wArhG1QjKd2ERjL8FFsGaHuzgdsBWqC+nV5YKzH5aCB7cNsvikXLDg0gENDNmoao6mZAMVlCdBxThUSIZeIqahhm2Rriy4zpCC4dFRFRyzcyYkoNIoGJjWrXXuXZzaAk7p+YqNkvwDWx5bLpxkg51FQq0F1s5ROKxeTC9ARxE8lmIWO/P6fLilAhUSrRMQNDiqJCVD1v4GPJrMv7Q4BsP3gh829Ql7cA7gd/bv0vPC7zKWAneghPoIeSwJXRmtO8YMIeZS+hUUU2VQrD1GlQUyUjxq9mSyC7UbI2GKOh6THtapMs9Zr4R9BZdw/JB5y0GwZYiGWq6ZNRXloz0jco6B6qrrENweOgo6wzEW5S1dq61+4W1tGXbE9ZS8ATZBWFtvEVV4uo3A7sgK/lY0bAWdCUr3RfWImxWjFZXq9M529AVY6rzG7pSNZqX9ulKm7Rmiyz1Cu1qtjRQ6Zos9XaFNVsa1Bq2EYLoH8Vqvcd7ESz+5lTMXBMtRrJUci2UanYv2hfzWAlvMxMPTbi4bqn0m5Kzpk2BVH0xn/a9qRU0iOmYp2wqpjFDscS2IrG9L2mK2cpv1FfusXRuG7K0mSDY0pkTBS5E8CK3xsoiisaCuLJk9bRtSuIObXmtXdeWl+11bbv9oBWX9Zl1bVnHWpdWdsKesk2r3SHu2MTlwW3FHecBwXdB3GbS6KnbvcPEUlYSYT4jJXVJNzlHsnGrqKuxJtzMcTXhHYPvzQ71aJ0vV6kTmM1CRgOzFrcr2wxqpKgR8g25tfJg1LHwYLY/LGBGyjNt0565XqljawiihnKrvVf9hUwYb2LynDOSZbwJQ2/z1HNU70JjROTHgUWEnuuTWh7dcZoLTQ1OJmrzFFCDCxJcp1ThtxlZZYiiOAQLk1F37665S/GY5tFI1oxRnhqc2eyVnbnonE8y6oWfaRJzfd+9hOfx1Pkc1dBcmRwIWSml3vKU1zWkUxLoR/la+HR6eZk+NvLn8usiLU1fJvH+Hw==);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="17.364341085271285" width="15.627906976744155" x="0.4341085271317821" y="0.4341085271317821" /></mxCell>
<mxCell id="nosql_dedicated_i8" parent="nosql_dedicated_i2" style="vsdxID=10;fillColor=#2d5967;gradientColor=none;shape=stencil(lZbbUsMgEIafJrc7wMIC1x7ew9FqM9bWSevp7SUSCAuV6h0hu/l+9hQGvDpu7143gxLH03R43nyMD6ftgNeDUuN+u5nGU1gNeDPg1eNh2jxNh7f9Q3x+vZst59XL4X3+wmf0swasnr2U+Io7Uoif59tofv82RXsZXzsE5xcHyT3Ep4obXoGQi03a8mBxscLK7QuzjfQlezfuC6mr/aLEgzI9qd4AGi41+JCqxAownosNVtZzsc6Ak1zubGW7oVJgZcN3jvOtB+NavuN8S0ANXnfxFoGwwUtb4QU4W+EdEHE8OTD18S141+OTzlHMfGr4hCDq4yP4KvzBinzFlykjZ6ul9Ig7Jgi2vzugAuSdYAQI8x+CDnXfKeDWQTpQ3RAWwUnNRiCqCi4DvWzJ0KX6Ygpl0IvdEiqKI/FlbqpcQkWhJb5o+G0FByPTxxetkWcNKOT4ss1WvFQcf6aB52/p7gARZ/ma8+cxoxu+lhemXbCx9PdpFwJKXa05l1lrkFrNmrmzuFLBVZa/A0xfEbIH1pjPuoLT+E9gZXPaEtmskxhboxQkAoe/B6n0WLrYpcI768BjqqkaoT1jg9W4vySFJCj1H4eQHe5Qh7p0SWnXUJVjmQ9V1VInzdVvn2u9eEsIi/WG8TjudvGCUr6vbyRhK95m8OYb);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="9.116279069767424" width="3.038759689922475" x="3.472868217054257" y="6.07751937984495" /></mxCell>
<mxCell id="nosql_dedicated_i9" parent="nosql_dedicated_i2" style="vsdxID=11;fillColor=#2d5967;gradientColor=none;shape=stencil(lZbddtMwDMefJrc6tuTP6zHeY4d1NIfS7mQdlLdHwXFsy8Wwu0SR/PtblhRP9PB2fHo9TKjersvl2+Hn/Hw9TvRpQpzPx8MyX/lposeJHl4uy+Hrcnk/P6f316fVc336fvmxrnBLcWjA2TUK1a9kUaD0H8Pn5P/lfUkBOn3XDnLAZlHp9YbpNQCFzQHzkrhZbpQtBjef3RJcjT3N50pm5b+pUODdSKYFFVqZuiySpUYI1EplJ7StVm3Axlbs6mWGSfLgXIfX1OJ5W973fGr5SOCx49shHx043/GDFfwIRuA1kGvxpMGTwCMoGuHJAsrtU4cnB0ELvsvVV/gOtNx+AD0oljoiWQyKom4DnAfr24AIMXyEYD3Ej/gHDWGYQVcOfTMFyppKBu2erpzBwCjfnaA4wMBq/bB+QnYo+LBPir1+3N4sOz7mo6nrV+K57sZ4BSSGDMd4sXtuMjQdPohRw+2bE1Lx/ZBf+uLvdB6cPdyJ4lUdeEvY/SnXlEjkVMaRSr/XQ5bJIV7MmLWjYqtTK9Wq5L1gN2HUcLryT0CUZ1l1w3gsMzDPWwMUW3btlbNE+cTuZqmO2PpXgx6kdVeWe5UH6v97GwdmsHivhsJoFPT+fEJhOMw5JIpusODEr4xPJIp6VN0srf/2JJzuqv339YAfyt3iZT6d0tWk/i7vImxK9xh6/A0=);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="9.116279069767424" width="3.038759689922475" x="9.767441860465098" y="6.07751937984495" /></mxCell>
<mxCell id="nosql_tables_i2" parent="139766069536112" style="vsdxID=4;fillColor=none;gradientColor=none;strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="18.23255813953485" width="16.49612403100772" x="71.75193798449615" y="4.935242567760066e-14" /></mxCell>
<mxCell id="nosql_tables_i3" parent="nosql_tables_i2" style="vsdxID=5;fillColor=#FCFBFA;gradientColor=none;shape=stencil(lZTRcoMgEEW/htcdYAHlOU3+I9OY6tRqxpg2/fviQHXBEds3WO56rrC7DA/3+nyrmOT3cejfq6/mMtYMX5iUTVdXQzO6FcMjw8O1H6q3oX90F7+/nSfltProP6cvPH2e5lOK5N9+K7jfn7z29TF4sfDHSkEpQoKIM/hT+gAH/isJEWvBYBDhShQipYHCUHbbdMQnSQhcBdrmvPLEpwKFidPYplPIcs+mEwn5HyyCVXksQqF3sQjaZLFLSoggGBODpQGrYziPwXM1ID3eQBYIXMfMpBTcw1sbA4krXIv++rdz0ZFrni9Rphq5fooMe++B12xSN5tsUn1ZdlzTcQ/QjI2mSc3SlCVkkkbQGpKWXbp6ozKSQREbzQ8Vt1im0bVpWz/M6Hk6vVzITz48/gA=);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="17.798449612403065" width="16.062015503875937" x="0.21705426356589105" y="0.21705426356589105" /></mxCell>
<mxCell id="nosql_tables_i4" parent="nosql_tables_i2" style="vsdxID=6;fillColor=#FCFBFA;gradientColor=none;shape=stencil(lVbRcsIgEPyavDJwFwh5tu1/ODXWTK1xorb270tKYg5uAvEtnrvswS07FLi5HLbnpgB5ufbdZ/PT7q6HAl8KgPZ0aPr26r4KfC1ws+/65qPvbqed/33eDsjh66v7Hla4e56WQqqBBfLXV0Cg/S+8efz7rfcE5f+vQNiRoCKGvIOv1JVAM4LGkhGqHEHIQWNJlaLElPjAqUJ1xzHI5atQ3qEs5vW1kPCsvhbK5PW1gHqNfrj/Y3siw6IMX7Fa2OS0KGUquVbKsGFjWMOOaCBsmHoFY9SCPqIwZaRPVobJQSayC20SGQgXdh8eFyEsHG/cLbBm6dyAgYBbYLHZrLccRTNrW2TiOhIn/l8Wz10sQlHswk7alVB1KE6u/rJJ4kQJp5RPoFxiydTGSsWOVYbbIus9Kia6q3xT2ROVPKZUJMwGWa2RrZMXPpZ11sS0rHO4zcqmg4mNJJtLhDHFQi0wOiA6u6lbKYuc3ybMgrS2LBLnVWOZRx6R7jDGrIujGb8yjWYCCSOTaXQYOGQazZqIK/Mk4srO4XnhJ7dMriLw8YWOTlgiMEQufwKw+5jfTvv2ePRPL/p//NZyJf9Ow9c/);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="18.23255813953485" width="16.49612403100772" /></mxCell>
<mxCell id="nosql_tables_i5" parent="nosql_tables_i2" style="vsdxID=7;fillColor=#2d5967;gradientColor=none;shape=stencil(lVPbDoIwDP2avTZbyxg8e/kPoyiLCGbg7e+FdMq2BBPfejntOe06Qau+3l0rgbIfXHeuHvYw1ILWAtG2deXsMFqCNoJWx85VJ9fd2gP7192EnKxLd586PLlOSTnVoHyxz96WofubY6ziZJGBRA/3IQ0lceSJHMkNoPIgHypBGQ8iX/ZhpQSxwEwIpoyZg6aeRo1iipg5kEfhgF/iaN7GtsFq4sWUEjD/JVEVoLJEooFkOaRB61ji9wWWdvMBLPDmGWQ65p1beo5CgcmTN5m1UXoKtDByvJ+fp/MHdDTm6zzapuHjDvPpNY8h/gm0eQM=);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="0.6511627906976731" width="4.12403100775193" x="6.07751937984495" y="12.589147286821682" /></mxCell>
<mxCell id="nosql_tables_i6" parent="nosql_tables_i2" style="vsdxID=8;fillColor=#2d5967;gradientColor=none;shape=stencil(lVPRkoIwDPyavmbahFL67Ol/OCdK5zhwKnr494Kp0nLizb2lyya7TRdBq1O1PZYC5anz7Vf543ZdJehDILqmKr3rhkrQWtBq3/ry4Ntzs+PzcTsyx+q7vYwTeu6TYwfKK5+sBDR3ZMPkz7NntmKCKkBloSVA1gAx0iMjpEHrQAqQkkGoJwb0Q5hSwoJunkGmU91pZNAoFJg8lY28zXSewr+uXLsm2s/Ej/e14LLIQGLqUoPVqc3cAKqZTVD2/XqejAVlQjB29i7T0McjDGaKVDmyR2kg6MV909X8EZ1/kYdiSuje1TUHPP4+T/QA8d9A6xs=);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="0.6511627906976731" width="4.12403100775193" x="6.07751937984495" y="8.46511627906975" /></mxCell>
<mxCell id="nosql_tables_i7" parent="nosql_tables_i2" style="vsdxID=9;fillColor=#2d5967;gradientColor=none;shape=stencil(lVhdd9sgDP01edUBhPl47rr/0bOma866pidNt/bfT54NCGEb5y3Bku9FV0jCB7x7f354Ox6Mer9ezr+Of0+P1+cDfjsYc3p9Pl5OV/p1wPsD3j2dL8efl/PH6+P0/+1htBx//T7/Gd/wOfnFCDGOXkZ9TSvagBv+r3yfHH58XCYP3brMSwhxclGfZlrxFpSbjeYlNVvg9HeY/38hf7yCaQaItsZUNaACpWs8RgobG9y5WVWDkn1wArhG1QjKd2ERjL8FFsGaHuzgdsBWqC+nV5YKzH5aCB7cNsvikXLDg0gENDNmoao6mZAMVlCdBxThUSIZeIqahhm2Rriy4zpCC4dFRFRyzcyYkoNIoGJjWrXXuXZzaAk7p+YqNkvwDWx5bLpxkg51FQq0F1s5ROKxeTC9ARxE8lmIWO/P6fLilAhUSrRMQNDiqJCVD1v4GPJrMv7Q4BsP3gh829Ql7cA7gd/bv0vPC7zKWAneghPoIeSwJXRmtO8YMIeZS+hUUU2VQrD1GlQUyUjxq9mSyC7UbI2GKOh6THtapMs9Zr4R9BZdw/JB5y0GwZYiGWq6ZNRXloz0jco6B6qrrENweOgo6wzEW5S1dq61+4W1tGXbE9ZS8ATZBWFtvEVV4uo3A7sgK/lY0bAWdCUr3RfWImxWjFZXq9M529AVY6rzG7pSNZqX9ulKm7Rmiyz1Cu1qtjRQ6Zos9XaFNVsa1Bq2EYLoH8Vqvcd7ESz+5lTMXBMtRrJUci2UanYv2hfzWAlvMxMPTbi4bqn0m5Kzpk2BVH0xn/a9qRU0iOmYp2wqpjFDscS2IrG9L2mK2cpv1FfusXRuG7K0mSDY0pkTBS5E8CK3xsoiisaCuLJk9bRtSuIObXmtXdeWl+11bbv9oBWX9Zl1bVnHWpdWdsKesk2r3SHu2MTlwW3FHecBwXdB3GbS6KnbvcPEUlYSYT4jJXVJNzlHsnGrqKuxJtzMcTXhHYPvzQ71aJ0vV6kTmM1CRgOzFrcr2wxqpKgR8g25tfJg1LHwYLY/LGBGyjNt0565XqljawiihnKrvVf9hUwYb2LynDOSZbwJQ2/z1HNU70JjROTHgUWEnuuTWh7dcZoLTQ1OJmrzFFCDCxJcp1ThtxlZZYiiOAQLk1F37665S/GY5tFI1oxRnhqc2eyVnbnonE8y6oWfaRJzfd+9hOfx1Pkc1dBcmRwIWSml3vKU1zWkUxLoR/la+HR6eZk+NvLn8usiLU1fJvH+Hw==);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="17.364341085271285" width="15.627906976744155" x="0.4341085271317821" y="0.4341085271317821" /></mxCell>
<mxCell id="nosql_tables_i8" parent="nosql_tables_i2" style="vsdxID=10;fillColor=#2d5967;gradientColor=none;shape=stencil(lZbbUsMgEIafJrc7wMIC1x7ew9FqM9bWSevp7SUSCAuV6h0hu/l+9hQGvDpu7143gxLH03R43nyMD6ftgNeDUuN+u5nGU1gNeDPg1eNh2jxNh7f9Q3x+vZst59XL4X3+wmf0swasnr2U+Io7Uoif59tofv82RXsZXzsE5xcHyT3Ep4obXoGQi03a8mBxscLK7QuzjfQlezfuC6mr/aLEgzI9qd4AGi41+JCqxAownosNVtZzsc6Ak1zubGW7oVJgZcN3jvOtB+NavuN8S0ANXnfxFoGwwUtb4QU4W+EdEHE8OTD18S141+OTzlHMfGr4hCDq4yP4KvzBinzFlykjZ6ul9Ig7Jgi2vzugAuSdYAQI8x+CDnXfKeDWQTpQ3RAWwUnNRiCqCi4DvWzJ0KX6Ygpl0IvdEiqKI/FlbqpcQkWhJb5o+G0FByPTxxetkWcNKOT4ss1WvFQcf6aB52/p7gARZ/ma8+cxoxu+lhemXbCx9PdpFwJKXa05l1lrkFrNmrmzuFLBVZa/A0xfEbIH1pjPuoLT+E9gZXPaEtmskxhboxQkAoe/B6n0WLrYpcI768BjqqkaoT1jg9W4vySFJCj1H4eQHe5Qh7p0SWnXUJVjmQ9V1VInzdVvn2u9eEsIi/WG8TjudvGCUr6vbyRhK95m8OYb);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="9.116279069767424" width="3.038759689922475" x="3.472868217054257" y="6.07751937984495" /></mxCell>
<mxCell id="nosql_tables_i9" parent="nosql_tables_i2" style="vsdxID=11;fillColor=#2d5967;gradientColor=none;shape=stencil(lZbddtMwDMefJrc6tuTP6zHeY4d1NIfS7mQdlLdHwXFsy8Wwu0SR/PtblhRP9PB2fHo9TKjersvl2+Hn/Hw9TvRpQpzPx8MyX/lposeJHl4uy+Hrcnk/P6f316fVc336fvmxrnBLcWjA2TUK1a9kUaD0H8Pn5P/lfUkBOn3XDnLAZlHp9YbpNQCFzQHzkrhZbpQtBjef3RJcjT3N50pm5b+pUODdSKYFFVqZuiySpUYI1EplJ7StVm3Axlbs6mWGSfLgXIfX1OJ5W973fGr5SOCx49shHx043/GDFfwIRuA1kGvxpMGTwCMoGuHJAsrtU4cnB0ELvsvVV/gOtNx+AD0oljoiWQyKom4DnAfr24AIMXyEYD3Ej/gHDWGYQVcOfTMFyppKBu2erpzBwCjfnaA4wMBq/bB+QnYo+LBPir1+3N4sOz7mo6nrV+K57sZ4BSSGDMd4sXtuMjQdPohRw+2bE1Lx/ZBf+uLvdB6cPdyJ4lUdeEvY/SnXlEjkVMaRSr/XQ5bJIV7MmLWjYqtTK9Wq5L1gN2HUcLryT0CUZ1l1w3gsMzDPWwMUW3btlbNE+cTuZqmO2PpXgx6kdVeWe5UH6v97GwdmsHivhsJoFPT+fEJhOMw5JIpusODEr4xPJIp6VN0srf/2JJzuqv339YAfyt3iZT6d0tWk/i7vImxK9xh6/A0=);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="9.116279069767424" width="3.038759689922475" x="9.767441860465098" y="6.07751937984495" /></mxCell>
<mxCell connectable="0" id="functions_i2" parent="139766069542640" style="group" value="" vertex="1"><mxGeometry as="geometry" height="44.0" width="33.908256880733944" y="9.178386898625882e-14" x="53.04587155963303" /></mxCell>
<mxCell id="functions_i3" parent="functions_i2" style="vsdxID=37;fillColor=none;gradientColor=none;strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="33.908256880733944" width="33.908256880733944" /></mxCell>
<mxCell id="functions_i4" parent="functions_i3" style="vsdxID=38;fillColor=none;gradientColor=none;strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="33.908256880733944" width="33.908256880733944" /></mxCell>
<mxCell id="functions_i5" parent="functions_i4" style="vsdxID=39;fillColor=#FCFBFA;gradientColor=none;shape=stencil(lZPRDoIwDEW/Zq9LWUHCs+J/EAVZRCATFP/eYYdsAzW+td2922mzMtxey6zNmYBrp5pzfpfHrmS4Y0LIusyV7HTEMGW4LRqVn1TT10fK22xUjtGluY03DOSLOEajScCDCknC482rsif9oVdkCEggeIjGEfgWGASVwChMmsQchVGgqzBpEvLQfrWStUUJDuKb+QMhuHgz8ERnteDyTnDWVBzcVTiNvnFnCN/o9Cyi2CUEFy8Ab3xWB+hLfOJVxFnuI3+AnA1L6kEsG/HJB1zOxkNfBf39Hf/V62D++4WsKlod+9zfFV2iPcP0CQ==);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="33.10091743119266" width="33.10091743119266" x="0.4036697247706422" y="0.4036697247706422" /></mxCell>
<mxCell id="functions_i6" parent="functions_i4" style="vsdxID=40;fillColor=#FCFBFA;gradientColor=none;shape=stencil(lZXRdoIwDIafprc9aUMpvXb6Hp6JgzMmHsSNvf1gLbQNCHpX4h/88iehDHe34njNmYRb29Sf+U95aguGb0zK8lLkTdn2J4Z7hrtz3eQfTX2/nOzz9Tgoh9NX/T28obN5BjmqIUvCr41Ijtl/4GD17/fGJgiXoXhiXIYgKdBJJ9IcR5ELJVy6SIdzkQulPMHwz6vyEsIGCRN+JlZpgxRfgFEEN6jJV5ClhDfwCqlqEbgvR8S8VE95e5c0wdU8lTFu77cmtIprEdMGIs+v9GPYIGG5GZQ1SBCzHstZPXI2LDhzCZdnkIzB5sy+qt/aCXihxbBuWaZiyyD2C6hZdAghdmp9YSAi21wWYHTyREInb+J3EQHANro5Sh41R8U7TeQLGy2Ih56BQgXbPJWCVPPcenj9c9thDNcp/U5O3Ry5Um5EjErsXPjorLu5Nrr9wV8E57Kq7D0S/k4vjj5kLx3c/wE=);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="33.908256880733944" width="33.908256880733944" /></mxCell>
<mxCell id="functions_i7" parent="functions_i3" style="vsdxID=41;fillColor=none;gradientColor=none;strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="32.29357798165138" width="32.29357798165138" x="0.8073394495412844" y="0.8073394495412844" /></mxCell>
<mxCell id="functions_i8" parent="functions_i7" style="vsdxID=42;fillColor=#2d5967;gradientColor=none;shape=stencil(lZXLcoMwDEW/xlvGWDzidZr8R6YhhSmFDCEt+ftCbbAkB+Lu/LgyR/IVFrC/ladrIZS89V37WfxU574U8CaUqpqy6Kp+HAk4CNhf2q746Np7czbz62lSTqOv9ns6YTBxOo3SeIpS8mFW5N/saMR11SBxEqlkXft+78zJsdmMI62tOsZyOSgyfdipsrtAd2H5drpOJgmWzra4JIXSO0qFsOcVKSkaqgNQyVO4scZ5RgCZnBPqXSRjSukYONRMueQBXAAOY6OETv+84B6kno9bIBVF1LnLm175AL774KX9XniVGTtzNVzJ38so88puneRSSr2UxihbqK20nCqsszw9hwWvuzCImkV5wmkpKlKE2QQFhPkEBdiVhEPyhoPFWesdB5uUfstxfcDlIwx01+z6EwqKFUF/rgCf/jtgHLj//aWqa/Nc4H3+PoxL5m2Bwy8=);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="32.29357798165138" width="32.29357798165138" /></mxCell>
<mxCell id="functions_i9" parent="functions_i7" style="vsdxID=43;fillColor=#2d5967;gradientColor=none;shape=stencil(pZLRDsIgDEW/hlcCNG68z/kfS8aEiLCwOfXvhTTGTSPqfOul57YNuQSqQTe9IoINY/AHdTbtqAlsiRDGaRXMGCsCNYGq80Htgz+5FnXfJDJVRz+lCRf0seQQ7IqKM9Q7RK1xM/TeXAVn0JVgdn0WXf4AByrKJV5QuXk/Wxa0hP8MEijPGF5P+tnw4aQvDLF4hKYz1mLm5v3nkMUnDCjUNw==);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="6.862385321100918" width="8.880733944954128" x="3.229357798165138" y="21.394495412844037" /></mxCell>
<mxCell id="functions_i10" parent="functions_i7" style="vsdxID=44;fillColor=#2d5967;gradientColor=none;shape=stencil(pZLdDsIgDIWfhlsC1Bm8nvM9lowJEWFhmz9vL6QxbhpZnHc99DttQw6Bstd1p4hg/RD8SV1NM2gCeyKEcVoFM8SKQEWgbH1Qx+BH16Du6kSm6uwvacINfSw5BLuj4gz1AVFr3AR9NlfBGXQlmF2fRec/sKFSzOktlcX30buCcvmfQQLlGcPHRb/yCwct87F4BaY11mLepv33gMUnDCdUDw==);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="6.862385321100918" width="25.027522935779817" x="3.229357798165138" y="3.229357798165138" /></mxCell>
<mxCell id="functions_i11" parent="functions_i7" style="vsdxID=45;fillColor=#2d5967;gradientColor=none;shape=stencil(pZLLDoMgEEW/hi0BplRdW/sfJmIhpWKQvv6+kklT7cPWupsL5w7D5BLIO122igjWBe/26myqoAlsiBCm0cqb0FcECgJ57bzaeXdsKtRtGclYHdwpdrigjzMWPYJdUaPaImpNM0D/BO8vvEWzjEqxBJ+AZ3xtEh0vLBM0XY/gFCiXn3snlK8W8VzSBCZ28jLQbMOXiX4w9MUjYbWxFgM6vH9OZH+EaYbiBg==);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="6.862385321100918" width="16.954128440366972" x="3.229357798165138" y="12.513761467889909" /></mxCell>
<mxCell id="functions_i12" parent="functions_i7" style="vsdxID=46;fillColor=#2d5967;gradientColor=none;shape=stencil(nZBLCoAwDERPk31tjuDnHoLVBmsrtf5ub0sQRdzobiZ5ycAA5pOuRwVSTMG7Xq3UBA1YgJRktfIUogIsAfPWedV5N9uG/VgnMqnBLenDxneZEOlGip09u4pRQ/aG/gTPhFf0Gf8J/otGcdXRkjHc5n3/rC+OuHosDw==);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="5.651376146788991" width="6.055045871559633" x="21.79816513761468" y="12.917431192660551" /></mxCell>
<mxCell id="functions_i13" parent="functions_i7" style="vsdxID=47;fillColor=#2d5967;gradientColor=none;shape=stencil(nZBLCoAwDERPk31tjuDnHoLVBmsrtf5ub0sQRdzobiZ5ycAA5pOuRwVSTMG7Xq3UBA1YgJRktfIUogIsAfPWedV5N9uG/VgnMqnBLenDxneZEOlGip09u4pRQ/aG/gTPhFf0Gf8J/otGcdXRkjHc5n3/rC+OuHosDw==);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="5.651376146788991" width="6.055045871559633" x="21.79816513761468" y="21.79816513761468" /></mxCell>
<mxCell id="functions_i14" parent="functions_i7" style="vsdxID=48;fillColor=#2d5967;gradientColor=none;shape=stencil(nZBLCoAwDERPk31tjuDnHoLVBmsrtf5ub0sQRdzobiZ5ycAA5pOuRwVSTMG7Xq3UBA1YgJRktfIUogIsAfPWedV5N9uG/VgnMqnBLenDxneZEOlGip09u4pRQ/aG/gTPhFf0Gf8J/otGcdXRkjHc5n3/rC+OuHosDw==);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="5.651376146788991" width="6.055045871559633" x="14.128440366972479" y="21.79816513761468" /></mxCell>
<mxCell id="monitoring_i2" parent="139766069584112" style="vsdxID=76;fillColor=none;gradientColor=none;strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="26.2018348623853" width="26.2018348623853" x="46.89908256880736" /></mxCell>
<mxCell id="monitoring_i3" parent="monitoring_i2" style="vsdxID=77;fillColor=none;gradientColor=none;strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="26.2018348623853" width="26.2018348623853" /></mxCell>
<mxCell id="monitoring_i4" parent="monitoring_i3" style="vsdxID=78;fillColor=#FCFBFA;gradientColor=none;shape=stencil(lZPRDoIwDEW/Zq9LWUHCs+J/EAVZRCATFP/eYYdsAzW+td2922mzMtxey6zNmYBrp5pzfpfHrmS4Y0LIusyV7HTEMGW4LRqVn1TT10fK22xUjtGluY03DOSLOEajScCDCknC482rsif9oVdkCEggeIjGEfgWGASVwChMmsQchVGgqzBpEvLQfrWStUUJDuKb+QMhuHgz8ERnteDyTnDWVBzcVTiNvnFnCN/o9Cyi2CUEFy8Ab3xWB+hLfOJVxFnuI3+AnA1L6kEsG/HJB1zOxkNfBf39Hf/V62D++4WsKlod+9zfFV2iPcP0CQ==);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="25.577981651376124" width="25.577981651376124" x="0.3119266055045869" y="0.3119266055045869" /></mxCell>
<mxCell id="monitoring_i5" parent="monitoring_i3" style="vsdxID=79;fillColor=#FCFBFA;gradientColor=none;shape=stencil(lZXRdoIwDIafprc9aUMpvXb6Hp6JgzMmHsSNvf1gLbQNCHpX4h/88iehDHe34njNmYRb29Sf+U95aguGb0zK8lLkTdn2J4Z7hrtz3eQfTX2/nOzz9Tgoh9NX/T28obN5BjmqIUvCr41Ijtl/4GD17/fGJgiXoXhiXIYgKdBJJ9IcR5ELJVy6SIdzkQulPMHwz6vyEsIGCRN+JlZpgxRfgFEEN6jJV5ClhDfwCqlqEbgvR8S8VE95e5c0wdU8lTFu77cmtIprEdMGIs+v9GPYIGG5GZQ1SBCzHstZPXI2LDhzCZdnkIzB5sy+qt/aCXihxbBuWaZiyyD2C6hZdAghdmp9YSAi21wWYHTyREInb+J3EQHANro5Sh41R8U7TeQLGy2Ih56BQgXbPJWCVPPcenj9c9thDNcp/U5O3Ry5Um5EjErsXPjorLu5Nrr9wV8E57Kq7D0S/k4vjj5kLx3c/wE=);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="26.2018348623853" width="26.2018348623853" /></mxCell>
<mxCell id="monitoring_i6" parent="monitoring_i2" style="vsdxID=80;fillColor=none;gradientColor=none;strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="24.95412844036695" width="24.95412844036695" x="0.6238532110091738" y="0.6238532110091738" /></mxCell>
<mxCell id="monitoring_i7" parent="monitoring_i6" style="vsdxID=81;fillColor=#2d5967;gradientColor=none;shape=stencil(pVjbctsgEP0ave5wvzyn6X9kGqfW1LUzitM6f19U2YIFaxHWmxDniMNe2BWdfPrYv7zvOsE+zsPp1+5v/3red/JbJ0R/3O+G/hyeOvncyae307D7OZw+j6/T+P1lRI5Pv09/xi9cJp7XoPnIEuxresP+j75P4EN/TMAKhFrG/vgcpi/zaZKD91c0T+HsItDw6zoU11mJZ+W8tl5WxpAsbyhdDIvyDqtKZN/eMIalJXaQGHJXHHfgNRJIwoUH7tbDlQau1sO1BmnWwy0HKdbDHQfdsNUQfZYUk/vOO2C3cOW5d3J33fw3e1jmABllEMEV8fdDsRDpb5+bRQos0du4b5wMlyhpzkuUEEt2pLIYp7wEi+NFOHL73kSbP0iQEgi8DSGJ8cpT+DArcYIoQeHDjo1HeCPIDRQW0qT+VoPW8dhhxbErafMXSZXji4A1RVbNlBizBkQWsyqL2QSx6tROCVdLkGbz/nFwLWkTp3C8O1F8URQ2WiwMtKuqnsWBIEQeyKMFqcgvCI6RmaJBqU34ZkHbCVmyODCyZYWSYBhJ0KEk2m2EZknbCdhKVoHjLSuUBGNpggVtthGCpCZFD+DbtlwxalmFKyuEbqnJzQXe0HWVA7Ob8BU9oZfkTRsuCZr0mQou8JvwteMltOZNLigJ1tDNY9H8NxNqyZ8XkQJf1rr8zyxSkno3F8S5A+hQtUsQ6xrpsq+yZHVRwLO+zRKxxYBjzyj6PAhNDz5v6C7vTlfrat0Ny7OD8sqdLmy2uIj2zXqw1HPL/w6VEFpxcoWHeIfw1h8O0xVEOp/fOYRX032FfP4H);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="24.95412844036695" width="24.95412844036695" /></mxCell>
<mxCell id="monitoring_i8" parent="monitoring_i6" style="vsdxID=82;fillColor=#2d5967;gradientColor=none;shape=stencil(pZJNDoMgEIVPw5Yg01b31t7DRCykFAxqf25fyKRBDYtid2+G781kyCNQj7IdBOFsnJy9iafqJkngTDhXRgqnJq8INATq3jpxdXY2HdZDG8ig7vYRJrzQVzAWPJy9scbqgqhWZoHuBL8bkuh2fRa8F13/QMloBSs4dpKzoaD8+J8hdpKGU0XLQ44h+4YfDF7E0PRKa8zc8n0bMt/CgELzAQ==);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="2.8073394495412822" width="2.8073394495412822" x="1.8715596330275215" y="1.8715596330275215" /></mxCell>
<mxCell id="logging_i2" parent="139766069586800" style="vsdxID=16;fillColor=none;gradientColor=none;strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="26.129629629629623" width="27.074074074074066" x="46.462962962962955" /></mxCell>
<mxCell id="logging_i3" parent="logging_i2" style="vsdxID=17;fillColor=none;gradientColor=none;strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="26.129629629629623" width="27.074074074074066" /></mxCell>
<mxCell id="logging_i4" parent="logging_i3" style="vsdxID=18;fillColor=#FCFBFA;gradientColor=none;shape=stencil(lZRBcoMwDEVPw1YjSxjkdZrcI9OQwpSGDCFtevtC7UwsIGTYyeJ/8/jYSnhzKffnIiG8dG3zWfxUh65M+C0hqk5l0VZdXyW8TXhzbNrio22up4Nfn/eDcqi+mu9hh5v3kQObDi7CX99xDpD/OztvqKtTbMiARBsEMFswENhMG1Iw7rkhBZFl/fu19d9gwiuAOTjM2II38i0MirB0BGiCgrUiLMWBeU6JCtECyhIhajyClDRdT+M0IGq4KBWFOwsnFqzOEJfoRIBzTYgazyGkmeYjMKIRYxHP56IxY0PYNAexS6gGR1GygzTXsA9NaNgM3EvUTCDP17COz8cYNXaY6aGjafb3sKPDy9MfymPVLC9bELPm2jECsTLcc5y/1qsHx2tDXzzm1LGqaz/m4ufjuda3/Ezk7R8=);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="25.499999999999993" width="26.444444444444436" /></mxCell>
<mxCell id="logging_i5" parent="logging_i3" style="vsdxID=19;fillColor=#FCFBFA;gradientColor=none;shape=stencil(lVbbVuMwDPyavOrYkuPLM7D/wVnKNofSckLZLX+Pu3EUW20VeEvVmXg8uqWju/ft49umQ/N+HA8vm3/D03Hb0X2HOOy3m3E45qeOHjq6ez6Mmz/j4WP/NP1+ezwjz0+vh7/nN5wmXnTQxzMLzecUQSD3P/Brwv/+GCeCLQwPHgvDCoo5YQFFQFtAJUSQykEnugSVkAeT6sN3w74WWxHKyRH6oKlNAXrbqqXEV57l1qgS6j2fpekNc+ibgmMA6lV7K8ocSuC88LdKwnwHC1JvlVsSoKtyqQcKjdwVvAHfXi/lBOJtAgZwriU4iL1CIFmeyUAMtwk9JB0u/ab5fLZ7obDdCBhat3NOkFq7KxBxsq3mxkK4Xv1Sa0Vg9UmUcnUfFs/dSdIkEpDrVbw6I36KX5tB5vsJNrphQYwq07plpFVR9JBpjdLnk2mUrba66WTdeepE3bH+ucuJO+hmNhfM9bJD8KKnVgj9UlPc5kErbA/U4nMjKL5lfPCS4LQDcvcJRRHIq5OK2rqxRikyQnAk329JIeQbkPQ0aZvBcandIlxshsDNziXDnGWVGRCj6nIxVJhlUkXF74rAey+hJna2l6XW+xQlZp5dCeyq1LxDvJKJS6krQzUTnLC1GgPI/nCFtqNDWbZKga2MvPywfLA9D7vd9L1X/y8/8HJo+jikhy8=);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="26.129629629629623" width="27.074074074074066" /></mxCell>
<mxCell id="logging_i6" parent="logging_i2" style="vsdxID=20;fillColor=none;gradientColor=none;strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="24.555555555555546" width="25.814814814814806" x="0.3148148148148147" y="0.3148148148148147" /></mxCell>
<mxCell id="logging_i7" parent="logging_i6" style="vsdxID=21;fillColor=#2d5967;gradientColor=none;shape=stencil(lZPdcoIwEIWfJrc7Sdb8XVt9D0exZErBidjq2xeaAMla2undcjiHfBt2GW6v9eFSMcmvfejeqk9/6muGL0xK39ZV8P1QMdwx3J67UL2G7tae4vPlMDrH6r37GL9wjzmHoNSYkvwRFStAi29lHwPHW4gJ8RxJkpVgdJTucnZxl1xJsghOJBcmlwSNyYXUlc5vfJsBa9gQXuqnvAqcI7gKOMFVoJDQapCEdogZAmsA1TosL0gF5+vW/CZ+tD/9Bg3GlH1NibmrWZiacgKcLptaPLgyACXo4s97XIO0IHQJuQE6KQqsIpggyZxkMzdxI9hfrvPvuf53YCiWNTr7polbmL+nazdIcWVx9wU=);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="5.35185185185185" width="13.222222222222218" x="9.759259259259256" y="17.94444444444444" /></mxCell>
<mxCell id="logging_i8" parent="logging_i6" style="vsdxID=22;fillColor=#2d5967;gradientColor=none;shape=stencil(lZXRcoMgEEW/xtcdWEDhOU3/I9OYxmkaM8a05u+LQ0BYIm3fcL3XOXtdoBKb63F3aStk13HoP9rvbj8eK/FSIXbnYzt0o11VYluJzaEf2vehv5337vmym5Xz6rP/mr8wOR83oHB2Ibu7itEgXeXVGU7dOTVgnRoa0KZg0NCI1FCD4OsGCYhl/dttcD1wJxBgPBKnFjahF9XmIcIgYvIhEpnoUTEKGr0OGxkI/SprMGT0C2roJ4P3pFFKlP0p6NKHJ6V6ShrFc8/gJ8yCvmf0njUWUfznsJHBVRBBiiJtA7VIaS2J1ARXg1EprkVRZAo4YyktKlClEQ9635wsJrvoPSlwnoFyAsrCxpuy2QykQfS3rUXlGSlolaKylJOljIveM5Iky/89jTHbepSOpBhlNmU8gdBnv76RvOQpov0kT0ezLGfAVNqVHUFZPF//fSD/ZrCL5fw/dKeTuz7i9/S+sCV314jtDw==);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="23.29629629629629" width="23.29629629629629" /></mxCell>
<mxCell id="logging_i9" parent="logging_i6" style="vsdxID=23;fillColor=#2d5967;gradientColor=none;shape=stencil(nZLdCsIwDIWfJrcjNuvA6znfY7DOFms7uvn39rYEcQ4sxbtzki+5yAlQO+t+UiBwXoI/q7sZFg10ACGM0yqYJSqgDqgdfVCn4K9uYD/1iUzq4m9pw4PnJKYRgU+2O2R/ZNYat2Lfzb/gDNrIUvJ7pcCqbkphqivc/4Y3dxCyGM1eIc9G8cllNNZyrOv+NsdY4h+g7gU=);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="2.5185185185185177" width="0.9444444444444442" x="1.8888888888888884" y="2.203703703703703" /></mxCell>
<mxCell id="logging_i10" parent="logging_i6" style="vsdxID=24;fillColor=#2d5967;gradientColor=none;shape=stencil(nZBLCoAwDERPk31tjuDnHoLVBmsrtf5ub0sQRdzobiZ5ycAA5pOuRwVSTMG7Xq3UBA1YgJRktfIUogIsAfPWedV5N9uG/VgnMqnBLenDxneZEOlGip09u4pRQ/aG/gTPhFf0Gf8J/otGcdXRkjHc5n3/rC+OuHosDw==);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="0.3148148148148147" width="0.3148148148148147" x="4.092592592592592" y="4.092592592592592" /></mxCell>
<mxCell id="logging_i11" parent="logging_i6" style="vsdxID=25;fillColor=#2d5967;gradientColor=none;shape=stencil(nZBLCoAwDERPk31tjuDnHoLVBmsrtf5ub0sQRdzobiZ5ycAA5pOuRwVSTMG7Xq3UBA1YgJRktfIUogIsAfPWedV5N9uG/VgnMqnBLenDxneZEOlGip09u4pRQ/aG/gTPhFf0Gf8J/otGcdXRkjHc5n3/rC+OuHosDw==);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="0.3148148148148147" width="0.3148148148148147" x="4.092592592592592" y="2.8333333333333326" /></mxCell>
<mxCell id="logging_i12" parent="logging_i6" style="vsdxID=26;fillColor=#2d5967;gradientColor=none;shape=stencil(lZLZDoIwEEW/pq+T0qELz4j/QUKRRqQEcPt7WxsjaNDyNsu5N5PJJZiPTdlrwug4Dfaor6aaGoI7wpjpGj2YyVUEC4J5bQd9GOy5q0Lfl5701clevMMt6FgKmHkVo/cwSSh99vuAt6ab4akCqRa4YODbNYFESGS8/2sZBQsOii9wd57K1gWZBL485oe7pCDTWPj7L8iBi3UBE6Aw1p3GgpiA3PKQDc/eGJS/uCvemaxN24ZIz/efGXajkH8sHg==);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="2.5185185185185177" width="2.5185185185185177" x="5.666666666666665" y="1.8888888888888884" /></mxCell>
<mxCell id="logging_i13" parent="logging_i6" style="vsdxID=27;fillColor=#2d5967;gradientColor=none;shape=stencil(jVbLcsMgDPwaXzWAeJhz2v5HpnEaT9Mk4yRt+ve1i7FBih83hNcsKy2CAjfXw/ZSFUpcb835s/qpd7dDgS+FUvXpUDX1rR0V+FrgZn9uqo/mfD/tQnzZdshu9HX+7lZ4hP+MAtP9pMRvmBD/0VvAvt+bAJbhI0asTMHioUKoFGjfI/opDfGfB4YZGdeIMYLQc6QavM9plQSnc2qR06IGV+a8Iqc1s0JFTmgNdHFKmOyqn3ElKEu0ttmVOW9pwds56jSJ/ZQ3YE1OP1Sij6UQObX24wYxx0wQW8eIx1V7mpLkOd1ZFJgss1azd0CclSaTSozkaVWQYlaVeYRL7psokVc69d+06kVjl4qqTk5LNBXRTKqcHN/M5j3jsT6tPut5X3A50lkQfk6LI4lstVmZS7EjfXQTP6WGyBkhU92BWafkNUTHqAVoUkJUrISLshU3Lu9NinDbwRgDtyKy21JJN0tMnSMBCSvTjElNpjWr4eRNXQJM85N+rGl/8mBIc+TeHUET1MazuyBdOObXsWvoyYl1jH5RueMd8knDoD0yKQ0SxNpql/Q+ElA60ii4aMtz7ohkZvC8Yyx1gXYwPiz29fEY3iXpd/oQaafCIwZf/wA=);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="2.8333333333333326" width="2.203703703703703" x="8.814814814814811" y="1.8888888888888884" /></mxCell>
<mxCell id="logging_i14" parent="logging_i6" style="vsdxID=28;fillColor=#2d5967;gradientColor=none;shape=stencil(lVPbEoIgEP0aXhnYVcHnLv/RpCaTqUN2+/tgKEpIx952l3OYc/ZCcHWud31JgJ0H3R3LmyqGmuCaAKi2LrUaTERwQ3BVdbo86O7SFi7vdxZpo1N3tT/cHY8zZjnAHi532dZBG9V+QQXQdCk2ZZTxERiRIk4TQCz/fLFiNIrHKhJJZb7053dvfgtOQ4cBfH/RrtE8JvCg+XeIugAhBCPIq5ILKuQ/o8iA2nSKkIVzlrO+BIt8Ca/IOzMlP4p3yW+ENycDa4JTzmc2MrKWZDQT04Q/tn0WaoLPQVWqadw9fr+HB2hK7nhx8wQ=);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="2.5185185185185177" width="2.203703703703703" x="12.277777777777773" y="1.8888888888888884" /></mxCell>
<mxCell id="logging_i15" parent="logging_i6" style="vsdxID=29;fillColor=#2d5967;gradientColor=none;shape=stencil(jZXbbsIwDIafprdWEud4zdh7oFFGNUZRgQ3efqmStnFY2kpcJOZ3P8ex4wo31+PuUleCXW9d+1X/NvvbscK3SojmfKy75uZXFW4r3Bzarv7s2vt5H/aXXa/sV9/tT/+FR/CzCtD0XoI9g0UI6Lf+9x4cPu5d8OBBYBRoHl0GE8hoeYhg0TiantHEogLDVlowLiowVRSwyMFkWEaZ3IHKmElgkcH98Sh18cACpKRgNMAkhTMKVg6EpmRGsT7z3M5hGWU6AcrNMp0GnEVyNpthCdZR5uAwpXjKXhEqODhNwaOolOHEpXzcVBVN1o4xz+An1Xq+YWNjjHwJkuKVAqUyvL94Q/G+0rmaLW0JfLnCJAdpKB8RMMv+P201qQp8pSHrrPTD5Y5Og4wsbYdyWH16g8ANxafdM3Ry8uqI1yvCV1Xp8k/NOXkAU4+88goBWwEOq6Vq9SbtaMCpKmvJqVVyOg130q8sbWdA6cXsOv8YLV9uOixKjycNd8V48YtpOB2a0ynMtvT/fJh5UxiEuP0D);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="1.5740740740740735" width="2.5185185185185177" x="15.740740740740735" y="1.8888888888888884" /></mxCell>
<mxCell id="logging_i16" parent="logging_i6" style="vsdxID=30;fillColor=#2d5967;gradientColor=none;shape=stencil(lZPbkoMgDIafhttMICJw3cN7dFq7Mmu1Q+3p7VcnthXdddi7JH6B/49E0OpS7s6FUHhpQ/Nd3P2hLQWthVK+Lovg2y4StBG0Ojah+ArNtT5wft71ZB+dmlt/woP7JGLfo/DJOWdbRitfj1CjQKeyGgFlBGcIOvu7QZn0w5MVU6c4VqEdZPmCiliD0ZDbMb2/Bh6enF8wlIwF4h58qLf19zCGkpWAL4oG6jMBmkKJM57pnTTE7iyBWXSXm5k760C62J3F2JrLII+dOYx9vd7cryLHlyb9s3+84EW0Cz5LcvRVxTs2/j5dqq7EC0mbHw==);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="2.203703703703703" width="2.203703703703703" x="18.888888888888882" y="1.8888888888888884" /></mxCell>
<mxCell id="logging_i17" parent="logging_i6" style="vsdxID=31;fillColor=#2d5967;gradientColor=none;shape=stencil(nVXbcsIgEP2avO7ALgR4tvY/nBprpladqK39+yYFwiUGtW/k5Cxn71S0OG1Xx6ZCdjp3h4/mu12ftxW9VIjtftt07bk/VbSsaLE5dM17d7js1/b7uBqYw+nz8DXccLV2NQOFgxWyH4do4PoPebUGb5fOWnBHUKClM/EQB6otdEULKU9x37IG7YSuZCGNwIVjOUgioCqJa+MJo7hQoCgVNxhcdJAgH9aoH7McRBpqUdI3NQhM9UkAM6k+ZyxVJz6JPnAcgOpO7MHCAzrEhFP/vDNRcXzmJSieqo/lmRFXWcnHQo3StQDUqTRLZUXvHKWyrKRJJtzI0xt9XvsWkkVN5CCyJrvXY7wPxGQ9BlJm/T0RjjhJcLMp3rX7aBI92fkon/QQGYhsBFGDVKmPccfQNMmUs2b0pQqTO9+LNxqiz/04qzRleZf4nWaMbXhuU9KPZ7WgX/uJeUJ/3BxBP9qtvkcYGJ7qx7n0cyJBFOsvKVR2fgvG4+a3cDS28/WXxmfpgU7VebJKZL/CblLDfvsHWec9k9LjKB8yeOBhfNqgP4R3eNPudvYZj//n73YP2Teflr8=);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="2.5185185185185177" width="1.5740740740740735" x="1.8888888888888884" y="6.925925925925924" /></mxCell>
<mxCell id="logging_i18" parent="logging_i6" style="vsdxID=32;fillColor=#2d5967;gradientColor=none;shape=stencil(nZBLCoAwDERPk31tjuDnHoLVBmsrtf5ub0sQRdzobiZ5ycAA5pOuRwVSTMG7Xq3UBA1YgJRktfIUogIsAfPWedV5N9uG/VgnMqnBLenDxneZEOlGip09u4pRQ/aG/gTPhFf0Gf8J/otGcdXRkjHc5n3/rC+OuHosDw==);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="0.3148148148148147" width="0.3148148148148147" x="4.092592592592592" y="9.129629629629626" /></mxCell>
<mxCell id="logging_i19" parent="logging_i6" style="vsdxID=33;fillColor=#2d5967;gradientColor=none;shape=stencil(nZBLCoAwDERPk31tjuDnHoLVBmsrtf5ub0sQRdzobiZ5ycAA5pOuRwVSTMG7Xq3UBA1YgJRktfIUogIsAfPWedV5N9uG/VgnMqnBLenDxneZEOlGip09u4pRQ/aG/gTPhFf0Gf8J/otGcdXRkjHc5n3/rC+OuHosDw==);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="0.3148148148148147" width="0.3148148148148147" x="4.092592592592592" y="7.870370370370368" /></mxCell>
<mxCell id="logging_i20" parent="logging_i6" style="vsdxID=34;fillColor=#2d5967;gradientColor=none;shape=stencil(lZLdDoIwDIWfZrfNto6NXaO+BwlDFpERwL+3l7kQQSOOu9P260naHIJZX+WtIZz2Q+dO5maLoSK4I5zbpjKdHUZFcE8wK11njp27NEWo29yTXp3d1Tvcw55WkEi/xekjdOirOgS4ts0MVhQUxsIiBaUXMAqg+vcCl5BGu9NYEBkotoCFmq6IcGZ0xZsLQB2Pf39EIkix8m8EpuL9p2EULBNI5Za/bErKH3gU70CWtq5DnufzzwCPrRB+3D8B);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="2.5185185185185177" width="2.5185185185185177" x="5.666666666666665" y="6.925925925925924" /></mxCell>
<mxCell id="logging_i21" parent="logging_i6" style="vsdxID=35;fillColor=#2d5967;gradientColor=none;shape=stencil(lZTRdsIgDIafprc5kEAK1869h2fWtWfOeqpu7u3XDmwbcPV4Bz8JH4GfFLQ61ZtjVaA6nbv2o/putue6oJcCsTnUVdec+1FB64JWu7ar3rv2ctiG+XEzRA6jz/Zr2OEa8tCA0kMWqp+g6BJU+ae8hoS3SxcydAhwU0ZUkMFRkK4YJBUj4tRoMBwjSEbEqXVgzRJWSWZpgbVkzg4WFa8AjcSimqKipJVaAs+vSOf7RhRhRi/7A1lJJ87o7AD9En+eEyW24GzC54zPCrx7yLcM+km8IfCSbvpbRUknAzqp3riMjh5w0W2WE68ZoATOJitde7Bawt2dhx+j/rO6k3CNgJLt7zw7EEr0zWAjeNFvnqe7lN4fje4kUT2sdBHIyddCMIm57zxvXuX8n9wKT3vJvjk813z6wdS6ds1+HzrffD1tdb0U2iStfwE=);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="2.5185185185185177" width="1.2592592592592589" x="9.129629629629626" y="6.925925925925924" /></mxCell>
<mxCell id="logging_i22" parent="logging_i6" style="vsdxID=36;fillColor=#2d5967;gradientColor=none;shape=stencil(lVRBcsIwDHxNrhpbsmX7TOk/mBJKppQwAVr6+zq140RpyZSbo2jt1a6kilbn/eZUV6jOl659qz+b7WVf0VOF2Bz3dddc4qmidUWrXdvVr117PW7T92nTZ/an9/ajv+GWcEEB+x6F6itF0IA2P5HnBDg0xwnAGbASYAx4mgJerl16QqcE9sAmQ3LIYrnlhjlLg+ecNYQUUAbeKAMtqOF5Ktfr+3zNrwI9guP7AM0QrADYAMbfB5AG4scUIT9oXBQhB4GkIsYORIsi8S1FM0UMoJGKoF3wz4JBwXZe3ZysQ/BekuWRRSbmRqsKVzBWUmUHM+/UgnEMrAVRbcHig7KiBmslVVJgtaQaNSAtueKk6hwiBlzoNPVQ04ShRUp1akEMjj0rxXAMblGMqSPjIAae+eZAoxQjDiLOxPAEykoxxgn+e4qUlCM2rg9LdIMDw5Lu1JXMLRhQbuZdEaLQnS61wc7lrfaPNRgP4xLdNYdD2sHT//OlG0NpYdP6Gw==);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="6.925925925925924" width="7.240740740740739" x="5.35185185185185" y="16.68518518518518" /></mxCell>
<mxCell id="logging_i23" parent="logging_i6" style="vsdxID=37;fillColor=#2d5967;gradientColor=none;shape=stencil(lZHdDoIwDIWfZrdNbcmAa8T3IGG4RWRkgD9vL3MxMg1E707brydNj+Bi0FWvBOEwOntSV1OPWvBeEJlOK2fGWQkuBReNdero7NTVoe4rT3p1thfvcAt7OUjyS4T30MBndQhsa7oFixGYQpass1++nALJdV4yJDJayBFowx+Bs4jf4cbpr+GP5n88ZZudxfvzjWnbENxy/pnU3Aopc/kA);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="3.148148148148147" width="3.148148148148147" x="4.7222222222222205" y="21.4074074074074" /></mxCell>
<mxCell id="logging_i24" parent="logging_i6" style="vsdxID=38;fillColor=#2d5967;gradientColor=none;shape=stencil(lZXLcsIwDEW/JluNLfm5pu1/MCWUTClhArT07+vUMX6VkO4c+Sonkq6dhlan3frYNshO56F/b7+6zXnX0FOD2B127dCd3aqh54ZW235o34b+ctj45+N6VI6rj/5zfMPV5wkLBscsZN8+whn7fX7x8tfL4PXcbysOQk4JPM9gV/QBTcDspJlCVoIQk4p8yCBwM6lCSIKlOfoNFdhKA+XwKJkCpAHVQzQ3oGbRSgCpHF6UTRKUyNks53Idu72UWxScVpNDAjNpyX3sw06jAlnMOZ1hKNnERpb9D/TUYvSnx/bd4T+WzB2MzpAqkyOCmK/NxpRgLAFMF7XZapzuy2xenGSVk26ie0ZioKnobHxvOEIMLC8am3zihNImqmhh8VZUg3VT1Cbnp6rgKxlV9/nj0Zo/RwSoi/INiILvbH4bEdYqqme/lC+r+ystDCtRdANXD+lV93NrL/CqW8S7etvt9/6qT/fLu92F/H+Bnn8A);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="16.05555555555555" width="16.999999999999993" x="8.814814814814811" y="3.462962962962962" /></mxCell>
<mxCell id="logging_i25" parent="logging_i6" style="vsdxID=39;fillColor=#2d5967;gradientColor=none;shape=stencil(lVbbUuMwDP2avGpsKb49s/AfDBSaodsyoeyWv193bcey0qTtW6JIPjrSkeKOHr62z5+bDtXXcTx8bP4Or8dtR786xGG/3YzDMT519NjRw9th3LyPh+/9a3r/fD57np9+H/6cTzilOKOBzDkK1U+yaKX+vz8l95fvMfnr9Nk6MDYH6DZCnTAZXABH2SebggGVw06UTN6BL17VZM0aejwm9C16BFO6xZ8SKujWgnUtevXJBqPA4hp2jcgG6sG4Fpnnl02IgCiYW+h9i64JjF9Ddx7It/j9hHWqPAtWgVcttBGsV3tNBE5gik5HcsG1gCwrxk3fSddAr1tkXseWW0Hm/aDW49Yeiw5z3Uz0lGlhuQCXGV+VdjyZsIXnQ1M4GtBCYHX8Cks200LtGXs37O/ZAe3KIISeGvfYrUCrQoqCD2JpxB1hRGkJUHJzgF6wQ3CC3OS0tLMUeKEmfnAZHrbZcJ5kBnNM8XQjfedAidbGIoqldWFpUphkNMEzr2zqQ9kMS/AspoxXABTK4knWioSr7F2cCLdafQ9BsPcKUDSf9yibfOy02JwXpF29FvC5rPT8ZJxLFOdZZjDSoPyd/DEWVpSfFbYsUjb9tSK9KD/3urX7UZ1WLHGuK5wnWSoSOyJ+2Xz0l8Tf7pYblkV8qLeTt2G3S5cb/l3eZqIp3YTo8R8=);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="4.7222222222222205" width="4.407407407407406" x="12.907407407407403" y="9.444444444444441" /></mxCell>
<mxCell id="logging_i26" parent="logging_i6" style="vsdxID=40;fillColor=#2d5967;gradientColor=none;shape=stencil(lZRNcoMwDIVP463Glvwjr9P0HpmGFKYUMoS05PaFmpSoMzjJTjx/knlIQtHmVO6OhUJ96rv2o/iu9n2p6EUhVk1ZdFU/Roq2ijaHtiveu/bc7NPzcTeRU/TZfk0VhpTnImicslBfkkIO4q/wmvi6am54QghR8AaQ13kD3j6BUwRygrcMAdcTtCyu9TqKEZx5HHcBiAXuETjzKuwA3eP1mcFRDn87d6lTJh1HAnutv0hu7saAs+QhXMvOEgcws5OB5FX6Mgshgs20PTiwckzu9CUyUJDuIiBl/TnQLP2Zvy+++DPARvrzYI20xx44SoO5ThB4ORi5sXhyYe7zY7Bs56Gq67Tct+f/t3mU0p+Atj8=);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="4.7222222222222205" width="3.462962962962962" x="17.94444444444444" y="9.444444444444441" /></mxCell>
<mxCell id="logging_i27" parent="logging_i6" style="vsdxID=41;fillColor=#2d5967;gradientColor=none;shape=stencil(lZXbcoIwEIafhtudZDcHcm3b93AqVqZWHNTWvn2hISQbRsC7sPzJt8ekoM3lsD1XBYrLtW0+q596dz0U9FIg1qdD1dbXblXQa0GbfdNWH21zO+3893nbK/vVV/Pdn3D3+5QF029C8esNUoj/7zevfr+1Xi79b+3A4LBB8h3ijt5gEWTQDCanQbpBRd5USkA9qILJgDBz9BEV2MYCSU6PmsFAFvQiWpZg9RzaYDglsLOoCcE4ThYcKwmcehKroJQcixbKkqPzgB1kuRacqhHUHDRPshrPw4lXoeYGHC6Gu1hgJNCG09PWCQFq0CXnxyakSWMTlwzoY316Yg741MSyBXl0/FFkMUHj4GigrJJdr4psdKQErRZjG0WP5rYEaTN8cvDAMklcOHWSxlqrrLCL4TscBzXwuzZVyPmpKri0ih8n+tH4itgywSULMrs7SIHJ+KlqMrTr+V2yRdbYNvb6mH+wlIVPoAzHJ6KV85zsCNeKBNKcnXoY0hHvyZnYJ7Xnk7ViVrpFfJ/29fHon7f0f/6edSb/FtLrHw==);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="12.592592592592588" width="12.592592592592588" x="11.33333333333333" y="5.037037037037035" /></mxCell>
<mxCell id="sgw_i2" parent="139766069591360" style="vsdxID=43;fillColor=none;gradientColor=none;strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="23.032258064516107" width="23.306451612903206" x="43.3467741935484" /></mxCell>
<mxCell id="sgw_i3" parent="sgw_i2" style="vsdxID=44;fillColor=#FCFBFA;gradientColor=none;shape=stencil(jVjLchQxDPyavaosv2SfefwHBYFsERJqCRD+Hi0zlsc9GS+3jSK7ZVlSt+cU3vy4//D97uTdj+fL09e73+dPz/en8Pbk/fnx/u5yftZfp/DuFN58frrcfbk8/Xz8tPz9/cPV8/rr29Ov6w4vy7oUSeS6yrs/i6VWqvWf5f2y4OPPy7KCF4coVP26ZDWxc4vhxa8+TJxXn9VUC8XVKSyWkMi1jVZTTRRm2L5QqSN29eR5RPeBUhrRi5DwCM+VYhzhi29hH+CzkIsjfnEU64jPkQqP+FIoA7zvmV9NkilN0Zkkj+iSKAmgOypweomWEIN3u+RLoDjFr5QDwHuqAC9mMXRH4kd0ocwArvHwDFzIpxE8VwqM4AxHVydfRvBMFe49W1mt4A/nx02TZPKt6FaDUPGzYOGW1B8jTZQLRJrbphZpogh3pE5hmqbUM9DAExXEdlCe6gP1ES0Yg9ZlkyRFslOv/gGSuhskvQLZlkTIUyDBPHmbPzZJrAksWN92OgAPFDBPbLOlg3vAZooFsV0AbAcTdEyUb6le85QqybTtvBVPCzVtirrNPOI4xpoKQahMtYyhqs+60dHI6ZOsYYvNLZs4lCtgi83/Dp6g61KmfJwmttyv3ql14WGoUE3KbQUitZvpkUaKYYzUdY5pkYYbnKgTDmgpdQ7q4DY+G7h/BTxBOSVuO72aJ0dhHE5JCWlKYpsVbEvYY7AexnisWE/qAzNCfW5hOxmxYzFKNWwAVloE7nYAGxvpHMNCGQftW7gflUIj8LWwYdJw2NGmmnhaHLoNzprYWr6PGk8ZGrgH/dLPGYE33Qw56ugHxkahpswERekAs+yYwO79dSKoJrX+WMHFY38tPh+n/juOU3VZ4FhtSSe5/UTU3qrj4bRLXcHDSZkEG9tlt2B5mgz1zwL+Nw6nVAzygc1ih1MZAPq6a0M7nOwON4u09EpolDJS6M7f6sKIbZI5pU437h9uUHTeUIaxdgZ9oERvDWmsXUDM5M65Jm+cTGL1+Cq64b8R/CaxZv65KW0TS9NEiI1nEys2wy0RnZdNrZh2skTYI8x0NwwvCLR2wlwsBVh49Be2wdaek430jmS974Rnr8ndi06fJh7r3e2uWb1Q2bPV0BF+7mXZ8ENn5YYvfeeGr30K5CB6WKgzfTDKVGDpwzTB3WoBM+iWqiHB5QZnaq7h19wVRqtzJZFpbVVjdeOmSgzHt/f9RltWGKVV7NY2z6o5M9YuvuxFKbvKLiZk7TWfrH8afGFLmn1MMNPR3Ydd7jWF+AjQ5kYpdP1GArnffkgJ3WvSK//x6UV/9A83n88PD8t3n+3/8UOPmpaPROHdXw==);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="22.483870967741915" width="22.75806451612901" x="0.27419354838709653" y="0.27419354838709653" /></mxCell>
<mxCell id="sgw_i4" parent="sgw_i2" style="vsdxID=45;fillColor=#FCFBFA;gradientColor=none;shape=stencil(lVrbklQ3DPyafXX5fnkm5D+osIStEJZaIIG/j05mJNmtPT7J2zDI27YstVryPKQ3Xz+++/L4EP3Xby/Pfzz+/fT+28eH9MtDjE+fPz6+PH2jTw/p7UN68+H55fH3l+fvn9/f/v3l3WF5fPrz+a/jL/y4rcvZjXysiv7n7Zvo0vj3i19v9r99f7ktCPcV1aVyXxFgif8R70bNtXo3imyU79/8SHej4QIbJTaqM/anp8/TXot3JcBe23avJbicca8jrHsttP287jU5n9a9luRiXvdK38QteOLdCbgsUfDsUkDw3AE8u14QfOeo5mJaHJVd3Jh31zOYt7Y92nClr0cr6rL7Oap3caxHKy629Wg1rOcqrmwOVik+1p1SMG7Ms6uLNfml7M5ViwsQ282VDOcqrrb1XE3uR85VXRjr0TpH+xl4dS2u4N3lBuDN5bKCdzcAuzsP4TJc7Fvsro4NvKRWwB7Ow8GHG3ihg29QwIN3Ke3Qm3e+rui0pgKnkBWghyAEwvAtSIgJfHB1E/0taQbeF9A325tqxSUI/1BMajeKNuDA0CQlZMN0fQk2PJjnTvB71otgWiNeA3/1rrtkDp6imSMjaCozt0TXt+k/iB/g/KlLvDP+qMp/XBay5JfgN4lx4YCreBkEBtFaqtQGwZ/+MkdwZGJT/OIyJOqRDNv7H8kVyNSWJewF3/Jfo3yB8/cqxClEkblUnt1/kGMIU3TNRAarerO8pSiHlfjzrgP+uKJ/YkAP90/O9nD+IsQk8F2N+K7pRhC+uS06CZBSDHoCls4kFhLAE3FDWU/TSZL4qG5FxcGMacXvQ+QO41MN7eD9XpRSWe8Qg0H0d2K+LVcHKtdhxae44mMwfqiugrA4CAmyP2TmRsEnctvKmnlJgCWKHkXECHqUbQt6dB7qP1nFrfeJzQt4nzgfvU/lw8cVnwpTRe7ToqepP7bwQzldSyfrYcl8QG6isSXrpboJMrHV1u/d1BwSDB1rpAm6Q4hA0DdlLwYXEjyreBqmDJ5FNIo+EHITcFK3cQWv9uSkk/OWblyGG6clAYWR0qiSfUYVz0gKHi7Ai7QtAh5EXgnVqehQ8ZsLgiPRk4zu20JPPl6xi7ZMQnSG54h4C3hd70GwRbOeYgdgGVoSgGWSdo8Mru2hkKxrIEdLYXI6AU8qIhk8syiZwDPk+NFNDQSPQPBHX7YtMMmqi6S6RdrZgc1NcAPpXfYs4BI8Z9VFlzC4l3qn4BXBvQal9tIQ7NRwlwtwDPZMUisiOMpKqsimsKkRgxeOnnNwCLiUXuMYqGrHTUC/HKbaq1+NraY6HI+JrrQdZUPVjjUw16aRinpjode1A7mewVzNbPw2nHWawSejYIGTxaBVXYjF1GtKJqjXIV10ltkMQaJQrqDrfn6qpyOg+/8ZT36FzdpeT7AYyV3qu8CawQ+l0X7sNC3RHEYCmYw0hwtiYxaRTd/WK2/kUQmmWHqTwmQUL7HDNoynBWLfL/yEkobagWr8VKC2EhvnjJvFwk6lIG5Z3juISypKISA2KprDCAIkaDP+X8tb0OGQ9q/YPwUzbTmMMCVNdJJRXMDXWwrmlio3gKebxWa3NCU92SwSIxmNgZvFMeYhVba3FJUZJgmE5KXujGJUoNG3FYk0mm/nnoqujMVTZF/zzn51bJW7OT3bsNKywRR1EiOqayPkatKRfBKjfRdrFVa102mqv1AUVKxP2tLDwI9k/zpnhXqnuxX7tquP2sne7YtL+xGBKTq0BKRrNgKOWiV0rE715GyVu//ThqGAjKHWDkV7sY5tRkNVkV5Te7rWPJh3a6Mk9nVr31YdQT3yvqZW0VpyuCFpok0opmO1c+Jpjq2TqLRVp801nHt4ky+6HRk86IBXiGgaDySx2vditAaVectGIYagwxnGL5YIo764MH69EKiHqAUebuD4APWi62xPkIc+dvEsIvJVnPFU0u6RhxHN9iTdPKONic6YqSxbHOPGLVMNM20eTZ5gJJ2rEXNjCOVP40acfZDVnimPOSbMG4P3K3otRlENWgZs0gI/LCh6vZj1Nx1tyumpNV/h6Qob+t6b6Udv9k2qXIw/6ArNsNPOP0Yx4zaKehyA0K0FmIAQMVyM+oc+ZU51CuKer2MSShVSbgqGSUvvnwPpChv2wwnryPHMAXmXmj4GMHySlxd5ZgkcV2fwXl+mOBWrGXTTFQ7w/SHZ4Oq9vlkyEzQey5xFXjf6JBSdLOlQ2YPyo54Qr/5gSvsst5d+tAZunigYH++JtpHvj+dGQLd0O5iZXn8TDNoy3x0IigMK6dBRFNeqywdXLKRmvlW71X7m/YZ0A0o/bmPO35lx0lFMGSUj0yKarusQVeb9PmyU36Ee8YcJYfeAr52e2PtNc1PXS7h6xz0UOngiGW6r0pXryKfBJRR9/9GRT9kc7Ghi2rLX/YjomNauzUjgZ+OzqtXM/DaYJ/VjWAvDY0MdpZiSGZiXXt9rQX1/YT9N69h+F0TH/Ha9Z89/4MwXU3mU7t/4Ihgenwav0/gFnCF19uw3S6nBZnf2eVj7uH8jmN581snXJI0wl/16rFdGln6zx/38kT7or80+PH36dPux2vz/+Os0+ur2y7b09h8=);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="23.032258064516107" width="23.306451612903206" /></mxCell>
<mxCell id="sgw_i5" parent="sgw_i2" style="vsdxID=46;fillColor=#2d5967;gradientColor=none;shape=stencil(lZXRbsIwDEW/pq9WEidx8sy2/0CjjGoMUIGt/P3SJU2xEZX2Fozd02vfuA2uzrv1qW2MOl/642f7020uuwZfGmO6w67tu0s6Nfja4Gp77NuP/ng9bPLv03rMHE9fx+/xCUOu0wjGjVVG3XIkONDxL/KWC96vfa7QJQFoqigRIkCdQ4PJIQ+25EyBANaUHKw5JXIrERcBwxI7lSBnOwVoOTu9YORwq8FaDh+FE6cjgnNLdE1AnuONA+843lgwyPk6gtKcjwaU53ydCv0SHyOEyPkRnOi8DRAE3kPgcBdAidZPA3vWeAJjONpzLnlA4lyCKFQHC1K0hrgoOsT6lImsDRBxenSgxNDHdhLHa6UEPcnWi/RkJqHbAQUhHauqElGi36kTgZOTbXEJbA2g8Jp6tBrV8c89n2w1zBqF0XUAvWh09+CzZLTJ1APXWO+YrRMYpMb7C24XfZY0EieTrde59nvaUBUe6uKYZaeFI3WX8T+73h5U4PBkK7nZkq3QcHqchd6vF8fpD4t13x3+t4nTYd7j226/z5+B+//l3k+h/M3A118=);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="16.999999999999986" width="16.72580645161289" x="0.27419354838709653" y="0.27419354838709653" /></mxCell>
<mxCell id="sgw_i6" parent="sgw_i2" style="vsdxID=47;fillColor=#2d5967;gradientColor=none;shape=stencil(jZbdchshDIWfxrcakBCg6zR9j0zj1J66ccZx2vTtq+0usGhj0rtdLPazfs6BHd29Hh5e9jt0r9fL+cf+9/HxetjRlx3i8fmwvxyv+rSj+x3dPZ0v+++X89vz4/z+8jBFTk8/z7+mL7zP+9gBhWkXuj/zivv39nUO/vZ2maP9/GNwwHEJX5YcOJpX3nFeIb9ELO8IwksELSsIOS9By1KGMAL7AMmAPUGOPVk/QobtgaWH65d6NDmINII7kNSzSSDmnu16cNAI7MEeBHsyCyCOyJoi9eSYIXubNYcentIWzhBiT8+hbLxB1zZR7vHi62dau8FLz5cIPpmqO0im5ZLB5RF/Gk7D98719KgxaOjSRnJBRQEy2QvDsOlJh8lvkufU47NmaoqfGTD0eN1o6NohP+y8JHBsWi89W/Osc4l1oIJh14oV9DSZcai1uqNMYYRg2aoiw8aVHqmWInBPVyEzD+u+qmiZA0BjMZGAjcu4Hr02NvrA2U7H5/+3wc88U6uRh5McfJs/b/c0JWE1qzrLWByimSeX0WlKTqVCt1qaSs8rP2Mb0wXmPWTrJAoz5r3SRVFXhDzsaQAxOuZcD5JCD8UN1h4ajJC5GWIzlrF7J2ADV8fKtEld7LFFkKyWMqARslaWZGiiAaLxEYUVba9ab+QUIZncdYiMmGpdBwZq2LTREsvm1AzgrYGm+neqhRUzvC1kh9vE7eFF4E3hfWztKTOnR4X0eP2Tw7YLgbOntq+mVX2MW15YB4qtf2uUkZzOJo8NXPeY2kdfvK/xXbsUFMlRFUJNHzeay/Vic6v8BNLjleWMjUc94c3cTb5kzu4PvHTjeJ/56WaDPrRL6dPxdJrvtOvf7SVWl+YLMN3/BQ==);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="20.016129032258046" width="20.016129032258046" x="2.7419354838709653" y="2.7419354838709653" /></mxCell>
<mxCell id="sgw_i7" parent="sgw_i2" style="vsdxID=48;fillColor=#2d5967;gradientColor=none;shape=stencil(lZPbDoMgDIafhtsGqCeu3fYeJuIkc2LQnd5+MrLMQ5Rx18L/NT8tJZj3ddFJwmk/GH2RD1UONcED4Vy1tTRqGCOCR4J5pY08G31rS5d3hVXa6KrvtsLTcYxSy3D6cnkWQZJ8Tk5O3qh2Is9SYDgHKCTZNhALYGIOCOBxCMAopDvA2hITgHwbWD6ZxYDRjqG5mm4rg8oyDkKE2I4oCAxpzBrwtH5tyTPcoK+z6ON3Cn+NyFPaKx+D3wJUqmnc/kzvlwszHrllw+Mb);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="14.532258064516116" width="4.3870967741935445" x="10.419354838709669" y="5.2096774193548345" /></mxCell>
<mxCell id="sgw_i8" parent="sgw_i2" style="vsdxID=49;fillColor=#2d5967;gradientColor=none;shape=stencil(nZJbDoMgFERXwy+5Qin029p9mIiVlIJB+tp9ocTUatTYv/s4czOEQTTvmrKViEDnnb3Ih6p8g+gREaJMI53yoUK0QDSvrZNnZ2+mSn1bRjJWV3uPF55Jt+eYsKgi8EqTDODTnxKulRng/bKH2QI7Pb0AM4H5yAfBgs8LOMfwK9gBFtm8AP6H2QHDJisrguljRTixYGfjL63iofgGolZapzwN9+MAhVEKHy3e);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="4.3870967741935445" width="6.854838709677413" x="5.483870967741931" y="10.419354838709669" /></mxCell>
<mxCell id="sgw_i9" parent="sgw_i2" style="vsdxID=50;fillColor=#2d5967;gradientColor=none;shape=stencil(lZLdDoIwDIWfZrdL17KA14jvQcKQRWRkgD9v7+ZiBAwgd+36na5tDqO0q/JWMYSut+ai7rroK0ZHhqibSlndu4hRxigtjVVna4amCHmbe9JHV3PzHR5BJwC8BuEZ8gh4It4vp4DXuhnhSBxojyASHOVEIJAn8bKAXHn6AyzD09nlCvnb9rP5n2MnMYddh5EHDit7zg+/E984+ybugq8lSl3XwVHj+txC7inYj7IX);strokeColor=none;spacingTop=-3;spacingBottom=-3;spacingLeft=-3;spacingRight=-3;points=[];labelBackgroundColor=none;rounded=0;html=1;whiteSpace=wrap;" vertex="1"><mxGeometry as="geometry" height="4.3870967741935445" width="6.854838709677413" x="13.161290322580633" y="10.419354838709669" /></mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

View File

@@ -0,0 +1,289 @@
%PDF-1.4
%“Œ‹ž ReportLab Generated PDF document (opensource)
1 0 obj
<<
/F1 2 0 R /F2 3 0 R /F3 4 0 R /F4 6 0 R /F5 12 0 R /F6 15 0 R
>>
endobj
2 0 obj
<<
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
>>
endobj
3 0 obj
<<
/BaseFont /Helvetica-Oblique /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
>>
endobj
4 0 obj
<<
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font
>>
endobj
5 0 obj
<<
/Contents 22 0 R /MediaBox [ 0 0 612 792 ] /Parent 21 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
6 0 obj
<<
/BaseFont /Symbol /Name /F4 /Subtype /Type1 /Type /Font
>>
endobj
7 0 obj
<<
/Contents 23 0 R /MediaBox [ 0 0 612 792 ] /Parent 21 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
8 0 obj
<<
/Contents 24 0 R /MediaBox [ 0 0 612 792 ] /Parent 21 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
9 0 obj
<<
/Contents 25 0 R /MediaBox [ 0 0 612 792 ] /Parent 21 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
10 0 obj
<<
/Contents 26 0 R /MediaBox [ 0 0 612 792 ] /Parent 21 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
11 0 obj
<<
/Contents 27 0 R /MediaBox [ 0 0 612 792 ] /Parent 21 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
12 0 obj
<<
/BaseFont /Helvetica-BoldOblique /Encoding /WinAnsiEncoding /Name /F5 /Subtype /Type1 /Type /Font
>>
endobj
13 0 obj
<<
/Contents 28 0 R /MediaBox [ 0 0 612 792 ] /Parent 21 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
14 0 obj
<<
/Contents 29 0 R /MediaBox [ 0 0 612 792 ] /Parent 21 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
15 0 obj
<<
/BaseFont /ZapfDingbats /Name /F6 /Subtype /Type1 /Type /Font
>>
endobj
16 0 obj
<<
/Contents 30 0 R /MediaBox [ 0 0 612 792 ] /Parent 21 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
17 0 obj
<<
/Contents 31 0 R /MediaBox [ 0 0 612 792 ] /Parent 21 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
18 0 obj
<<
/Contents 32 0 R /MediaBox [ 0 0 612 792 ] /Parent 21 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
19 0 obj
<<
/PageMode /UseNone /Pages 21 0 R /Type /Catalog
>>
endobj
20 0 obj
<<
/Author (Carlos Mendoza) /CreationDate (D:20260412224013-03'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260412224013-03'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (OCI Architecture Proposal) /Title (Mercado Libre \(MELI\) \204 KVS \204 OCI NoSQL Database) /Trapped /False
>>
endobj
21 0 obj
<<
/Count 11 /Kids [ 5 0 R 7 0 R 8 0 R 9 0 R 10 0 R 11 0 R 13 0 R 14 0 R 16 0 R 17 0 R
18 0 R ] /Type /Pages
>>
endobj
22 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 589
>>
stream
Gatn!?#/1K'Sc)J/)JIV0[9I"m)q$K+=pf&@X=:YeQ*FrgWF'=,@`rea*(Y;X:u"/TOS;#o/tG57mqujF'\s@149#D_$.+r\7,fu$<PpIa,KOfE,ED#M3[$6.7>o-[okMaa-:+4J`*aqT.uNtP#b6nV<MnQXMjb?P"\-^LoMtESPYi>7_1i?^f)!jfh=sh;?`pWYr.o=9W/^QnDaga:.:@k0Wm.F%;p*:/+Bn3G.:[+ETq:nM`c3K$b#Zc%,#i8k6'Xek]jl]Wq(&/NfMb.=10N)hUepp5i;Is+3T6u[Q^@#BWc2RqM&8KIG"GJ[I?n5@&2BHZl<9)='^a<*q3j\Jc4\U7r<M57aQOmUV&eH=,EOBLYZCO1ld<CeoY@-1#B8WRlnH/+h*0GWdLIWD!'>NX6&L1"o]43bnGoP4H6*=9N*W41d\88+1.K`A2U+#GhM[ApM4Su0OpllqXrYOQaX42[WQNZQ$N<0UjTA4I.lRKbFcH&iPW@2HA=Ak(l+$2n&ipQVeC&h4S@$$D])0@?T"(<ru].4%@(jOm@(olZM9EK@.VNL;>IrAZIoH:G+g";:IHr7"8`DtP5~>endstream
endobj
23 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1866
>>
stream
Gau0D>?BQ=&:WeDbfcTAp(1`UnuZg5BX]R0"%g!!^l,F^7)bKl[V>!0hiW:X#fJ<rpMc"Dm$[Z]k0qPQ"DmuZk'*$k9]g<dQ2mU4?N=LMKD@Ntbn%N/=FOX>+U*f#bU*&2Io3_%G<k-a5mAqDht8)qf+#qRJ_<>a0$r<=bA3>Fb].@<^g_ulSdQ<K,-DGkW<GfpaXAu4.?#m4MKkZ/\\(c@Y"':@kO5T]]n6&]R(q35[fqV(q;.G,8Y.ME/@&1EA4siJm4baV7VJ"46^Ik\cn8I=l]\*/e4uFnJ+\\RNoa(A1p@#`DT\:IkT3MJZ,0o7j5[P1#uI+;>6:.YSQ<V6_7);!.+L=&2$=9f0crP(poqFP82chh*PHSlZhB4oQUYUP6r]HB:;Er';m,O1f\EasKq25g#6Gun(m>iJ'PZ^f;ht"-51ap9?MN#]+U40b2QC8pSm<]Ll.jW9FFtJj1fYZ*$cPb9!/FMhL!6lCUgto!T"rC]B<Y-U\]@bXGm;;rB!%u+e,,*%q<8"hU$cI"`9:OCearof$#@@qJO_1C$?5?!gU<g:2i/ra:Ah;#(AEms\QmtO$H-BsU9]<*=+u/S>:U</a9VeJ&6X+)#X"$=>_u3G.<l1-*[1;XUq+'l6lSTK.bskQb8#+ICK3,?8tJK+5YM`Rpf9t?6:IkooHhYd65GR6=@5@_0o@Uua%r_6XOIH0/98[bOfKXG-tKnaKEC4FUdL@.Yt/tE<qdHu!^eK>50CB1PN(DHqmi\=?/h9O>CfBD8Ym+BHC0u]<Z_kg\Bd5kBV7):CV)3a`oK#IIEeBY7]n35+0qZ:$jJ?aWqk#"bmT9Ef$`/hpBZT0Yk\ci#M,ShV=JB3>$#8g-C5-tl$Y!Y,h#Od]YWBQS;`kq^Cerc&?7UP3KT.j0-5lXM.c"u,+!F`cj'pG\<?bZ-F2tiL5bmp!kR#Fp3:0oTs=_ql0`9S7:b/jL'UP8s+.2sUbNRMfsn"V&W]ro0OFNL(R#Kjng*H/QkMGH_OE]gDf+m"CU?rE)NoFYGPJ8D$Xhp`bka[JpP.+9SO(EIS?&L]NU#SdBD6H[4;jVa-grd2ZcdDLjiAI&4UA_b9<d'l#c;kUVgFjth.@_;%@k@s-aQV3TBBjar*R3"m/"\EF"=8[Z'Q61%`@*lf+sm]`Y3R@6lX?#h.5&<k=u^;jE6aQD(:S55M9$.gsng_EGk(:QjfC-m>j'#9r9+sR<W4<CgoND!1ptP2:EF"0A-gqWU&r-2/cm61@D&\WD&M09;g?_4i2Ha;X`-eeRj[g_?4.-R"-94K!Kq3_3pmCYklV@:md_YS'J6J+JO=f%o:f21TX2FU&trW*,,fUoD%PA$Cf4":\#g;nV0QCfPQ`1aA9LsbrbT+;tIDqf'?S+=GuW9ZCcqtE?O#`hcD.H"O+g%@#Q8LK=6#apCbgG"+;hB]te^YBuHIdl0d_&Qbt-W3d%.dRW]LV/t0RXNFuI)'/ui6rK`&_QX&>n3KNo\8sjPU[kCR[fsFg4V:>'CV"XDk`"T^`Z""#`WI9?SX8/[,8f:sG?3Kt:\uX==!c9he:GsYKhRRUZF0Q0>hgM@OO0QoEVU*M?qQ"-;@ej<$lt9=^r]ptO`AA#'p]VfFZ,?WHQJ*FpRO3ZS+tg<]X=F+E4rB5$fPupZJmE_gEcp-g!nqZKJE7(I)aF'=jL.A`_3!SVoGGLg4i3!YhBhl&Y*q]J^K^Scs1\KPIt3sTPa[?eeK)6gfm;uCNkP7aIecNp[<l_r8)$2\mL_oFL!3q$009o5GWP$a<O;$u3B"9[U\1X6J^)cG7I$/IR5B)!%H9K53ektnS*V)hN`EHLV5OXa.8Ed'>k_6&1qgF8]l]]pK7<olX"Ro~>endstream
endobj
24 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2750
>>
stream
Gau0E>?BQM&q9"FeB=GN+VqZb2J6>987kC8+Yh*Opn]ROm@Hj`7kL-?J,OiH\l]/H_Cdj=@+"DFY,\\jX")(5(I+Mi*@4*lDWp_`8"NL8$h?V3Umk#'HZSi>a;GEB@-!O3&&Oon&,sbM07P&=FF06M0;Ln;:C6]?6i.SHjJW\MA8*9d?O:ejT]_A&E^J(koR#XaP1LXL[c@NsV32R,%jf`9P$''mRP*,AP;MZ3]tM(G*ZrkU5BQK9bA89mHHr2@3ddgRKpp1A=!DN&ECTA0kX(8kl](`pBkSU@,c=_u'X3\I./Wf>>31eH-h'LoLX+6rG:f,DJk%B^4_HTfD'#l:'pJ+_rRQPG5c6fnGA5tETMq(/B&:>lKd3N/Na+gcQC.&SjAO():Yu<Ugql6cM`U%LW+EP]cb5hEUZSG>4<1g34W?I@RTpWoGbmWt<'MA<h&\c85.%$/e/Jh;?=hZkq`EtHf:u,WR>G25<5A)T=iW!iq-CD9(>Y[`mgnVCP7*dU,#\2X:.Ah7'hLc=K2j/V7CW7gV2J$74=d/=aQ,W+L[Hh(0qb^>G0bi(oM4NF/Xsg`7X<1OFflAM+'>hq)<EA?Ah>78:_DOKm!GhQSCSn1ATep+Idi8Tld9'LX5f\dW)O[&8B+o2`M4QA@;!ofe8due,?-4+.`McuB6p\d.NEJ'ZW\h&6U^`9>D(jfdUF6_]*)qjn2Ba%HM3fFApf$S4bFdn:qoPB\L\D*^K\`u>_`ia++XH:@C)Ye&p,Ya\3$#bpi=YhbotP^rR'2YO6O@DaaWVKhl>aAb3Y(nBVf``;ij1[=?1YRnE+%u1Y3V-hB/[gWBCJnqZ/mK[NEQuqn;/r18of!p25^tB;3gc/A%<T_Pd%jm".Fdalc<c2o.g_IiF#]!7nQL,L#=#');V^_OiZQ#%=1h=qn6=;PlfdnS76/`0uNZPR'`>9pm"=amIWBo+)su9GbdD8Ho$a\F<PSg#PIGg#,XuA^6N++p,"dB<,-Uff]LM%-gEh_bd@u\Ut%GkmSct@KAV#M0.%2\j=RuG[Q*5R)P6(jgZ3S$sc7r"8@\e>[LoBI!=e,]PF[/FL'IHgh)!_RfH[)c37`5=k^+:n'Yo?)'.I%Q;lr9eDrXmohUWAH%GkHF^;:f)7iiDWk$l!DW"ZfcD6i"hI_RAM?FcN3QReajI&c0m!>F#0%1*lSai2kVou8&DfH*1(<AI@="dJmHO*%*h@bn_#[1b"Z(TRTZ]A<<>j55('Z:r]d%t&$q2+XkX[:/+Q]-2<SO.E70;$>KW'fpbK,fIYl/aZ<?!?-4RbLt=&;!?tno^WjFC"g!-EuqKL>2q*qSRc4:OB7un"YrNqnqp$p3X^9oCes,[eos>C;7f#U@LB-H=U0uDqa^#M8W\q27\-G$WU"jeWS:Y_0H_6Ds3tZs'J0DWIjSf2s&b'[6`XMKDa[aUXADXADC2gh:+X":atrLD38-]))j0gSa&TZB"RI/jO6VpFj0g8_'gp!jU^21kmYkkU[qMn"i`+![73eK.o`%nh#8qp\f24tZ:u`!!e$<JWWE/)FD-($VE66oX(ZDt2UXKdBTJQ5RDnq^_gQ]\@qU.8XS)<s>n['?Vm"I0(2Ig/aqdr%Z?7B<H7i^jE>fraoNqsprH3XMW@Pe0jm4FDK4i3bIXIR(?Z@YsM9,+pCd_s])=7;JeCece0#h.%(I]>$dJ[fm!NIX+l_\'2V(aENHJA\T.)O_bgFg\hOf>A<4p7H9)SQ?!FuE]JiS]%8WlJ(?doKDO/[hq>aS6).T\"f+]EY=I]i!og")_mn-@Z^ZK50OWi>5#j])"IuEE^"r;#=fI14^blo!lTqhh]8$Ae>,ZE^hf]3Fc6iSg\Y2deKt6@4"J%j9U<`Bftde&(+&4,$W3[rh+^LVT/oBm=d3YNGT#;qPG9r&tn*aM*tUX0@mA)=$59M<:GXg%)Dh@3Ss-j?__b].$TrZXGU,p>@#0gRRo!W<]B?kp"%>=b\_E8a35D^D(/EYmAeoG=XUM_+#/B:MK`>`.l.)2Edo8^]b`,kjc%BX#R>Hu*,2dKG)YW'U"?s2p!E8qK?@,c]o7P$-c)B)ABtc3'BWFZ8^Sj5*/tU<k_-9\P1mK0f!i`-`hGM:E_Z;l]"m5t[QEEGfW?6Nd-/58Dd`G[N9ck'aqF+I6<+_Vi;hu62+1-65Vp]MA2o=SJg<,!0HsRPJhq9!)C(S2@Qa`pSRss`U-j^9?.X'dUCm@nS(m+&C1WD_"@P3/G;ut7Q9]A(_$T%WlZqWgCg0YJR>LToECS699JQH]!H;1ucJ-ol.]X=M5j0,FMo&S%ErH7OH&^:o3-kA0'UYG4%#7hXF**Ae0$YD+[0R]`<-`T?M`J:NGHHWhCDQc[WWgks9'=a(Xm[4c6117Bcm#N*fJ4=a7HC/Vp'`L1;4Kp)Jf28bmSJ5m,)nA"mi(+=9.,4NkPbk>Jj+RO4<n[UB85du.B8]bj*$HRl!+I8I[>p[_tWl\`0O&>?<TH+NA'%(ZR/Z_CL<m]<>BQFhk5:*b0dnDYo(dq4StR"(=u[Oa0"58hdj_g!@/=HN_hIllSSsRD\#sihu%Fn`483U4["7"&WnYq;V9ZJ?)"qus0^<^fiP)ZIV1/KICH]A<4?$#(V*5`5&B-:h`j?q59ApBSCjO"T6T(mkAO\]?#a(qb&8An%/a_fhlcNX?*<`sZPrW3.\>p**idC`IVMn<@TTUTC0&#O!^G59c.6JS_T"%t/Y?d;5MI8@qCe$87D8~>endstream
endobj
25 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1731
>>
stream
Gau0D9ip(1&Dcq.B(_Vd&S&r?bEPgq$T'.iDj?;lMaX[a\ZuVkrUk)>`?@M,5jP!]YTc`84.87"Wt;N*6^n$H%e+oO-Q`U*$F<qZY3!Oe'$b)Z5E;ff[%3#)70D-dps@nHgmfH`\3DIYF!:%#aMIJbVNo!iBO`[Eefr;p(pdJfUQGqM91[uf@%en+"X'.X!nfhR$oX;i(gJe``2S8[^5rccK<)?%Mtu,:0`)'\GM;3I7,h@#^GG[b'Xp29L#R*\1W>7<.'sRUA<Y))QboVn?*_,o-V#+1:,U9\onl5!j\Qb,BS?o*8\ATlmdYrC.ggJ)O%RMMTJlIe-@EerZnm(K!pUo*,_+P:#Ee9NZ+C/4CWj*TioG`E`jK"d1#OX*`=6d)#X3&HSUnUI^0JM<0'6<Li#,U3p]ngOMCZXkgos3%0tDadmjSm!MaVWA^o%Zc(!XB2.I#bhDuXm*,\ZT4a8OY)LMF"3WnW9ngAeuX_)4e,AS!4>3Dp'+"Vi\V)&l2VjJ"p1:$7Q&#aiPQ-K]7*<_/U6;dafh<lYQf=>5j]XV9NFO!B`;j/`=[o&]KFY/U&!jdW:+Tu!JcR2YVtdTFIJ[`j!ER"75ZU8m,e(K-?P4Q]'9pKXh>YZ`b8Lb'D#5c&"mfQ%En^k/6^\%H)tPbM&C%;lbZpf/$_<HSMZWShCZjlC%I"\nro\RaFUb3BD,m6.?`-ApsN2@'?Vg^#^ONGOQQCP%Btd(r+6H^JqC,T<QNm5rNZh[VuDLRoUa%R-@rS)G3`AiN!!E"!V59L(IDUF(G3HVeRaJfbmn]/+UY?l8CS!$2l#.14j`]j!aXDh[0=fUf?Y<JX="pEt`+LNqnZL2@@X?DFYD=nK1^:7`B3RgJK=PE*>#kpmFQc,X)ik9<Q-:2'^#s-rH;e=ke[Y<38MpT)iR\I)se*c=*V/5K]u;OsC14bas*Oq0d9[lLj[]>r:ZDL6&)L<^$f'db*N7s4-!naC&X>Zchd<X2aSb>Piu3A5-dp93WEF8!p]H7q_WPO215S0$[Aqq%cc]I=8YA,$lJZ":fIk!4lPfoGB^d=M)l`FV6lhmXDXW92%ERmS/7\q%79?$Ft_HL-D1k2ippIV[,VkekhVqQOE)#dJO=)r4nj>8*#k/S!J@[P+jWiJ-S5VR:^>om$l9m-'cCbOrPt'\8Kp[5>`m(Sm#17DcWnZKleL.Opd2LPtsQ+5OAUBI/AV$&tNk<4D-lK<FUT:;)do?1!JpS!+t.'\:7e$C),C`EICuH"M(u`='o@3([6&EDdsP_QZg(UWE[eB5<<=e82W8)f_cq9uil5JgV[himF!JV:&7[BOi9i6tS]L.,dfJ^9M4`!n)n[(Poa@nDft:HQg.J/k(,0INnS.<c=r%7DY4f,_^cS?6EO('ko+AL\fJMCq!2*;^UsX_VcD2h8ei9(7N.kVZ/>5B_]a9:H+s4krHgG_p$5INn9t6\\XrB(AcS^EER2QY8`fEoKn_G^)!F;;lj4$kp;m,\)OJ[jLR0L0nj2Q6Ga.#B@A$sr*pbD@3-50Int39<unkI6_j?^Ju12R1+k&ZdEO;A5V2bM2]*1\]nGN?i.Y<)j@JHK6*IHWm!)XB8JnjuU0b"F>+OS;`en:93E)(gSHL71dl4F&Z!=`1i]>&??taf9M8Je0XYs<5oB*N:LJ;KO8nA7e'[bP3N8h=J0Ug!pSAA?Ja&/co5G+HTo&>qDmZ]@JrDW@j8,i[Hm*k_~>endstream
endobj
26 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1085
>>
stream
GauHJ9lJN8&A@P9Qt&G![3tr967E1>6jq2?Q`s1-W(BT>"i7BTlm-HA,6elu[G$Ua`h)?P1OcS/:*1's<u&N/,ojZ4+:sjj+=*/T4G2,Eiqn<Fb;4phcq#JHiVt'KGeHB;\Yqec0M4\99%bo0JWG^4SFt8LdmGf91PJR*P<p+gJ5ISc%('C>!\nL?":U2<3-nZ5X8JuKZgr0A^u`tUe$D!":S,Am)_@WXR+$aU0r$+S:R_-k]IN3Lb\nh$R,cJ4g4nY)Bqf.U^f+]WjHTH_4fL.5?WQAGQD"Ggb_FB5k?eQm1JCV!B.&n8hmVVU+@eRtE'`$B,Y]dXHWjF`B#:4(Nj^,PVp`]$B!e>%Am5b&kW_EEPgerrPRu*!oa+LLlAV<Cfe?]L:T$+E:J^HS<<b)J%,Q3P\0h_hpA:8\&GM`^H"pOaN_\m^A_Y]L<GdBRPcWDo,!R:HZ7O__W$4$V5:Z$C]ZWP&lXE!r)_&4D<:'?,kFWr<X_%:+\8TsC:#;.0]bR#lARf^KUq"Pta.Bm/g5!o?3ek$.EV-o>*;d92;Uj<%)EP-T*aI#G'q<`&Y0'c$'j%VSWnY.g3*pf'9;c\dWuA8]DS,UngTG&E[`?d:_\CliIa)(@<n>l>^@'^e<Hm'7G_m;E]Cpg-Y%-Cta"c*1J@+1]pY.prH-j2Ra;>B!Ph0=G]kPs4+/\\USTT7ckm*[tD=YMtUCB__jZ_ASglLlUMG15TC`)$@OT+"k2%1R3(4F2TWuhhSMs\C1VPWP7%bl/8rr1L$W0eRd7*&1[)bP;%X?1ZVgQbe7H_7HWJ1<JYrKf\k&32WUF^DSQ"P?@U%%KhmI&bY(2,PoqV8PEO@S*+'/#!r8Ke=ZP]Jftj`;1(`P"qjl.\g+cVSnq<a*9-e%bC5Lb(KAA`2'tA7Bo6Yh2%Z+bU(f!BFZh^<&`rXkoNJDeW!QC9.&2KB[:=Y<&`t.pE#5?eW"7Ucm@5%W#h[)WZ0>*U.VF)nJo]hkltTph2(>>nt`j:)oE:HWGY,M10o2:p0JLaWG^coXR'p#%=q)nj&ZqQ-e44"UDT@mWZ*i#AWk3UcRgPIquNk-PX>~>endstream
endobj
27 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1004
>>
stream
GauHLgJSqU&:N^lqB;h)9?4SM*YUn=)DJ*Po!6,I:gaTkV"49Efk#.Lg50Fag4Gm/oJq>f3AnJO3$+gl+3afB&)cZH!$Pci%72i[K._6MX`#fR4BFfMP>3'JVg'NHi_rLecdj(p#%oL2^_gF=VJt5B_"id%R,*9IXc*Z,QkmPA!t:<FENm*4#%HUj$!8+jT\[eXUMO1#GB1+8@G(!j\gPD/4W)tk?pA*Y%>A692N3]Tq=S9gce"@sg+Zrd#LCeW^dYIEOtR%p,\H>/<!91P.Yn$CPmiO!WBkjm9BZ0)9b-lR8>KY02dUsB=AG_9\SN1S@s)MobJBm7`F?iUM96!V%V^\1$9W=?j-&o),C3L;?55ZDe/et[+Fh26bJj.TEEVa.Enuj_Ni1rAO^(APjEe$[rZkE#,oIr<6qGGM-b6`\agIqSN&Rpul&G?b\IM1`P>jN_H5VuI39Y[FUr#uj>Wf!)N%$CHP6qP_6Z&%P`cmS=-e42:aeb0c"tB1J,h7m5i_gr!DQHD^T2[`pa^p\$L*=*L;VcRjEiGkG0d=.r;V`JYTaXM8@mP.GUq/k4AWuB`=YHb<lGeM<P-:c&;C'eP?PJh48Tf[@pPO8<mbV$kX<VUu.i/o.I*i+#p6sX[Y1Cs&XXCGk:$s'VgbQkr?,.o:`m7;i)&aqda$05@*]CpE+WO5q*O*Z9JKpVd@*noZ@jGrF1`W7AfWANL,=Xeqk[HNF9W6`q>hJn3!acNr/ai5(l?kDg0HIJg0us"ea]&O!R=5HaYF)N.:7n+\'";9>-,=043oAaEnC"+-Os#p`T/V[]WFp8#KeLIoE)p58G@;nrK?c<k))["p0np57GV[.H[G?;?L[G)H(_aSoQ"%S%kF$Y?YrCMZE6eKHoH[CnIti)h29f2-i-5bbqE7sAfc;&@d]1LWa3>j#SDs#2+2/k_CLL8H"rtQM<A-.WIj7/=O2"[XWpcl)9@[rhd&]"*7U'ru*%!*uW(*6]kN)`Hhc2rge,~>endstream
endobj
28 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2226
>>
stream
Gb!;f>>s99'Ro4HS-Rb>]>7&/]l+$e\(`1(-/6_jjMa([h"m2A*>neS*r2Cs*E&0J%RX`:l'tQ4VP>f@5k'P@s1/6H?j`h#.8U5t>G.FZ_/osLe"_DR'[n8+bs5^7VGmC(Ikg`hiJ>>1;$a`;VJ\X!\o)(T5$T0Ei[c7t<fBA4U8^2[2,H,%9g]-h,uNKOpeEB5"f+h"[O?[_LrZYSO'q2-`#NC&dH0lXm*-K:IY[/l+g\_@lAB:4(8"+UXZ,EOl8a<'M...Q+pc(5e2D8=<q[ZEV!-p3<$<OE<;-*n]4/4KW([;*.96XjinSN-GO0u[`O6\KcPEeK"!c$'/GP1\Bc'RRFi<>F_IqA/\n30$bpMX8/b^,,$H6h@J<'Lk@0FrU[r9Y<"u.]<&`'Z"'gK$Ija?d7q:>/7Dk^r7^B"P6(4U@?T>"CCc9dmu!F2)7^d0Q]:NHiE1-lYP?B]mo'J,si@q`jN:"*%!@CdF&HPD1u^&PH<1:'r6*@,nMV*%nE9<ok?SS4L`LfVMm*m3[Y6SgGq."2_;(PWZm]rUac0TN;#%q3JF$.il*MiaS(<'mI7PpG4$:amNI=^TcPQ\FP"+poKZIemJl)@4CO<,-sV$g]s3q8jnBk"@Z+U(GSnoN.SQQ3--7d6?kQZ4p<jpJ/rqE9TGUlFAU*jt0UlIYF&^F1;W#]Jp7Nm\1g-_6MiEUs$>I1eg!]]%Dk3o"A5raSCni1=EP6-I'CiI>m/-??h6Vqt5?lL[,K.3hoc6qVs3W9$oDS^l=KkDPJ%dS-3=\XL?nni3Mun.`g^PC3G6Q%?*f:LBUcspb`JT]=Tu7\TO=1i9^qY.=)1nJoq+[*q"q6=Ts2/r+3[qPjdK\84fb\l.N9kLh0\V;Q[-G>+1=T^DQtYJ%tI"$KpecOS)l<8bBi1;]$3ebHYN0Pp=s#[^fT><K4<7p%c4"/Z\Ki5Y<K7Gci;Je''j"nZI+S@O@?s;NG#CTN.$jjd8o+<G#o8XPg4SCLCYQfG_hg2kS^.*ZJ@bB][jdc+:mOldgUmo6A[S>73oNLmPFn=U#7r--<dTeHbaboK[h@7Gj&mU-\<S;1Cu[##:'?H;c/-IE4&#keTn'(qss[L#[LD'*Q^QqlMh8;]a4?2dJIn?EWI=_8COB0]%+!NlKkBT0C8$b$g,A[Dps)`t>#Fb!T:>d\S7*6`T2\Us=tG':>bDKMsWEJFgSNm(<KuC<L_p8l+`JJ5%I\\&)tC@-QcR:up!5hZaEl3%oiiDK^=pV_`Z%:,n#!chHCQU\!:i#eVDna#8=6/MU&*<HsSlm<KD#ge@egL9He\(6/]mDQ^aEUT\_c"O\]Z^cBFAfmN5hD;">dc'4SILj&:6eI\7i_Y7:IH?o*aV_m,]oqUXH,]jS<LP3\YT"BG*Y9GO`cMBN&OmdR%)WgW/X"?YN7WGKLj;(gD-h`]OI+NoGOMKPYCUeTrSKPK\[)+('*5R>c6Zk=l<ZZ4EWDFE1'aBGuI2O#gjWoZ)reCp-$PGWaq/q@Oek4+^I@K_COk#rocBiO0)I(XuB]'BJ=bV#d+Vs0.KP*c47MXa-M#As9T/qa+:Ju'4P=?@.??QpeSk2E@AMSi@GCFZ*:NGkfR!RcgIMtWOdX49WcdKGTAWE%Mm"F&q=t["!BXQa9)k*=@Pfb"Y1hET:V!'kEbr2asiTYe9)6*%lD_e<<0#pQ2eWF]H(r-M,F^Q+L@<0QO(Eka%Sp;YQ)o5?uo[8(>]5r.cISs.::dWmk-A>a,ftE_[9Ks;ZOI+m""b50i>uDC8Z%]14^X89dS7ZR\N3:1L5DT9O#W^)84c?/4?AR6cV<mcNSDHZc>1668^WsjZ^L)`VAUVbErUmP02A`nO`EdnWd_=,302"PJr]6p6DN;0+H3RN32rfML`M_P1E^<],F&j^R`l^41H_%nM/bF(;Fb=#'hPd<:NJl,'F:7?WW4J79TnY.SF;]@JZ'4j5B8]1u3H!#AjPhq19-mYu4h2;dkN?e+l8fTbs.Nk'cb<X[m[[lIF%-b[!CE\j^jRlk/XL$2f)_%!nL$W#$Vo.IM>rX2)I'oZc,kuYHjuOt%d:N`!.J49+TidspOUfm9rtS#B!!FNDO8W<B-/cQEC2[U%1E8aI[!0i5-l<4i+!sZkAD5],d>aW`6PVHa7h6mQjcDTe(+k@2:/G&CU7%LYu/Y!l<.k)_pu&G;(Nl9IN,[S7KcAS<P7[tG`e=N3;O0T-g)Z~>endstream
endobj
29 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2442
>>
stream
Gb!#]>BAQ-&q9SYfVabbZ"X9PVfNnqfh'[sZ"*%ZiJ_D10Ek$]GYq&RXulUPB)u=,aV#gYFJe(i#d/^6`U8N;`KGb.Imj;Y`W-fb3."GO:`)uZfS0jqCUb9)rHVpu^1d`b%-lLU_2!?3E;/=I_UD?`NX_T?64An7lVRe[UQV1O\-7Uk1,EaiTn*Z-9o.sn?m$iVG`^2"!`H%o)<sXFoS,I9fd)8enW7b#mgZJ'#PZ9Z0`D0o5:`>MKu>].\$<H8-;uYXM%hLU/272^n4ck,0M13^Q@(hl>;D^`:R5HfCe>5QG?6W*%#`h)IDa[Zh6In'J&b;40`o*Eq0\<]#cL>N`e)P#SVGNsLS.CNXF*K"lIZ-;@L"6kc7XL!)C7?^)*>A,;ecBfFS[d3`&0\b)8pNCf>=Fl<_g-Il1cg,,>@U1f\Y;.$Nc;*=sKomaT^9LoP(HN2=`<+[1*>RgH!IQg*W<D,Ske;e$4^S,a-u2WTb;(;YN-L%-O;uO$X2FDt#^Yg<*6f`DF!M3Ng.-3mb8tKI4Njl0cuR]JLX2n)4."MI7iE)3Z7=>)eBK6,>3KnWJo)*i:1TFt7:AK-?<)lku[7#3Rd)UQq:]H\s=l1)<>!c3J=1,^X34U,PUghe-^1poRb9dXT5cJ*[aYoV%-73P^3'"cDFlRb=L(Rc%3L2;`he:q`5Bd9U*`r3XInD&/g_5uiQ++Z7flfCWP)d)`A7fM*E!ahh=r@FcF@+$OVqeQ#4E7@;c$42+dMT/@J<3YiC":t4_QVF&1<&7NedO:1)*NUh;Ib;q`LV*2?Q&)^AIqKraIbMP!&r5p)6$/@_fH(*M1CIh/22%WiJ:8#AGAK%a#OGB6+aBVNd_`<c\%Bu3O(*]0;BK6EKd"!*n'2u[aOU0W-`:&a_.^2rE"_oam)TITj00GIIA&MLccF#X/i"!$3s%+eB$2_LOY/EG;jH"QZ-ph6Zipd,C9Md=.Q'9_+/h_sShnNFha#A3]epRA.s7(L+$#ZrmcqLj+"Ui)>oZ]A'mRMJV*tNMSAbq(J2o_sN(0Sesq+F6WO(Tn8Wd/o_P9l,^T/%R8_c[?o--p`VGGV_gCknkOXKpi7J]k.s4k4:FS`kDZMpglAJifPWdNfV>,1:HQ6.&J(LFbaO:=dRO(OFe$XcKKS<!_2`@9$`e:ob!4T/X)?opu&e4uLT;dQVX]S50ZbmiOIDhOM<0'gd<Fi4NCYo]P$F!u?Wp@9`pZT'^')+k,$s/q_Lggp0U#0*LWKMr:SuTGT-;o2p];\BWGlOlOj*nC;F':.4!IgU7b5rS;*+K;?1,IVLd[lC(j[q!9eqeqcT$NEDo+#=$$QAC3>QB`A&OFs<^3L9q<pK4LFU>\;/U/hq+r1)\BPBtnO2\(e)")7t<Mp+s=ri"1r#(,#jdc6Jq&Dd(Kb!U/i;7N;4%/rY"*`R]'\L:cJSqT-#:>iNNcSs8%l&^^fo:*T"[LW`B1^&-[EI!>^b7NYe`.V615O>PfVB64b_#>(lK>uc=,ddKH-rI@$#k%UQR38./L#r`7)K8@:sgBu)>D]H?Rft,j:)qqk_Vg.ku;g1<G&_=Fud;lK_1YE8L\&[8Cfl$gjOh,6A4Vp!0h;0TL7B8Gn^//ksnLLUXePs#T\dbZF;sadSel:@rep<L6Zs$R!<\:<pW>=!F6W`PSI3j[64fRUZ:R:0ZWd7^q/ZgAbD84Ou2lQ2XHSs]#8`=8b2"+HE5lh;kZb"<>4lmbF8'6)oVTVB5K$m.]+"&TaaX?jI^iq=[dk'XF[X12\[^XAW)0F>g\.e[>e:&`bflEQMM'N?fm5T@AILQNKgk0M>DY]j>U5.Xq:%R<?ZEiBUritK$oMo]t*)!ur`W>T<f7+P(To``l/OSoT\T\S^cp4+<n^0*f9[mFAOW7j(%/d;jj8$4Lf,('b"!Dm+P40>5bcYumn[J[Vhfa;(+0UT)s)IPej"&AW]!<9EI_i)`KLoKP[Bp`4#s$UckXCe4n/@5YAFV<t5lP#/XBP6I&4r7/eT_kYgA2,eUFef`F^Pp;Y4YeJpM1AXD*!5@5#J-V_I1NS^2VEN@eEm%=+#mr$Ci4OR#&Db(;6[7^Cq>?rE#Yd'/fUubJa#jnc]QOEadG&"ZD6:ejKa*E(j%I?.*-f\D@&6k\YIP--Kn*W\ugob9k!;2DM@=s%Ou[>;c9'a?b`!6m:\?pW#>m,cS_!!t4:D5H==]#q=K(Q@g'qZ7oiM:h?eX0h':rS2n6n*;k$USZ(hhD5X7>#.F!ZDbn_!cT+H)QDou;Pt0/F2GXo[+jY5>Hqme6?=#mm*A)O8$RAt@V&>R?j)OT,D"Tg1e-omq&#l'<E.L[E0uLOQPY2bm:F;tp4iKq5E*JX`^Woj`7TmJ=GGD0E;4:MXk.LA54K-m9DTaD0F=o.Z3%."j3lEH3gg[XR6O?V-dj8rfXF;\b>r_[F\@_ne~>endstream
endobj
30 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2396
>>
stream
Gb!#]968iI'#+6EoP)L:)GpY4Y!"eR1ZO<44-k*QiX8.@1<+\i+DHo1f5Ca6-'<NK&QZ36Z3>eEUHa.^NGai.N?=np`u2\53uEGk5UbF4J@LmQGF*8tGP(:D$:<L(-s/<F4b@&+(PUW$N[R"3jl!Z\GWoZrH(f,P0KEmdKh>NZq2I)OFZ^SQ@(Cpn^'>EG,$k7iXsT6",qVqhb2E&PbEsRZ>`,NAE.<7XIX,r5i<.m6%<oQ8R@=kHB*J:SjO5<FM1k&W@-PZF/$bqs7PuBZ6p<pEF[JI#]G?^+KG[Osq7W_?jB)n7JVI4(Q+LIG%ac=CPZUem1&,9&71.PArl0VpaNhf&q*aH]B8SJX:sY+t'fWF\3nJ>*)Wb]jn\ITj,AI<ulKf>B&`4'b[3M7bq@7u?H-Q,_)=GjQ%EDo5iFl9e1#"G^j?TMXN34_5`S^j'D$+0e$<`dsU\:E0iV6H<O.B"ug_SteU@/^ViD3^9C:RD&-%Y05mui)F.PYS$..WsO>L.)/MB(7t>e+:s(`P6u])gV@_(XR#dXud6&^gi.p),V?QWb3`ZWSG%\>M06\B#>WHIna0bl:g:?C'5H_TC%+,[r[lP34PQHT5tSW8jR[3"?k$#H^/'C]fEr^jR._B,A(Yo<XAT>eP36)g7"ik)Zo@'4B:pOt>0gS['Q.OOR1hF1<Yors]iM^tCJU=`O-I2Ku_^<Wl["?GMn:o(<Xj[oto!'LQ)SlSjgAnV>KjN)^:djao!'(J<XH>Egi'eMHA=$U.lGcgh3>Re@2C@),&!ZCK9a#Y#BjKcrq)f,BB:#;D+[lbC0[.L+;[@o5BS=YCQ5kPgiRIi7A3L/2&mF_M8Y238&DEZbUSI\X[E-Meo.ANVL(&n2V@E"I<6gXu!HWeYFQ*11#@s$*_LL__I95mhZqjNEPMPSd3FV$XCDHq,WW121BrM`fg<k59d[J%m1K0rKAq:LM^NBhNN%B?e?&bLSgRgS&4IgJcWU]BP<dPKflJ$Ct&4,=nj&2pJa08r229rN'^OWogpQ/8V\AQqj#4Ci%8'=5p!HFF,UPH1\N534P1nR&m:=n+i":`pi6%B0GBWBF.WcLrY#81``..pd%kAY':#3\<&gb1>2-B\@f:S?DZ>t!;7f"/Kod.%3]*Uae;@u=!i^$r*,?%n86)!rp[BBL[LWfXW*D"9^^6c2#6SPX@_2#2fs.$H\^C6<H\=8IskK;2CiYuA;7:"n$d"rqSop8IGnOP>%EOj0MM"CfY_ZaN/a!?YJBt*<76j^KOWt;IRd1to^oPH)ci:$TS-Mj(KncL7*"roe*.B/k:K1.V]n!WhXV;Kr+/@r+W0mmiP9gNU"3$"diF%d)_SBjbEPq?%kXguQun*kdN*Z:1HC+l5E/5q`1C9g\B4SL$Kna`Lm;<g\8fl3%^L+7-MG5s%\_M#F3F[YoLrY@0;c/"nP7Q-hOi[_DE5M$WfZH9Gjmcb'lH$^>$o8shcI_B[_>S?rAB?Z@FepHMj;PTlB8=7[F`*#gDR0kr3jpYpUP.5]C&lP\6=U?=D@!L9l%F+%>(HP0s1/kNbZKYcH^1C$"&h/GBe,^lk8W'780Y:\LSFKpe5nb[h_9>N8#6RZ-Bl`j4J842]Aj^YFN5r"Is.an??A^+%o_/X.qoDJsj#8</m`,^^-S_Ws&$^H&b8]9N3rb:f^\>*sC^%59?'#$dY3]eTK1+(Vfodma)dPH"*aDRL@bq/ohG_I/.$g"B(A=b)l6Gj@+bHn=WSk&&P*hO,%r!B1hd%>>TO6'q[-:*t)3s[CPg4@%K,Or7iC7Z7*nYjE&j)3>NI:7bN'jZ]0mi+-5_`6Onm/9iGpH5m35Hq>Q",J^dt-!u!00Z@`_Th;59j%COPhoeHiO(hD./N)E9C\uiCIYW:E@=i%LV1$ZGp#OtBkN2)Lu)UD$5\?lT+f#$?!k4uM<dTW-s\;8+;b)sAk^:fPP3BdRD`OMH]SUiCm^@6V%QrO!f)c/TR"U`BsdE8T"j(rL5:1HJCdW]0nC^otR=Zd"5gTR`Yi]6/p`e!b>io`NR3jNJ":74e6'#nmb9i6%-QhntbaEC)IJP0JM(IgKc+b;Q\2S+n81hBS/Q>iG$&rd-I,T&*Gjmjm7F/G]m"uYF9k4Q`k6Zld\nN%oK01rgcHuCrMNspZmfuCX](`4JY;+&#4Oo/FCScg6u0p\/NMTm:,4D@U$pRu]NDNlsp#,SrP@M95M/6ErKL2j"e\/$O:2:/Xh0i!rE98ki.0E^PH9qg4JfmX.[76u*P'4O&@T_#V>9ecB6C1Qb#o>bqZjYDluq*e1?2t\)Ep;/Ohf!/WY%VuCK1"q$q"M:ee\)3_X&q*;q3d`hDG(g61n_](g8K7#)F\)GaSfPD,JW"n&d=Gl2Z`bDu3;O^](?=K~>endstream
endobj
31 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 454
>>
stream
GatU.bAP3?&A7ljk*Yd+!J>r5)^SL[7"+luMebDR>K:VQXK#8b^-EYq&+rmFfO`%Gc2\:&%2RNB%:#g@S1lXWF9s:M5WZeBNSYnS1lVqLiCZZ'K&:Q1gdE,(;$/8?A:c\7e01m_)"i")ZPequA44A!)Z_-";i(Ws9M?qgPm=O";BQC@2$W[#k#p)@<^#+KMnsd'RkBF_Ub>7l4QdlL8YV@Mn>L2i<Db[/.]X(&`)*5.P@5jqM6j!Fi[kbQpCqt;SZ._Mf+g6'\5a1_UtoU_&rcfuKJR)EpcX&uAuci?o&KdimiH,&81:93KY+]UX7O'nX*u&SEg->@Q]i8<H=rCe@tXD6CL6PaG"4,[af0CVE8FQ-[B$q>PIS6$)FV00HrO>XF!a9B<&fSOpk(W+(hL-n2jfq+d=,[%`i[MV]#:Ob])pGnBsZ(8G58SQjbZf%5G78;DZ~>endstream
endobj
32 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 772
>>
stream
GatU/?#LB2&:Dg-fJc\B\``k(8#TT>C.4ijfGE_`QPf/W@/GiPmo__D8Q(+m:aFe8G%PC,)\*1&G[.imi-c!"2]R&LD%AaA3OF!Lh9LJn=B-_OP6+CX]\p/ND^g)40MCBf9LFq0<Ko1(;:P+m^uK6,<sQ0gQ$Y9PB1:P8^iI`$Z2d?f]VrWK!eB_c7D]<K@=F9G'@O[e>$?TWq>L!BmF0#X[,7O))`Wn0]O4`b"MQY&<t_oB@Q8tD->DauA2FU29!VF:6a4LdK;U8^lqGCYs11fAc=j=_*MkoT'a!QJ0TpJ-eG8RuG8mRe8<^DC!dp]^3?ZHI$>NDc>J@\pX5,p%-/U.]Ubf3q32\>Wc]fafe%<97W+3'#7]5iJd3F#QG%iKiHJrk>A5DifGKsMULJd%"kqBrM,As:`b\.N$^Z*Fpm%9go4"E/@a_nDZQ$/.kZ.PaLH3MHBdN5ea$/U3#r1GmpDIJ5;XVe"haJnbR'qr8qR_c*j!VVb8d^5#Yr!o4<DN$pf7M"7m+f;fs&k9,0D*0A3&=oLU952PaAO,H2F@LU-3e(fUM?VgrU[fT#TMjdBT$bQ(C5J6gHpKV&(LZT&^OFU.Y8EM]/g.NFCGQFjTYM0Noq"(;=_XW,*[2d#h-.=-Ph7ET%$!W0:#[r=AeS]+!Z6WdNa@]EHYSaV[L358O!8obI^1+.$R_s1dWJSBpE=u4k6&G<LWj&JMpuG:`ro_,UJTZqTH$La1BYA`Q&;Lo4oi"H;8LdHip^bso*Vg24"af"~>endstream
endobj
xref
0 33
0000000000 65535 f
0000000061 00000 n
0000000144 00000 n
0000000251 00000 n
0000000366 00000 n
0000000478 00000 n
0000000673 00000 n
0000000750 00000 n
0000000945 00000 n
0000001140 00000 n
0000001335 00000 n
0000001531 00000 n
0000001727 00000 n
0000001847 00000 n
0000002043 00000 n
0000002239 00000 n
0000002323 00000 n
0000002519 00000 n
0000002715 00000 n
0000002911 00000 n
0000002981 00000 n
0000003315 00000 n
0000003446 00000 n
0000004126 00000 n
0000006084 00000 n
0000008926 00000 n
0000010749 00000 n
0000011926 00000 n
0000013022 00000 n
0000015340 00000 n
0000017874 00000 n
0000020362 00000 n
0000020907 00000 n
trailer
<<
/ID
[<1a6aa1302ad6ba2dca92b79c88f91ea9><1a6aa1302ad6ba2dca92b79c88f91ea9>]
% ReportLab generated PDF document -- digest (opensource)
/Info 20 0 R
/Root 19 0 R
/Size 33
>>
startxref
21770
%%EOF

View File

@@ -0,0 +1,175 @@
{
"summary": {
"total_artefacts": 18,
"mentioned": 3,
"likely_relevant": 1,
"possibly_relevant": 5,
"not_covered": 9,
"skill_auto_generate": 5,
"skill_assist": 3
},
"artefacts": [
{
"id": "DEF-01",
"name": "Customer Profile",
"phase": "define",
"step": "ideate",
"skill_support": "assist",
"customer_facing": false,
"relevance": "mentioned"
},
{
"id": "DEF-02",
"name": "Strategy Map",
"phase": "define",
"step": "ideate",
"skill_support": "assist",
"customer_facing": false,
"relevance": "mentioned"
},
{
"id": "DEF-03",
"name": "Point of View (PoV)",
"phase": "define",
"step": "ideate",
"skill_support": "auto_generate",
"customer_facing": false,
"relevance": "possibly_relevant"
},
{
"id": "DEF-04",
"name": "Ideation Workshop",
"phase": "define",
"step": "ideate",
"skill_support": "reference",
"customer_facing": true,
"relevance": "none"
},
{
"id": "DEF-05",
"name": "Business Case",
"phase": "define",
"step": "ideate",
"skill_support": "auto_generate",
"customer_facing": true,
"relevance": "mentioned"
},
{
"id": "DEF-06",
"name": "Value Story",
"phase": "define",
"step": "ideate",
"skill_support": "auto_generate",
"customer_facing": true,
"relevance": "possibly_relevant"
},
{
"id": "DEF-07",
"name": "Value Story Delivery",
"phase": "define",
"step": "validate",
"skill_support": "assist",
"customer_facing": true,
"relevance": "possibly_relevant"
},
{
"id": "DEF-08",
"name": "Joint Engagement Plan (JEP)",
"phase": "define",
"step": "plan",
"skill_support": "auto_generate",
"customer_facing": true,
"relevance": "none"
},
{
"id": "DES-35",
"name": "Solution Proposal",
"phase": "design",
"step": "confirm",
"skill_support": "auto_generate",
"customer_facing": true,
"relevance": "possibly_relevant"
},
{
"id": "DES-36",
"name": "Partner / Services Proposal",
"phase": "design",
"step": "confirm",
"skill_support": "reference",
"customer_facing": true,
"relevance": "none"
},
{
"id": "DES-37",
"name": "RFx Response",
"phase": "design",
"step": "confirm",
"skill_support": "reference",
"customer_facing": true,
"relevance": "possibly_relevant"
},
{
"id": "DES-38",
"name": "Commercial Agreement",
"phase": "design",
"step": "confirm",
"skill_support": "reference",
"customer_facing": true,
"relevance": "none"
},
{
"id": "DEL-17",
"name": "Cloud Operating Framework",
"phase": "deliver",
"step": "operate",
"skill_support": "reference",
"customer_facing": true,
"relevance": "none"
},
{
"id": "DEL-18",
"name": "OCI Operationalization Framework",
"phase": "deliver",
"step": "operate",
"skill_support": "reference",
"customer_facing": true,
"relevance": "none"
},
{
"id": "DEL-19",
"name": "Retrospective",
"phase": "deliver",
"step": "improve",
"skill_support": "auto_generate",
"customer_facing": false,
"relevance": "none"
},
{
"id": "DEL-20",
"name": "Value Realization",
"phase": "deliver",
"step": "improve",
"skill_support": "auto_generate",
"customer_facing": true,
"relevance": "likely_relevant"
},
{
"id": "DEL-21",
"name": "Customer Success Story",
"phase": "deliver",
"step": "improve",
"skill_support": "reference",
"customer_facing": true,
"relevance": "none"
},
{
"id": "DEL-22",
"name": "Improvement Actions",
"phase": "deliver",
"step": "improve",
"skill_support": "reference",
"customer_facing": true,
"relevance": "none"
}
]
}

View File

@@ -0,0 +1,125 @@
[
{
"id": "FF-202603-008",
"date": "2026-03-14",
"contributor": {
"name": "Diego Cabrera",
"team": "Field Architecture",
"client": "Vector Search Customer",
"context": "AI Vector Search engagement",
"confidence": "validated"
},
"product": "ADB-S",
"version": "23ai",
"severity": "HIGH",
"category": "limitation",
"summary": "Distributed HNSW indexes not available \u2014 100M+ vector search requires partitioning workaround",
"detail": "ADB-S AI Vector Search supports HNSW indexes but they are node-local on\nmulti-node RAC (\u226564 ECPUs). At 100M+ vectors, queries on a 2-node RAC\nmiss vectors on the other node. Results are either incomplete or require\ncross-node scan that blows P95 >200ms.\n\nWorkaround from internal DB PM team: hash-partition vector table on\nvector_id, create partition-local HNSW index. Queries hit single\npartition on single node, maintaining <50ms at 100M scale.\n\nRequires table redesign \u2014 cannot be applied to existing unpartitioned\nvector tables without data reload.\n",
"workaround": "Hash-partition vector table by vector_id. Create HNSW index as LOCAL\n(partition-level). Ensure partition pruning in queries.\nSource: internal DB PM team contact [name].\nValidated on ADB-S 23ai with 120M vectors, P95 = 38ms on 64 ECPU.\n",
"oracle_sr": "",
"status": "acknowledged",
"resolved_date": null,
"resolution": null,
"affects_matrix": "AI Vector Search (HNSW)",
"tags": [
"vector-search",
"hnsw",
"distributed",
"rac",
"partitioning",
"100m",
"latency",
"ai-vector-search"
]
},
{
"id": "FF-202603-002",
"date": "2026-03-08",
"contributor": {
"name": "Diego Cabrera",
"team": "Field Architecture",
"client": "Strategic Migration Customer",
"context": "Production migration",
"confidence": "validated"
},
"product": "ADB-S Dedicated Elastic Pool (DEP)",
"version": "23ai",
"severity": "HIGH",
"category": "limitation",
"summary": "ADG must be disabled before joining Dedicated Elastic Pool",
"detail": "When attempting to add an ADB-S instance with active Autonomous Data Guard\nto a Dedicated Elastic Pool, the operation fails. ADG must be explicitly\ndisabled before the instance can join the DEP. This is a known issue\nacknowledged by Oracle but not prominently documented.\n\nImpact: requires a brief HA gap during DEP onboarding. Must coordinate\nwith the customer's change window.\n",
"workaround": "Disable ADG \u2192 join DEP \u2192 re-enable ADG. Plan for ~15 min HA gap.",
"oracle_sr": "",
"status": "acknowledged",
"resolved_date": null,
"resolution": null,
"affects_matrix": "Elastic Pool Membership",
"tags": [
"dep",
"adg",
"elastic-pool",
"ha",
"limitation"
]
},
{
"id": "FF-202603-004",
"date": "2026-03-01",
"contributor": {
"name": "Diego Cabrera",
"team": "Field Architecture",
"client": "Strategic Migration Customer",
"context": "Production migration",
"confidence": "validated"
},
"product": "ADB-S",
"version": "23ai",
"severity": "MEDIUM",
"category": "gotcha",
"summary": "DEP provisioning takes days to weeks depending on capacity",
"detail": "Dedicated Elastic Pool provisioning is NOT instant like ADB-S Serverless.\nIt requires physical Exadata infrastructure allocation. Lead time varies\nfrom 3 days (if capacity available in region) to 2-3 weeks (if capacity\nneeds to be provisioned).\n\nBilling starts only at AVAILABLE state, not at request time.\nCo-location of existing ADB-S instances happens at the next maintenance\nwindow after joining, not immediately.\n",
"workaround": "Request DEP early in the project timeline. Don't make it a critical-path dependency in week 1.",
"oracle_sr": "",
"status": "acknowledged",
"resolved_date": null,
"resolution": null,
"affects_matrix": "Elastic Pool Membership",
"tags": [
"dep",
"provisioning",
"lead-time",
"capacity",
"planning"
]
},
{
"id": "FF-202603-007",
"date": "2026-02-10",
"contributor": {
"name": "Diego Cabrera",
"team": "Field Architecture",
"client": "Pepe SRL",
"context": "Discovery engagement",
"confidence": "validated"
},
"product": "ADB-S",
"version": "23ai",
"severity": "INFO",
"category": "gotcha",
"summary": "ADB-S Serverless RAC node split threshold at 64 ECPUs",
"detail": "ADB-S Serverless runs on 1 RAC node at \u226424 ECPUs and splits to 2 nodes\nat 64 ECPUs (16 cpu_count each). The gv$instance view only shows nodes\nwhere the PDB is open.\n\nThis affects connection pooling behavior and session distribution.\nApplications should use UCP or JDBC connection pool with FAN events\nto handle the multi-node scenario properly.\n",
"workaround": "Ensure connection pool configuration handles multi-node. Use UCP with FAN.",
"oracle_sr": "",
"status": "acknowledged",
"resolved_date": null,
"resolution": null,
"affects_matrix": null,
"tags": [
"adb-s",
"rac",
"ecpu",
"node-split",
"connection-pooling"
]
}
]

View File

@@ -0,0 +1,26 @@
{
"total": 8,
"by_severity": {
"HIGH": 2,
"MEDIUM": 4,
"LOW": 1,
"INFO": 1
},
"by_product": {
"ADB-S": 4,
"OCI CLI": 1,
"ADB-S Dedicated Elastic Pool (DEP)": 2,
"OCI DMS": 1
},
"by_status": {
"acknowledged": 5,
"open": 2,
"monitoring": 1
},
"by_category": {
"limitation": 3,
"bug": 1,
"undocumented": 1,
"gotcha": 3
}
}

View File

@@ -0,0 +1,206 @@
[
{
"file": "kb/architecture-center/catalog.yaml",
"matches": [
{
"line": 25,
"text": "- title: \"Deploy Oracle Autonomous Database on Oracle Database@Azure\""
},
{
"line": 267,
"text": "- title: \"Deploy Oracle Autonomous Database on Oracle Database@Google Cloud\""
},
{
"line": 427,
"text": "- title: \"Migrate on-premises Oracle Database to Autonomous Database\""
},
{
"line": 463,
"text": "- title: \"Migrate a PeopleSoft database to Oracle Autonomous Database\""
},
{
"line": 623,
"text": "- title: \"Move Oracle Forms applications to Oracle APEX on an Oracle Autonomous "
},
{
"line": 635,
"text": "- title: \"Stream Kafka topics to Oracle Autonomous Database using Oracle Integra"
},
{
"line": 795,
"text": "- title: \"Implement Oracle Data Safe for Exadata and Autonomous Databases\""
},
{
"line": 1140,
"text": "- title: \"Deploy a microservices-based application in Kubernetes connected to an"
},
{
"line": 1226,
"text": "- title: \"Deploy JD Edwards EnterpriseOne with Oracle Autonomous Database on Ded"
},
{
"line": 1262,
"text": "- title: \"Run PeopleSoft ERP and Autonomous Database in an HA multicloud deploym"
}
]
},
{
"file": "kb/competitive/aws-mapping.yaml",
"matches": [
{
"line": 32,
"text": "- \"Autonomous Database \u2014 no equivalent in AWS\""
},
{
"line": 81,
"text": "- \"Data Safe included free for Autonomous Database\""
}
]
},
{
"file": "kb/competitive/common-objections.yaml",
"matches": [
{
"line": 12,
"text": "- Only cloud with Autonomous Database"
}
]
},
{
"file": "kb/patterns/database-ha-adb-s.yaml",
"matches": [
{
"line": 2,
"text": "# Composable architecture block for Autonomous Database Serverless HA"
},
{
"line": 10,
"text": "Autonomous Database Serverless (ADB-S) provides built-in high availability throu"
}
]
},
{
"file": "kb/pricing/oci-sku-catalog.yaml",
"matches": [
{
"line": 462,
"text": "display_name: Oracle Cloud Infrastructure - Autonomous Database & Exadata"
},
{
"line": 465,
"text": "product: Oracle Autonomous Database (ATP or ADW) - ECPU (2 ECPU minimum)"
},
{
"line": 471,
"text": "product: Oracle Autonomous Database (ATP or ADW) - BYOL ECPU (2 ECPU minimum)"
},
{
"line": 477,
"text": "product: Oracle Autonomous Database Storage for Transaction Processing (ATP), us"
},
{
"line": 483,
"text": "product: Oracle Autonomous Database Storage for Data Warehouse (ADW), using ECPU"
},
{
"line": 489,
"text": "product: Oracle Autonomous Database Backup Storage (ATP or ADW), using ECPU"
}
]
},
{
"file": "kb/services/adb-dedicated.yaml",
"matches": [
{
"line": 3,
"text": "service: Autonomous Database Dedicated (ADB-D)"
},
{
"line": 8,
"text": "what: Autonomous Database on dedicated Exadata infrastructure. Provides isolatio"
}
]
},
{
"file": "kb/services/adb-elastic-pool.yaml",
"matches": [
{
"line": 3,
"text": "service: Autonomous Database Serverless Elastic Pool"
}
]
},
{
"file": "kb/services/adb-serverless.yaml",
"matches": [
{
"line": 1,
"text": "# OCI Service: Autonomous Database Serverless (ADB-S)"
},
{
"line": 5,
"text": "name: \"Autonomous Database Serverless (ADB-S)\""
},
{
"line": 38,
"text": "name: \"Autonomous Database Serverless (ADB-S)\""
},
{
"line": 47,
"text": "name: \"Autonomous Database on Dedicated Exadata (ADB-D)\""
}
]
},
{
"file": "kb/services/database-at-aws.yaml",
"matches": [
{
"line": 32,
"text": "notes: \"Autonomous Database on dedicated Exadata \u2014 NOT serverless\""
},
{
"line": 37,
"text": "- name: \"Autonomous Database Serverless (ADB-S)\""
}
]
},
{
"file": "kb/services/exadata-cloud.yaml",
"matches": [
{
"line": 20,
"text": "- \"Small workloads under 16 OCPUs \u2014 use Autonomous Database Serverless (ADB-S) o"
}
]
},
{
"file": "kb/services/oci-networking-core.yaml",
"matches": [
{
"line": 46,
"text": "description: \"Private pathway from a VCN to supported OCI services (e.g., Object"
},
{
"line": 84,
"text": "description: \"Resources in private subnets cannot reach OCI services (Object Sto"
}
]
},
{
"file": "kb/well-architected/security-compliance.yaml",
"matches": [
{
"line": 148,
"text": "description: \"Private endpoints for Autonomous Database\""
},
{
"line": 150,
"text": "pass_if: \"Autonomous Database configured with private endpoints\""
},
{
"line": 151,
"text": "gap_if: \"Autonomous Database using public endpoints\""
}
]
}
]

View File

@@ -0,0 +1,50 @@
[
{
"feature": "Auto Indexing",
"category": "auto_management",
"compatibility": [
{
"deployment": "ADB-S Serverless",
"version": "23ai",
"status": "GA_CAVEAT",
"notes": "Creates indexes HIDDEN by default. Instantly reversible. DML costing prevents over-indexing. Deduplication with manually created indexes."
},
{
"deployment": "ADB-S Serverless",
"version": "26ai",
"status": "GA",
"notes": "Improved in 26ai \u2014 better cost model, fewer false positives."
},
{
"deployment": "ADB-S Elastic Pool",
"version": "23ai",
"status": "GA_CAVEAT",
"notes": "Same as ADB-S Serverless."
},
{
"deployment": "ADB Dedicated Elastic Pool (DEP)",
"version": "23ai",
"status": "GA_CAVEAT",
"notes": "Available but less tested in DEP."
},
{
"deployment": "ADB on Dedicated Exadata",
"version": "23ai",
"status": "GA",
"notes": "Fully supported."
},
{
"deployment": "Exadata Cloud Service",
"version": "23ai",
"status": "NOT_AVAIL",
"notes": "Not an ADB feature. Use manual indexing."
},
{
"deployment": "Base DB Service (EE)",
"version": "23ai",
"status": "NOT_AVAIL",
"notes": ""
}
]
}
]

View File

@@ -0,0 +1,86 @@
[
{
"feature": "AI Vector Search (HNSW)",
"category": "developer",
"compatibility": [
{
"deployment": "ADB-S Serverless",
"version": "23ai",
"status": "GA_CAVEAT",
"notes": "HNSW indexes are node-local on multi-node RAC. Works well up to\n~50M vectors on single node (\u226424 ECPUs). At 100M+ on multi-node\n(\u226564 ECPUs), requires hash-partitioned vector table with LOCAL\nHNSW index for <50ms P95. See FF-202603-008.\n"
},
{
"deployment": "ADB-S Serverless",
"version": "26ai",
"status": "UNTESTED",
"notes": "Check if distributed HNSW is added in 26ai. Expected to remain node-local."
},
{
"deployment": "ADB-S Elastic Pool",
"version": "23ai",
"status": "GA_CAVEAT",
"notes": "Same node-local limitation as ADB-S Serverless."
},
{
"deployment": "ADB on Dedicated Exadata",
"version": "23ai",
"status": "GA_CAVEAT",
"notes": "Same limitation. Dedicated infra doesn't change HNSW locality."
},
{
"deployment": "Exadata Cloud Service",
"version": "23ai",
"status": "GA_CAVEAT",
"notes": "RAC with HNSW has same node-local constraint. Partitioning workaround applies."
},
{
"deployment": "Base DB Service (EE)",
"version": "23ai",
"status": "NOT_AVAIL",
"notes": "AI Vector Search requires 23ai. Available in EE but HNSW performance limited without Exadata storage."
}
]
},
{
"feature": "AI Vector Search (IVF)",
"category": "developer",
"compatibility": [
{
"deployment": "ADB-S Serverless",
"version": "23ai",
"status": "GA",
"notes": "IVF (Inverted File) indexes ARE distributed across RAC nodes.\nWorks at 100M+ scale without partitioning. However, IVF has\nlower recall than HNSW at same latency budget. Trade-off:\nIVF for scale without redesign, HNSW+partitioning for best recall.\n"
},
{
"deployment": "ADB-S Serverless",
"version": "26ai",
"status": "UNTESTED",
"notes": ""
},
{
"deployment": "ADB-S Elastic Pool",
"version": "23ai",
"status": "GA",
"notes": "Same as ADB-S Serverless."
},
{
"deployment": "ADB on Dedicated Exadata",
"version": "23ai",
"status": "GA",
"notes": ""
},
{
"deployment": "Exadata Cloud Service",
"version": "23ai",
"status": "GA",
"notes": "IVF distributed across RAC nodes. Exadata storage accelerates scans."
},
{
"deployment": "Base DB Service (EE)",
"version": "23ai",
"status": "NOT_AVAIL",
"notes": "AI Vector Search requires 23ai. Available in EE but performance limited without Exadata."
}
]
}
]

View File

@@ -0,0 +1,46 @@
{
"query": "ADB-S vs AWS Aurora / Azure SQL",
"aws_database_mappings": [],
"azure_database_mappings": [
{
"oci": "ADB-S",
"azure": "Azure SQL Managed Instance / Azure Database for PostgreSQL",
"oci_advantage": "ADB-S runs actual Oracle Database. Azure SQL MI is SQL Server only.\nNo native Oracle database service on Azure.\nOracle on Azure VMs loses Exadata performance and autonomous operations.\n",
"azure_advantage": "Native SQL Server support if migrating from SQL Server."
},
{
"oci": "ExaCS",
"azure": "Oracle Database@Azure (ExaCS in Azure datacenters)",
"notes": "Oracle Database@Azure is ExaCS running in Azure datacenters with\ndirect connectivity to Azure services. Available in select regions.\nThis is a partnership offering, not a competitive comparison.\n"
}
],
"common_objections": [
{
"id": "OBJ-001",
"category": "market",
"objection": "OCI is a niche cloud \u2014 AWS/Azure are the leaders",
"response": "OCI is the #4 cloud globally and growing fastest in database PaaS.\nFor Oracle database workloads specifically, OCI is the leader:\n- Only cloud with Exadata hardware\n- Only cloud with Autonomous Database\n- Best Oracle license portability\nThe question isn't \"best cloud overall\" but \"best cloud for this workload.\"\n",
"evidence": "Gartner, IDC reports on cloud database market"
},
{
"id": "OBJ-002",
"category": "risk",
"objection": "What if Oracle EOLs or changes OCI pricing?",
"response": "OCI pricing has only decreased since launch. Oracle's cloud investment\nis $50B+ in CapEx. OCI is Oracle's strategic platform \u2014 not a side project.\nContractual pricing protection exists via Annual Flex and Universal Credits.\n",
"mitigation": "Use annual flex contracts with pricing guarantees"
},
{
"id": "OBJ-003",
"category": "skills",
"objection": "Our team has no OCI experience",
"response": "ADB-S reduces DBA workload by 80% (no patching, tuning, scaling).\nOCI console follows familiar cloud patterns. Terraform provider is mature.\nOracle provides free training and certification. Typical ramp-up is 2-4 weeks.\n",
"mitigation": "Include training budget in migration plan"
},
{
"id": "OBJ-004",
"category": "features",
"objection": "OCI doesn't have as many services as AWS",
"response": "True for breadth (AWS has 200+ services). For database and enterprise\nworkloads, OCI feature parity is strong. Key services are GA:\n- Compute, networking, storage, Kubernetes, serverless\n- Monitoring, logging, IAM, security\n- Queue, Streaming, API Gateway\nWhat matters is whether OCI has what *you* need, not a raw count.\n"
}
]
}

View File

@@ -0,0 +1,33 @@
[
{
"id": "FF-202604-001",
"date": "2026-04-12",
"contributor": {
"name": "Test SA",
"team": "Validation",
"date": "2026-04-12",
"confidence": "observed",
"client": "Test Client",
"context": "CLI validation"
},
"reported_by": "Test SA",
"product": "OCI Queue",
"version": "GA",
"severity": "LOW",
"category": "gotcha",
"summary": "Queue message visibility timeout resets on failed processing \u2014 must handle idempotently",
"detail": "When a consumer fails to process a message within the visibility timeout, the message becomes visible again. If the consumer partially processed it, you get duplicate processing.",
"workaround": "Implement idempotent consumers. Use message deduplication ID.",
"oracle_sr": "",
"status": "open",
"resolved_date": null,
"resolution": null,
"affects_matrix": null,
"tags": [
"queue",
"messaging",
"idempotency"
],
"confirmations": []
}
]

View File

@@ -0,0 +1,5 @@
WARNING: Unknown tag 'queue'. Not in taxonomy.
WARNING: Unknown tag 'messaging'. Did you mean 'sizing'?
WARNING: Unknown tag 'idempotency'. Did you mean 'latency'?
Added: FF-202604-001 [LOW] Queue message visibility timeout resets on failed processing — must handle idempotently

View File

@@ -0,0 +1,174 @@
well_architected_scorecard:
overall_status: GAPS_IDENTIFIED
generated_date: '2026-04-12T21:26:00.300204'
architecture_name: examples/meli-kvs-wa-architecture.yaml
customer: Unknown
summary:
total_checks: 23
total_passed: 18
total_gaps: 5
high_severity_gaps: 2
medium_severity_gaps: 1
low_severity_gaps: 2
pillars:
security_compliance:
status: GAPS_IDENTIFIED
checks_passed: 12
checks_total: 15
categories:
identity_access:
passed: 3
total: 4
gaps:
- check_id: SEC-IAM-003
area: Identity & Access
finding: no mention of admin account restrictions
severity: HIGH
recommendation: separate admin groups defined for operations
wa_reference: https://docs.oracle.com/en/solutions/oci-best-practices/effective-strategies-security-and-compliance1.html
resource_isolation:
passed: 3
total: 3
gaps: []
database_security:
passed: 0
total: 0
gaps: []
data_protection:
passed: 1
total: 2
gaps:
- check_id: SEC-DAT-001
area: Data Protection
finding: any storage service without encryption at rest
severity: HIGH
recommendation: encryption at rest specified for all storage services
wa_reference: https://docs.oracle.com/en/solutions/oci-best-practices/effective-strategies-security-and-compliance1.html
network_security:
passed: 3
total: 3
gaps: []
monitoring_audit:
passed: 2
total: 3
gaps:
- check_id: SEC-MON-003
area: Monitoring & Audit
finding: no VCN Flow Logs configured
severity: MEDIUM
recommendation: VCN Flow Logs enabled for critical subnets
wa_reference: https://docs.oracle.com/en/solutions/oci-best-practices/effective-strategies-security-and-compliance1.html
reliability_resilience:
status: PASS_WITH_RECOMMENDATIONS
checks_passed: 0
checks_total: 1
categories:
scalability:
passed: 0
total: 1
gaps:
- check_id: REL-SCL-002
area: Scalability
finding: no service limit review planned
severity: LOW
recommendation: service limit review mentioned in deployment plan
wa_reference: https://docs.oracle.com/en/solutions/oci-best-practices/reliable-and-resilient-cloud-topology-practices1.html
fault_tolerant_networking:
passed: 0
total: 0
gaps: []
data_backup:
passed: 0
total: 0
gaps: []
data_replication:
passed: 0
total: 0
gaps: []
disaster_recovery:
passed: 0
total: 0
gaps: []
performance_cost:
status: PASS
checks_passed: 2
checks_total: 2
categories:
compute_sizing:
passed: 0
total: 0
gaps: []
storage_strategy:
passed: 0
total: 0
gaps: []
network_tuning:
passed: 0
total: 0
gaps: []
cost_management:
passed: 2
total: 2
gaps: []
operational_efficiency:
status: PASS_WITH_RECOMMENDATIONS
checks_passed: 4
checks_total: 5
categories:
deployment_strategy:
passed: 1
total: 1
gaps: []
workload_monitoring:
passed: 2
total: 2
gaps: []
os_management:
passed: 0
total: 0
gaps: []
operations_support:
passed: 1
total: 2
gaps:
- check_id: OPS-SUP-001
area: Operations Support
finding: no support plan consideration
severity: LOW
recommendation: Oracle support plan level specified and matches criticality
wa_reference: https://docs.oracle.com/en/solutions/oci-best-practices/best-practices-operating-cloud-deployments-efficiency.html
distributed_cloud:
status: NOT_APPLICABLE
checks_passed: 0
checks_total: 0
categories: {}
action_items:
high_priority:
- check_id: SEC-IAM-003
pillar: Identity & Access
finding: no mention of admin account restrictions
recommendation: separate admin groups defined for operations
- check_id: SEC-DAT-001
pillar: Data Protection
finding: any storage service without encryption at rest
recommendation: encryption at rest specified for all storage services
medium_priority:
- check_id: SEC-MON-003
pillar: Monitoring & Audit
finding: no VCN Flow Logs configured
recommendation: VCN Flow Logs enabled for critical subnets
low_priority:
- check_id: REL-SCL-002
pillar: Scalability
finding: no service limit review planned
recommendation: service limit review mentioned in deployment plan
- check_id: OPS-SUP-001
pillar: Operations Support
finding: no support plan consideration
recommendation: Oracle support plan level specified and matches criticality
references:
framework: https://docs.oracle.com/en/solutions/oci-best-practices/index.html
security: https://docs.oracle.com/en/solutions/oci-best-practices/effective-strategies-security-and-compliance1.html
reliability: https://docs.oracle.com/en/solutions/oci-best-practices/reliable-and-resilient-cloud-topology-practices1.html
operations: https://docs.oracle.com/en/solutions/oci-best-practices/best-practices-operating-cloud-deployments-efficiency.html
distributed: https://docs.oracle.com/en/solutions/oci-best-practices/effective-strategies-distributed-cloud-implementation1.html

View File

@@ -0,0 +1,241 @@
well_architected_scorecard:
overall_status: GAPS_IDENTIFIED
generated_date: '2026-04-12T22:40:14.045613'
architecture_name: examples/meli-kvs-wa-architecture.yaml
customer: Mercado Libre (MELI)
summary:
total_checks: 49
total_passed: 39
total_gaps: 10
high_severity_gaps: 2
medium_severity_gaps: 5
low_severity_gaps: 3
pillars:
security_compliance:
status: GAPS_IDENTIFIED
checks_passed: 21
checks_total: 26
categories:
identity_access:
passed: 5
total: 6
gaps:
- check_id: SEC-IAM-003
area: Identity & Access
finding: no mention of admin account restrictions
severity: HIGH
recommendation: separate admin groups defined for operations
wa_reference: https://docs.oracle.com/en/solutions/oci-best-practices/effective-strategies-security-and-compliance1.html
resource_isolation:
passed: 4
total: 4
gaps: []
database_security:
passed: 4
total: 6
gaps:
- check_id: SEC-DB-004
area: Database Security
finding: Data Safe not included in architecture
severity: MEDIUM
recommendation: Data Safe configured for database security assessment
wa_reference: https://docs.oracle.com/en/solutions/oci-best-practices/effective-strategies-security-and-compliance1.html
- check_id: SEC-DB-006
area: Database Security
finding: no mention of DELETE permission restrictions
severity: MEDIUM
recommendation: explicit restriction on DELETE permissions documented
wa_reference: https://docs.oracle.com/en/solutions/oci-best-practices/effective-strategies-security-and-compliance1.html
data_protection:
passed: 1
total: 2
gaps:
- check_id: SEC-DAT-001
area: Data Protection
finding: any storage service without encryption at rest
severity: HIGH
recommendation: encryption at rest specified for all storage services
wa_reference: https://docs.oracle.com/en/solutions/oci-best-practices/effective-strategies-security-and-compliance1.html
network_security:
passed: 4
total: 4
gaps: []
monitoring_audit:
passed: 3
total: 4
gaps:
- check_id: SEC-MON-003
area: Monitoring & Audit
finding: no VCN Flow Logs configured
severity: MEDIUM
recommendation: VCN Flow Logs enabled for critical subnets
wa_reference: https://docs.oracle.com/en/solutions/oci-best-practices/effective-strategies-security-and-compliance1.html
reliability_resilience:
status: PASS_WITH_RECOMMENDATIONS
checks_passed: 6
checks_total: 8
categories:
scalability:
passed: 1
total: 3
gaps:
- check_id: REL-SCL-002
area: Scalability
finding: no service limit review planned
severity: LOW
recommendation: service limit review mentioned in deployment plan
wa_reference: https://docs.oracle.com/en/solutions/oci-best-practices/reliable-and-resilient-cloud-topology-practices1.html
- check_id: REL-SCL-003
area: Scalability
finding: critical production workloads without capacity reservations
severity: MEDIUM
recommendation: capacity reservations specified for critical compute
wa_reference: https://docs.oracle.com/en/solutions/oci-best-practices/reliable-and-resilient-cloud-topology-practices1.html
fault_tolerant_networking:
passed: 0
total: 0
gaps: []
data_backup:
passed: 3
total: 3
gaps: []
data_replication:
passed: 2
total: 2
gaps: []
disaster_recovery:
passed: 0
total: 0
gaps: []
performance_cost:
status: PASS_WITH_RECOMMENDATIONS
checks_passed: 4
checks_total: 5
categories:
compute_sizing:
passed: 1
total: 1
gaps: []
storage_strategy:
passed: 0
total: 0
gaps: []
network_tuning:
passed: 0
total: 0
gaps: []
cost_management:
passed: 3
total: 4
gaps:
- check_id: PERF-CST-006
area: Cost Management
finding: non-prod environments running same shapes as production 24/7
severity: LOW
recommendation: non-prod environments use reduced shapes or have schedules
wa_reference: https://docs.oracle.com/en/solutions/oci-best-practices/index.html
operational_efficiency:
status: PASS_WITH_RECOMMENDATIONS
checks_passed: 8
checks_total: 10
categories:
deployment_strategy:
passed: 1
total: 2
gaps:
- check_id: OPS-DEP-004
area: Deployment Strategy
finding: different provisioning methods across environments
severity: MEDIUM
recommendation: same IaC templates used across environments with variable
overrides
wa_reference: https://docs.oracle.com/en/solutions/oci-best-practices/best-practices-operating-cloud-deployments-efficiency.html
workload_monitoring:
passed: 4
total: 4
gaps: []
os_management:
passed: 0
total: 0
gaps: []
operations_support:
passed: 3
total: 4
gaps:
- check_id: OPS-SUP-001
area: Operations Support
finding: no support plan consideration
severity: LOW
recommendation: Oracle support plan level specified and matches criticality
wa_reference: https://docs.oracle.com/en/solutions/oci-best-practices/best-practices-operating-cloud-deployments-efficiency.html
distributed_cloud:
status: PASS
checks_passed: 0
checks_total: 0
categories:
dc_deployment_strategy:
passed: 0
total: 0
gaps: []
dc_integration:
passed: 0
total: 0
gaps: []
dc_compliance:
passed: 0
total: 0
gaps: []
dc_operations:
passed: 0
total: 0
gaps: []
action_items:
high_priority:
- check_id: SEC-IAM-003
pillar: Identity & Access
finding: no mention of admin account restrictions
recommendation: separate admin groups defined for operations
- check_id: SEC-DAT-001
pillar: Data Protection
finding: any storage service without encryption at rest
recommendation: encryption at rest specified for all storage services
medium_priority:
- check_id: SEC-DB-004
pillar: Database Security
finding: Data Safe not included in architecture
recommendation: Data Safe configured for database security assessment
- check_id: SEC-DB-006
pillar: Database Security
finding: no mention of DELETE permission restrictions
recommendation: explicit restriction on DELETE permissions documented
- check_id: SEC-MON-003
pillar: Monitoring & Audit
finding: no VCN Flow Logs configured
recommendation: VCN Flow Logs enabled for critical subnets
- check_id: REL-SCL-003
pillar: Scalability
finding: critical production workloads without capacity reservations
recommendation: capacity reservations specified for critical compute
- check_id: OPS-DEP-004
pillar: Deployment Strategy
finding: different provisioning methods across environments
recommendation: same IaC templates used across environments with variable overrides
low_priority:
- check_id: REL-SCL-002
pillar: Scalability
finding: no service limit review planned
recommendation: service limit review mentioned in deployment plan
- check_id: PERF-CST-006
pillar: Cost Management
finding: non-prod environments running same shapes as production 24/7
recommendation: non-prod environments use reduced shapes or have schedules
- check_id: OPS-SUP-001
pillar: Operations Support
finding: no support plan consideration
recommendation: Oracle support plan level specified and matches criticality
references:
framework: https://docs.oracle.com/en/solutions/oci-best-practices/index.html
security: https://docs.oracle.com/en/solutions/oci-best-practices/effective-strategies-security-and-compliance1.html
reliability: https://docs.oracle.com/en/solutions/oci-best-practices/reliable-and-resilient-cloud-topology-practices1.html
operations: https://docs.oracle.com/en/solutions/oci-best-practices/best-practices-operating-cloud-deployments-efficiency.html
distributed: https://docs.oracle.com/en/solutions/oci-best-practices/effective-strategies-distributed-cloud-implementation1.html

View File

@@ -0,0 +1,269 @@
%PDF-1.4
%“Œ‹ž ReportLab Generated PDF document (opensource)
1 0 obj
<<
/F1 2 0 R /F2 3 0 R /F3 4 0 R /F4 8 0 R /F5 10 0 R /F6 14 0 R
>>
endobj
2 0 obj
<<
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
>>
endobj
3 0 obj
<<
/BaseFont /Helvetica-Oblique /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
>>
endobj
4 0 obj
<<
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font
>>
endobj
5 0 obj
<<
/Contents 21 0 R /MediaBox [ 0 0 612 792 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
6 0 obj
<<
/Contents 22 0 R /MediaBox [ 0 0 612 792 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
7 0 obj
<<
/Contents 23 0 R /MediaBox [ 0 0 612 792 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
8 0 obj
<<
/BaseFont /ZapfDingbats /Name /F4 /Subtype /Type1 /Type /Font
>>
endobj
9 0 obj
<<
/Contents 24 0 R /MediaBox [ 0 0 612 792 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
10 0 obj
<<
/BaseFont /Helvetica-BoldOblique /Encoding /WinAnsiEncoding /Name /F5 /Subtype /Type1 /Type /Font
>>
endobj
11 0 obj
<<
/Contents 25 0 R /MediaBox [ 0 0 612 792 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
12 0 obj
<<
/Contents 26 0 R /MediaBox [ 0 0 612 792 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
13 0 obj
<<
/Contents 27 0 R /MediaBox [ 0 0 612 792 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
14 0 obj
<<
/BaseFont /Symbol /Name /F6 /Subtype /Type1 /Type /Font
>>
endobj
15 0 obj
<<
/Contents 28 0 R /MediaBox [ 0 0 612 792 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
16 0 obj
<<
/Contents 29 0 R /MediaBox [ 0 0 612 792 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
17 0 obj
<<
/Contents 30 0 R /MediaBox [ 0 0 612 792 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
18 0 obj
<<
/PageMode /UseNone /Pages 20 0 R /Type /Catalog
>>
endobj
19 0 obj
<<
/Author (Carlos Mendoza) /CreationDate (D:20260413001815-03'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260413001815-03'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (OCI Architecture Proposal) /Title (PharmaCorp Mexico \204 Oracle Database Migration to OCI) /Trapped /False
>>
endobj
20 0 obj
<<
/Count 10 /Kids [ 5 0 R 6 0 R 7 0 R 9 0 R 11 0 R 12 0 R 13 0 R 15 0 R 16 0 R 17 0 R ] /Type /Pages
>>
endobj
21 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 570
>>
stream
Gatn!9lJN8&;KZL(%6/,_8K]#EeJ:l.T*U0*&qmlM74Fg`5,#;(\-N'-VMuB'qu>HjKV4HH(UKZ7nS[mHdr.89>#_o_$.t%\7,g,HX)fW[tO9<E,ED#actapaeTfkD:1)r)$QEp+?8`5&n^]6dZ"R.1qa[p-J$d@1'&Osb-&O&:3I(Me-5Ck?Eidpc'6_P:gf0E[K_pG$0@l]I]O[PPVg]1EJMe5E.\V&`qO*!j*H'/F(\^iW@HN2?md%&U&9f=/.*ATcD%D6/2*=>ku"nE2^<'Ec(4/Jd!5orY,R7fk6%0Ep<HEmmtkVC_r+$D_Y<GK&_](*2n3jFV\,I_i6I&ZHc5`2`pfXj6M&j)W]TmS>d+.jNU&$5)@Pr2@L9;]=tW2!h!?W/D1*7?jmJV\5>aVpd,qeAbBT/G3LD.'U,>9<iX]%sWY3[Q.[E8:Y(Ni[LN>Q106VHIC2Ur;+\Y)FmB7)D4Pp,f?OA/&i;!0?(V#BM]D_L1l*Cp*jK+1RT<`r3PX7Tm-oq;lLg(g%5LRLHgAeDPM.8o^Xe0B6p:F_Q.EqFpJia!%ndARjp0@~>endstream
endobj
22 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2000
>>
stream
Gau0D>Beg[%"?O+^r(JYe(L`lh08RUHe5ST(OJdsnj6!V_aY7R8kSAu5EN0]-]RL?dn\XgV$Pu]n.>Xf^rAUWr/<F^_[1]O,sWkPAjBVEKuos+1>.$,Z\$PI+po(p>`[f1s,Y%ifcGjF]c9-N!mcW14>/O0.?+"el9_U)ZM^OSbB5oc\R;t$"MP*VC*HsaC9@`]&s?+*KJFBLhD(;#,H2#0kMJ]ZpL3V%-6KY,FW'1AJ\NOU,kIEpG[:]BY)-8C*JHBqLhm_"kY5_sZo=<&]&RHMNBcRu^H+b-a)\*d1pk->.5p?S2g@ZG'npFm%gjU\TJlJp"KjF5Xb:U[?u&GUVUIsP#SmJ^"8%]5_tIG&ZGD4Ye#@tg[85;^1cY<Vj15ka*6*,e0su7<o7^1/lE"_M&GWPb/@gndOC8V_F\%#/k7Q/-HNobn2[#%b&>FnQHjprVUn/N6d+uc4PAXl'c!OlgaFYpCnIchO:b5@%,ckHR<oVQpi8ehcf7XW<D[5<Tb97k_h!Tg=naEDQ4;3&0a`jTciN!K&,C*aU""O^)=aVUfH)H2Ua[j]HWL.Z55.<TgT.++'5qL3ZKO9NMScd.L87d0UK#fGK*b81=:="MJ<J$aK+I8#nR?n\ZMg=n(.!Tb(LIQJE#"8'=gb1`8Nr@p<@hSkgFfZmD^f-APgr-#[7)P!#(nFDY@l]]0_h0cKO_N(Ms7dK>e5i?_mGRj3_X&?AhE6ULC56akH*Ma@]0FfjY(_[+;q*_>pkn"8+r)Yi0q,)/kLq%@M<\uHX\j^\,qSVT@V)C_)\&QMQ&38`NN[6,jO_RtT<(f6##7<oUtZq3igP02R_s2G/#@6H.u`ao+>.roECBt&PPB#S-/+a!,sec0o^Q@hq7=SnNnTp9aUf@sl]3ulmlO[=r-!Q?<9j/`Q.jl.A0*BKL#uAqKS$OW88<hbKUF5uQ9q+aEdJ5^TN>Nb6TdaO=uN'aZ'&[T>YJ4A@N-45ZMR&]Qdf[7QI5b*$jrl?'G\Xid?_*`;(W]^0uf?VXk3]Q:Mf2FY;&`<M1^SP.7B7M)SGo'ZT8[5Ahm0SL4YoX<f!@)-cF=i?):81'/o4?19^+fX`(6-6S5>Ze9@kK93IW92<R2$'ke/m[>@!;eKCqs_,itK[Js;c=1i!7@K:Kr^rBudX!n3bR)&pJ$B+LtTm)QcKM,@D&nY$m3=7"MkIT%\?Xl0uVk^PZpT#p/oBJoIH_'Oo_/RlV&0m5e3Q2nrUKGh%$6c!8MpeQRD(&2agb4D$F)YmFT(l9/dT".ZHQ/E6p(,$=bkK6L8S@L`04<=uXHtM,@pjF*1Q6Ra@]Jk'%5h'ETC;%\eG!>;(=]+_:+7Oc9`b_,lt/`?PXskhaKPp4r&97;Q,LLB?b^VN=0<G?0QB)G4E5gW@e.`?_a97+i&2!#m[Zt@7PfucilW"llCIlcZFrFVNk'HM)"WUBC<%bN;:t3I8:ieo-@8,-35OP_.WbY'-1l`Zq;;q;hb"XsR=ZELZM;-dn;-9G;D3i(VG2e#RIJ]72Ghsn+Vh;@5OrnP\+#+aL:\so%R>h;1#>r#(i^O9AfpRBinHbtmk:7Sq@5]KfQ+V$E]_[FEZ#"N\]?a)]=V>b9^pjBcaq%uSS;$;VI4@q-U*eHg#si(!t4k;6a\8i7^\IY.sRE7^P`HFgd]6mSdG-SHJ;Ts25Mp3c/&W4SZ>gaD'RD>PAJ@<lb9Wb[)ZVr5W^u4@_ZS/%D+COMqLaOYjsj0Q2b0Li=.]&53uZF09un%[(VmW%8H](KNC\Q@'si\"kn_X]M4b"6BB1!\C$5N1RW,52bRKL@S$+-gVo(W/@gKORo@iKUDHij.#;H0#:%PJQTH]e+"S,jj6h*<(FsYEM]V5<5K/KZQ[N61hm]6QIAn)^1,F--c(*?[DL1RCMS7`lI/H:UDqFp;RbP!UX#8V6d<:MZ6kd_%N6Q.9Q4dO\5^utOG+TbD=q-SUXo!WiR+7!LDrGF8IJLM,m[=-&rrU/\L?&~>endstream
endobj
23 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2270
>>
stream
Gau0D8U&oI&AJ$CbY`()QJa*iY8>/^dO)5/WD*o65U7VKi>)F#U]1,8J;YhrQK)"kGn+O"1RRuMqd9U\raY[%,R8S)J=eJ30FnpL@"B!,iXMD2:-P:0PM#Q+*]W"%#T5hi2\0dY:HZ-K.3K%,&k7sM(rl8$KDA*>/gbF6-Yeo,JKK3e!1\SE8JHc/RTMNM[3bq*RUd.:Tc?PR)m441>,hqdMD$_6?bkZ>=StGLL,(<%-IG*HZn,65'nqc4)i-IPG8e),_:3&F#ec)^$[LccSNB"aC&G6>s48E4l8u]rJ/::eitPi.n/q2=A'QnPCn=X!B&L4+1_=nmJa"F((FCcfPiNN2esPBg6,<[eAGC,=HR?:2@J]f:8'U+YB3cG#<3hWU,c4TDY*CON=_0qgSUBnmB\K(Q$,PQ/""@/N\K(4ba!Uob[D$>4bJXd@.Dcus>uVUsHLABXFKVj`AoDKk3>5T!Mh@<#rCI*>-uKbT>6;5]/4,C"$_rc!1')`d28ei(SW-nZ=-ZV;aKjafXN[_=-IQ_bXe"_hI.Y&Xi[n1t6-]k^Ntert[k\O6m\JM9Y>(F+KBj72(o1Vhco'_XcE;ljC'L_:_96$*6>-g1E^gi;U[Bu?Yqd_2WNn!RMi9)nfr79!G[_.DLW07@SVtkIPpj!>=l=(,2@mFl[a#9r#f\?n'm^?-h[630Jtb)P%^#7?Aq8*Z&aGHR@2p=;l`7,Bk1KG=Sec`U"Ks9G?Pb63[8D(q9K4=h.NZTLQ=YmEhYpKU0HX1"^d9Hg0l?K6/n*X"ILEg"V'6Ut#>\suW!s<urEN.X\8e?t[>Ei*XQJ2<M)?%dS:BLqF%!E/O'ggn/X.qoQ1/dH1FD:"qsajf#]j=h26Sf>5J$r5G`aWKP68#Rj]GUG-NSoTGGY.h$#[@R#7p7;UrpEjdAsN#eoVN/n^#[.g(qE\aTb9k.sVIk$KV7j#o=G)C`io@N]p]#/)7>N]H-if9"!1umS?b*Xc&D[#*MGThVp^(50PWm1BgXnq9(eRM.M%de`glE':gprS(4`&3sSV.C0OOkJkojV6%$Lh`Q".9ZJWX05;4PXW[uLEr<nQg8H3/c/Rlg:MSKZs5#KH4Z1T:%L+g(Q)Y"ic)?'i,.$.?aCQu1KP:4<*T@\dJI)*PAY,qa6"!QCB"[\`@PmFa3USGuc:h[l+N9r6JV^P"/O\Rt2"t:_3a-21fo6>d.D'AN_Z5-.A2juhCqTBdL>Mk\22;.OFbj&/2Tfk@kabrP,W\6U7*ouHW,Z8-f%rrUR3$PgtB#tm:]$$9Yc\ir7SiT=Gd+HkZaBTs6&ef<qUH%i7C$"(I/G,D061@VGUS-<.HgPuGrP-=6J=G7Niq9d2*Ye*_eTrn`fg5(Ncjqsl3j9^FR`-=S3W=s%S!I@9:Ee>IFUkYY%^@F2??WTXlaB/Jr]mp='XK?t&_Ps_(!Os0Np!iIYaOi+s/>Al:E[NkB4ekBIE8k"OHoTG98-+/C-Kq]XiS)Z-4;E/`,F:b+K76H:&0hR=$+oX?l-Q)Q/W**RpMYg0Yf3,5l4t93#.ji1l1%0RIMRU@sbV6@*eiQ92XW'2nNsFHW&H*91=%MUeWc@WC&Y2,l"&&67BWcOE9sI,#27s@h1YlkZ:Ys"(HuH8aQ%QkOF/EqE.A"b\.WG@AC<Gm=p5G[J54)5*ZF[D=!gSgkc<+f+GIU;gdupqT9j9qR(UQ0ZTU1#>tk=$jPrG^83--/ZT5j[kf-1rHM\-EijSoO\,##():bj4#Wj3WA,_Z(3Lf.Y%3BW1]Ttr'jUi^GIPEd=^e=paLV"I`PigB#V!Dhgp;HN.%6@X(r:T7g@!Ta4*@NO>3]UkGTsB<m647cmotVnG8J5aSaBR2ok*WF.$3cM8lZZ!5n>F#j#dg(B,&\Q5PA"/??D9K)-(8ea$%k)TA\Q'&nh4"7Uho]?"Vk#Y,J+Uo'&O3nt4V$*fek3Y3]99OSC)!-$V@cW)%?`!u0s]0HJ3DH#k8O)C@3=+YAnhjiZD]Z,@WW&OIdp/Zn-VSK#6ID3U^R_TC@U-oFQ\qY3(iSk'17`SaPuN`%Up/UP3-$u[HLZ,b^P_6e$V`s8-"ipln]'9Anj\lUbAk(U7>=NmMQ[-ZTY"s,c8\C4O(`TuhM?GtX(#B/t-p#4I!m<FIH"H5)bC8]iSnb<QCrr.Ye<]3W+[q(NULiml'Ph+X''mHm[q>.LpkP"c-h(%s<AsM6LeUB.jlpYgF/E0=3k',g6-]RY:)@N"CcA)(#ZgdAnN:0R#jBp)$k@4~>endstream
endobj
24 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1936
>>
stream
Gau0D?!#c?&:N_CbgW/j?!L$g^Wu7?8q>@-7nU((+*^X&-#p2l<48Luq]/7J#`q"tlTI8H[URM:RCOPJ6,:GM1#GP4n6lao:C%L=iu&Ej0GpG"nbD%_JJ1MU(K59daF&RUrC#W@oROgW5lj0%cjq6(hiGue#,?g9\O]q_SR?$Q@@g8)"qDk'%"*$@'(J=cF$5)U+;ofD;@^D!JubC`8[X3ZnM<o#)]4'[nQTjJEt7`20\Db:,`>ed'h+DYCh&>9]5cmUK%MAhJC-dI7RuM69fS_&@cK2Ps"to;H]CT6d)_&[:jamGm>-E.-]U)kmOqS/!Hi+\1#Xo(VO8%+&@rcYP2kb\.2PZ1W'U=[`'Yaf^-aGB#9gDbF$T6S"pc,n+4L#eqKG'Hpa",4l2gm76!Eib&dkd1,4C22G_4rnOs"'UdI\RNWJ*TkR?o/a4M9r9^U+f=XcX3Z*5ZN*8DLnP%98j<o`/\,T51,g`Kc,R[).'O._QKLi"_$rR]@l:&k6-COOonBi++[S#-!c>-nE7e;8N_TUf.:MM.mi7R>ge;[MQ5gi:t1qGVO%jeJn1:0LbjP?K-&QQ<BZLV<M>@pkk,r3mB.A.@J),-b&bHUI;"k+ptJN#rfOpRV@OWMI/<,L(GrDBAc?*Q=r5k2fG5;b-4lW2TLsI^)o6N`jAU8`COJS]3$b!.tqfjQ,411fK+f/+sgXj(7Qal_al_M+%1[8=#4^d3cgq,N^^gGD%4b0fISn%^!Njc6Fan=3TIC:T!%uI"5*)<;ARpR4&\C8i'bt.Cl_#j-tF[f]:&,u&MBKTYhbCRRo+oG9j_IRptVf`-8`7\/\1W3L'tUsBe+]]-@<Xh=(tOpQDqG5XpNoc)9.-O1\%rb55rZb7dt:g;nk,J]P^;I=#*:5ah!u9<4A(8&6R#"[jPDNDER`V@h!Cfg:\s9rQUjNolM[iWNA!0F8MumM8u/UhG_9dS24*\h-%-Cm)7Eq[KOs2PL[rf$97gl[nAe6ht9G<ZJ"_dbIs?l(J+e*8h(NGHV2rpNp)fZq>YKt'E3F["^Pm:hqW%IGb_ZEURq+>qddWnI)Z*[@U@^>$6R;jo,`7c7[l-dN"P&a)Aq.>DqASaQTE]e]j(Me3WeoOJ$=-t+$RFR.6d?1MA/5ADO5ph/T=3(WKl#A=u'V;09Y-j6dI;1SI/O9"T.<3P8IH/`=l\tjkFJ%PNSNMJp@8u%n9XXChp6J4#)F8YED=Xbl>VdBj(NeS%3eq`KI"39k=?G#1FL0B$9=faF(G(>)]aga2e\aaFHK2#Ipf,^qne8?bb$_,\jtLVZqL*khV=SKWCk(39sr(K>C5TKeb)M=%K\0mpDReF^2Uh-$V&-q@2X!DVhb:oV/Q_Qm5fa!ITco4Q=HP\]PLp#tnOI7<+YD=laFO=JH5Z/l>oEoMOrSW)JC!dmkXSALiFS.4hf/$0CthQZt\B_/BkI))"Vo\PR?E,S0%UKEFjn'/?Uh42jAJF[G1_;;FlfgZlrK2#*.)jKMn3>6/)k/hN\#f;EdDcqlL>Ok6GR9Ng)"d4"2kf[p+Z+iikM!;Br3NjYu#K"+GZQ_RJUFXCq2fIWH/@%0A#C=Z/!$kNB?bsQp5-)NuQ1H=?)FX2l3lQ?;.OKbf6)4jaSU(XI;'o8JT=X%cgYu03]D2khB.TmpfI4TA"9uhKtN2p'T*gUD&iYAUIAS$.g([3Ta4LcB'S..tJd64:Em^977,kAQ8Gl3@-(V!*-U.dG=nMpYkkW=#""ZPV./&d]G^ni[?HI<k96.@?o*fn.I2TlOHXWY9T',Flp,"5@i)Pbh%kqlpFP.o=&btcb1Sj@reV;B1p^?mAbUZ1VIc+2A-##A\%".3Zj^3'O83gDXVec-anR5*Oi:Q`q#gp#&MSf.d'WYh:kj#\JhhSH%i&4^1uK#pmCBQ]mQ<B\Y@*;g1A-GD_~>endstream
endobj
25 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2349
>>
stream
Gau0F=``=U&:XAWfS="WD%q^)n%QoPijKN@Nhn)iN*ftMZC18[GW9SjI<P^TU25[L*-=<"@$'%>p:sui!u$0Or'*jU:1j"`4Ti]4[K'nY2U"A#A9RV4aRFT+$9/mXZQ4cBoG`SOo-4b&O"tZjn/N6BE#`5f&ss^tjF![;(iD^bYUtV82Ae>^T'LoXPaLJsECU79"%a,iLJg+G\eddb:@hp$(XZ_4k!-]K/'NGhEr@f<0g)phmPN6*nN=so=<tR)7UQG7M$O0H"YNF-b6:II33>.U&Q/,?jc9be"3[pY%GWmi-'Yot^tBn<B1ChR?61bX3!!o;[s-aD)Q#[VRc'Te.87ig9L1?DOR8`p$pRG[#p^1[Rbk`eO>=qrV+AXjlle"P/4IOoWMi4Jhpp*mh^=rMT]8`6^u4qfLWSVf'YV`-:K$L>4k.1*=Y!'+maqOieIG7uB.H"k#gm))"U?XT(@`1Q/:L(C\u+YSD&q5P/c:jrReL)l]l*B&F`_g);/.7;"OcmekP(O/^e@ZMl5s/CdV:YmUX3*'<qQX!iUI^]T>poNg"f]G4RgbW?:=Uu1/C:QkLinq[RJU&-+$J>Z@^\(#b1BYCBc\)#1l)`_jR8bXO0/E.e7j*p*Di83W;uJ79#*f^\MT![If!:4GqT:r5mRpI&]V470QqSn8GhqgdBoBn`JYb1+IV^-R[@T9ZL3Z3;YI]Z8'$6QtOf/%Rh,W!<Ek4%SrTH$;jh-C9fJ##70EASp_FmCD.J*\>QLYG7NrSn@(jECRA-HS)=2I2oekE,o_fqFgBa^oRId#%R0(r:b)+L*CQ+*oJhZO2)pCNkTA$u^uDAMhEHuB>N<:!Nb9a'$D/u9m>D61UTR6-rF(g):dns'7j^4b!cBpi'MC1A^2DU9PgNACkQ@C?_`Yo/C,#=g8OQ'VE&QDJGPq2XO)e#2&uhrABLP?]>Gfc=\[H#AhGI(@T+"nD_.jL=&%.1NFq;ilp2H`!!gEP:BWBU?.M"M,OWHC'eMA-p7>4.3g*`Ma(Mf&sW8d+,^?+]6]%/E@\+uTJdM2[1_-\gq30!qY/g?*#Et56RObqmT!&IWI,2(g,cN=U3:%3e0c:SW_<lM8m`>R]aI>Hei!u.888=ed@qGtX*<'i(7n=FMrGqYJ9Q*-*J8L%Q!,tj1C:h(o/k+7naaRT[;#*@3THEi:DR-J\&mu'5jYt$'$Y<G8GR8t%m&+=,O'r#$$&3Yb>4ib&TiJ)JXjXFdm.92t5Lf#Xac_H7]W33b[2/UY3F>hQ+-`F>X(TTG<@9dS<_gH[CNeSY.dBI78c&VP'A3[#&3p_"gm.Fe$T>&$h5K7'[H_ehI)bN]c=pBHgm>F*-mLq&fYJu'_&(P!pB*:HAj5dDe%g+pF$cA5-+s%itC/n7Tgn(eN^GY:KN36M4SRW3Od"aA,e'`l]@fFG'c!C%n`69=n!FCbVp$gt.J?Y+c*hi^7OG0)Z05*i*D3<9V<S.8#kL8**gG4lX(u"uUHFN"D1`-$m?4XC@/?acZq!>YqRs&#heC$jGcVE=l0jMNTo]crBiYN.4g,]mHV6.=4W[AQ>2&X#cXJM,*`CKVC2V,d(m:Bcj)Q/a'er3M)Bm`GL)PGrf*0`>?eMQXX?Bc&k!C-'rKUheh6_<FC(53K\H%*BD,.LsKeSd4M(=o[jOm2;@F'q0`7iS4:_8,"Acj(Q6I$[`G+&KGIKAYeTDt"X>k-"PN$aWo]KM$0PHF4mjFaETO(/kJ3-%AGb@$d3g3ZFS[\6s+"oBfWMk\65GDiPiZFohfC?LA53=qL%V/<0LsD<f`)iVI$]Yn=R#2\]uU0*Bqk3r".A^INGho"-tul/)JAbqWC2W(h0PIQ\G#DS99/oWCo;C:5K;;tqEi65<u:o`dfIO"3bc>+Qkl^[9GME-=5\D_Ei6>G/kJ[PK[_>=/cKDXEY1Fg.V:$qg%$Q!jJR2YH.ee<B>Up#I'iT)FkS)gemIglll5:Y)"_Z>T<V]%Nu":Gf]GMSJ%dqPucgh/cYEG.VCjp36hLh.$pNe/22f<YBA@O[I1rX'2Zt=V`@md^*Q-\'J1(Xr@UKb[$3ZpA1fj`34R(;1E^Ro/NbAbHalS4]hV<1r`u7Ij%%j`_TA/UuMd@N33s[`cCVUQ\>\Y2--P,UgPs/,S$T.7Xs=Ul5kVI]9`,1R25t)QX%DZLK:gFb9@E&,se"fSj?Hp"\gPI'M;1)q8Tala#Ybhl\!`W:l>ZBRj8#;LYp0"XIDa>8u$<%l>!9j+ahM`L[S`5XhfCV7,LEF23oKk``YC^V=,9f/=.iiO@g6YRTp@*%:8>t)fYL4#Pt/D6S.30..0oW1d,dI%cQs&p6*;?Ii9b0>l~>endstream
endobj
26 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2147
>>
stream
Gau0E>BA7Q'RoMS3"KRJ5iPDAI-Y"*QJJj2Q8Uf59OEIJ[YD^1ZI@6O^IQ#W\N*4n_gp!gFDfuucG^J'rh9/&i<8(L#Y4>3:^4g!T\SN\quCBIK:`C7k7]pb?nm^('Hd1$%'KUo@.87LK>YNH>aU'%q"`Y]D@T9^^?-25DTU,^[_i.V(8oZ'*O(V=FZ`LpH35a!ar0?2-IB;L&8EBnM42;8r"Xq-CD_MUi>^%E\VE53k;N#CP5$XJaZ,3s\?X![8Dk02+<WL[d2G6!dFMDpAWEm\'_^Uk^M=AgCs-E1QuDeS;;to6]>5+LXh\j+mS?h>#"D^9_^>Sag>NZ`I2d;9-Q4U@W*l;cgd;Gu5)?hH&cnJ9mRQ_^A?Ci#\P;:s1kS(LR0j\*8ULr5EUQNA$2jB4Y2u4;klX&FE&fn][-:g`pI\sn&hiIXXJ&^2W5FA,qj,$To6h:27N7uRrJURb,OTl!M`p4l!1hF<K'[`u#7]731qF/@hEup\KY'/[""s+k*<V>f]/DkEIFWYhMtQ;"?.PbOq^go@H$QIaHS/sSbOJ!\T)sA!Fc[\`<Zg`J+eTl0gtCK2#a[#E)B:e!:6HG)fgb&%cgWEXY2@6g3pW/7JQG<H*H&>,k?6WThC+QG=^Wm<#D3r?IYklMS:%mFYYfq1i4amCW>oP[M(?]W<;=fuI(6rS!AAOsi7U,On!$@!2%-`.7`]EOYLh0c;"?"S-aQ[.>>$6$BQ6ST4s=2u#gB/i.VT3^&kt/kRHJcS+\0kY*F'i;:6ZGWHLaqQ+>V;E4A2Brc'K\n/EO#i06l%l2CjOX,*$:;n''I,R]$YoJdW10R>aQSb&->t1N$eb[V]n7@5T7t4:]E<OW6Y$2tPIDBT5RL;*nTs!Jrc,mn5[SL;i2a%6Yq6%gh)"E<7OO91Iodqb:iqCp;C9%/-cCWmn=&m%\r[:e\j;BH1U0E6FUR\]JuWa\?\>f\<mh=pqRU":Qu48qfI$-;RM[Kh4%[iqoKm.RL]=3]<_PTtfW-2'\*f!c19E[e&_p'Bl"ZiGpE+dPo\VMCa-?m'`Y.\VVFmF=Z!afdc<!dA4K$[!Gr;Xq<nZ(P\;ga[B[FXb+ph)NhN>hVAQF[\rlOW\D(*p-1hBj2_2hESJm/*U$P^NJKc/?!9M."^Nq4CsUYN=t?UB,kZPsmED"dc0g!?lX.PKE4PA+RR,-kG<sE.0\W?]d<W)6/gG$M;Tj,60_SfKC2MnDa1pMU(q:83qBTuaop]jnWr[aJOTc)+X=8U(h2-;S<.(aG]Vb6(Q.8hlVd`S3&FlTkGnnSnds*11ca@9uNE%h-Y>o7>]ZkS1Sqk\Y?])>g0=L',FT&;>T2ru^gi83+a>0=7I0W+,g3HLXgk#HHWY,n-Cd+WJ+4TM=L[@4c@J`c9r;Dr9Ch\X2a'=>*c9BfS$EbF<g/@=mlpY07=<:je\X>/sg=n8hrNCU'I[EQb;&7:8(3fKjLMrnIbFJn1(u?RFGgnpEe?05To(aa4YY',U25_QYL9m'_fKMFJ3dM`e>c#&?)ekEA-1,3Pl!M823;pM1\6!HNN)3P4?D[+]g=m>(a"Y;,oFX0b\+<L"L<3s=V<Kn7l,m"0*f1)LO0l>R[;8NPopUTAf%<Pcc&^)JIRWnlZo\4Ed[sgA0=sh`'X.;krcK0#=FPte.4KbIIT_k^=T5^>2>Jr<c2rp>jW?<-01K)&R^$^q2:"HRm#0?Q*5283<PGjCQV)p@$"'OGp-!\YFUL#j;coT<4h\@Rh1`Mlrd-!A#Yn@i"2j.O;0p6Eb%s!'_Rgb7f;(J?NHP$G_3:he6)If$YR<gtPe_td4_b&BLl]r^jE<-[D7PeVoj6VS3i09kb/gW$\JgAcQ6Y>$LLd8i17nQ`;\Y:UVo%"5(1RWno7F(qi,pK_[H/H2f3e5Te0tpPPT4gENQPPMFGemsPYZ$J[322rUj!tkESoJcC45HaBJ&3J]9OT.asW\0dc*2Lg$nsT6'Oreo4X%Br_*"rAndQ)AGbla"anMbI0<V<Aap--h+J,#/SafqB^$JY<B9beFf>uCmA"MC,-Lrb#C]i_0X]O%5l\c<3Kn453bm5Sq+'g.eJPL5!P?qlDO("QjnbVs1s:NJ<Ju"=DTsVOap&QP27mJpl&nO8LP,U-\/'R>~>endstream
endobj
27 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2272
>>
stream
Gb!#^h,E&f&:`lHfV_Ku.?5^(:ZieI'PM@kUkEO\^l*/";"7V(#Kk<in[Gf6`sK"BK%dhf&7m)g<r:X:p1HZV`ue4Wog=9(Qd@rD5U]mo!&6>E/jI2"jhZu[c#ImDUS(K)Zj=Cf:D>EV%OaFZ6suG@=>kh?=`2Uo?uiJJk=TT_AhTB_VI<?J"O/41Yq==!'<rNJB6!uTQrGIb#)1DChm,(L_`1BKPlDGHr#.3&_rVi:XuV5=RU\:r%HHYA9R2j1(,UbZT'j-M>2\Y`ZZ.j?d?(EVXD0bM<)TlsBYJRSe2&q6RQt0'/JlB<*1W=[:ni5QU[oU"70$;bG%8=#"K(-2bHoPB5Ep+!LK^R1VO3s8W0nr:BMg%%RlXZ]r^3\Qb2MIlHGnAT=*hfj?/*0h@U.GjhlXZ,>Bd[8*?u,F9)&">%If6oUie@lCUR)RQ4%R?+a$a'dW]IFH36AJpEG)lEFdO`'Hu@(nSk)]EQHU0`<Nn]+3!Clo)fJN(pc&[SkPdnUFUPN/pHPl'd%"C@[u)JK,HrD9t/m$=jbq"^iBW,F-]S[1lasFV]qRPHW/&!(Yt*O1<6VA%NF3B"AcFiK54c[(-q=OoC(fJ]RgOZa7h^`%R^!BY"AIaaV=-hfO1bI@)DkfMFe1W^!Yd1/Y#O1hSL'e&+ZdQSK:`cH["O"RA)5$9I1`Brs",O<9/"?0@*%YGPY%USDAWm1.@PeW0.Hh_L*5Hj+'SGF$#qU.D+E5AlW-qVEk/0nr(?m\%+&HUPr^B:A?tt-<ksed/>0OrJ@`H>?$o"obA5WO)2qDZB.s5eQ68h$*>Jl)#A?]r)?>RlM0q^eQGrM;2['f7B>!S3:9+>[$nGg[2+0>FXs/tPhD>G?HVQp2`0)tX]STX7%6*b(+l>Sf)ll58_5ICiH;]keJ7XU76=[R"op65I\N/P#(KU'/Zu?6qZd<R)>JYCO)e8nL+#@eOl6nkVtbOjT1@:'S;)FFSpY4HD/?YO/8a9"GjVMu6r0NHe1Q^sfc=6\'3X0hWtmR?4ej9J1</'_?kmU5)R..kKqB3nZR%iP)0Y!ee1LP:F?=q\Y'&WQE&dR:jh#VZX.KtoNUEVY[o8lAnecuXG5'F5.WR7R\VR$Z\H[A(VeDpPVS2]er<+aWm2+hUr*:/)6-/>6pJV!#/eH+qa^K]`$,F;ed>V^\LEt19_beS*9e0rbl0!\-JXhlQk2Y[dj.;jF:f_&G.([Gd4&-lK"i7drPE[`6p^V>9jWG`aUNi<K*Lg5P9^H:0Yr5a/bd&4te;3u^)AD"d$k:%1%&Q.#`5>S..=(LCPUASVA]U(@"'nA*$TA:-^n&PuC.$\nG(%EEGb_lHO$8O%3di1@C4&+bd:^hk@>XS-__R7f"6XknhSElaU^Xtrc[[TG9gj6)Lp2dI\k:0eN5=[k/oH>L`$=4/d8)Zje>D0lQu,Cg(BX'(82D!j.l$)mJp$Yjd[OlhNb;djQ<o5_KUb@e:QcR4igSmD*87jJ-G7?YH*J7D`Zq@:k7;QY#6E#1ZnA]_o:2]uK/Po`YSbAr*lRA@'0Q0^<7.r<2[C0$a=pk0:YS3QmWa8!o^JdMY:mdrM%u@tY>4mM#*pON,<Bo>%b(,+nf`si*163dUo[g4#fq8#lCGl0'QV%=%aqdA>AQmoo5DF%LD/.II%'gee9VWLR`5l\\+0Ji2QJQciV&0_F<V)&+0[`cPs=l)+]g*'mcujIL$TDps"Gt:/qJKiVo8^P_$I<rc9E,([dLK=>T4n"`_,MQUfce]m+&57T"P\]p6'Wg(%3tpR8Kq?.ZM@j>0/PCf$XUlLd\'^TOkJ+D?JXhe\0/;*0i!^CgVH!*"GmH('4(SS"08`*W*?.G0r6`&uG5[&@*U1HZGh/9ul&F\j*a<g4?s%]3i:271c\HSkKMi]8tqQ`-/hs;=%)*kfm6och?L<8o?ZSa7ZWD(l([*=Qf;<_M:`9,,j1%]-;Yp*Dh?\_Qa$E\RMI6fXPf^Q8.(laOr&)]ANtG[0TCo/pN,qm`U1`4=,1o:>]&p^6d3G0P_]?W#[pD&9tS)S%ULDi`Yj7^%!pZi&Tr!I-)jKY=QYaIg/IjcOm7mV)Sc]R.WP(:s&+KH,@biQN_>MK+qBDWD<n@8nRen6s#n2.d[$#E_saT98G,p`V!J:DSmTg[o[F)$reqD'rB2:Nh&*M>@aBNZf%oLGT#2eE/E+22X#56AA@4e9:*V=_'b+@j8.#?(*o\lF^/\oSSTPic5)-0$8uKr2r[:X_/[YR"EF!+hS?tB)HGZl~>endstream
endobj
28 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1224
>>
stream
GauI59lo&I&;KZM'mip6MBY<9+%KPD1[-`9&o$&@I"=j[7SNpm#hkSoI2AR;%p@<0;iaEe&JVLnICQoXP!FsJ&q8".i-5:O1BN6H@L7]V$l4?.l!j9p'P2Q['GMa[0i%5rcR=2@321@Rd_H`24G<u!cblc;q.Se@pYLcUh)L<p_J-h/@YA8@LBp$TSq10m"0r4^3"/7cN5&[*gPD9&/UWk.W\bf*nII1"na<"&&0>EI'>'[[93"RNPc14A6q(AA0h,!XUe$Up%gu/HnL[MqSI@Vhq1!s/O[KLe5k?BGTYsGhrY#o:U*>)mq5C^$"rbt_M8;,Ebgmtt+[`"=oB=XlL(GO;Lh0+Jn.;KZ+d!b3pE">r%lsAXe$J]"q=oR4iP)oca2%J7'i85Yo"'HSFIfMkK$k&gB8p5KYiV-jZ?3dFYV[,s>kPLD\F%l"le70[)::'8bheuVW2dZ,qU1bs&FtZs!^?=p<j3:<2E0'9PFYXnG;9)J(S%l*)G\"6Kk[P?4rcm]oBcF<YS0(a":OD!:P%\,F:pbFNCDK-K*9I4(KT&N*g<q3V0('$XdlX%HB9P5hk0+#/sV`!MH5taX^PecXh01n(-95^<EG%rb1[tO/&aCF=CnN#+A'.YU##bE@r)%@DNB>YJ94Tq+$2sj-U-?9'Yd`VV)nqF<g:"F^LUVGNjcWQf?^O3V!jD=Rjq?[OU6B0dPOn%Vk'f6V_G;Q;l[qcf&NRF%8N1oRi[5Vpg-Kt]M^u@eGu#113lJ1,]W`NhDprbfcGOl4Fal3T-4>d5;6YjY\S27-$]&cr6c[:kc8>NL.^4O=0eg"T*)rt6ou\RL1B85?aQpm2cs%n^3h._C1W+F!F5?K$Mu.1C3Fba/2#O?YpV8u&:X+GY\\eYP2pJAkY%_TLnZpP]-hSr$XKpo=#dl,ZT0EChg0"5'@puuKZ.!/q5Z#e06R?c9+D$OA3XI,]FA9>&o`l94#dnE6h/XX<R>WG]l;jYY84W:UFHJ:0@GQ/F&FiujC:W`Q]L8+D>;aV^=2+&P^V^gU[Em]<;He6gt4Ii?"&?H"I!(RN[g*3EdY59n8O)eCqjSdPe7GJhig<QX/L=Ya8,Pg+Sn\j.#kKsdK=B>'C(-aAt$//=Ms^;WT3k%T-aA-QBD)B,r<^6m3bM.&Yj*G6*>B"P&3XNO>%#d&BTA!1uCnd4H+mL[M*+NS%aJMH>0XYD'*)_G.:rP0:F0Dr;~>endstream
endobj
29 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 446
>>
stream
GatU.b>,r/&A70Vjp2r3gTb8c#SBKr+C=jE.o"b`*lW!76[V">P"KF=:<8<:]unREGg/MP@f;nM^f?-BS:PZj9/&X7Z9)<(d<e9GVQo)&>RAN"#UbYqRu$)LC*3\E9Me)Kh.II/U6/1U2FEXiN/1SV,<uBA.ZkjFM+Il[$32tVl3Vf6NO-[5FgXqJ\&!L_=m#*3Z<(QQJSp?RP,MoC9A=&]/rF7Bg1g[4L)Ne"!^iAI]GoZS_$uNR4)lA\r:K6'%<3&FQj[k-oO,hE$CF&JE(5eXr-Z%pAHbhS1''N5_<_a?KiEqK5KAsK+7#U=etFetdElA]O!/2@->@FBQE>#qL9J$IBR*9HV8%i8VF%>Wmb^e!0:-Dbl%9=?E@K+g$ot9U$KM-al!?en?.Eikgm^b0D=N5`BCi,g>.*/f\'<@SmETkMY&hRE:di&>=/?6~>endstream
endobj
30 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 765
>>
stream
GatU/gQ'`:&:O"KbSp^chDk6l_M[G!&.=sLE8sN*8F0_G$iPFl::mmF!XYPm[d24!F3a<?6UDk9f5:_9e\]iG#G+9:"4(*[m0@mlY.h)A<@:q5!_]T,i3\2V.=?EI9&[f_6]j`9PV>F$eF>B2h<IO4#I]AP7l$BC7G?h<EmC_k!(KYpW5.g&J0-(+_?_&gICg;='\C?"n.C/Mc9-mU/$pr2h)U3+X=DP8f1,L,U@q1fB+WW>9q@At-K.ZjDX)HPDHLnaP6I,g:H\W[TsWd;esb-I-*]hqaWHJ;S2GHg]DCW"eGs<HQ=k`ooI_LZR6X%I8p\K)pNa1%djsuX)'b\t7E.?)8bknk!\qBhRuBB4X(c[e^(WZH>@G"\_OVJa7nWJAcf<=(6g$-L*8^^,Nc`4!1jg2.+mgY)H'/'3P@Upb6_,bq*Nc\qKZR\Y;X#2M#>0?m&g_c)B(gl*8@sQrC:%HC@O(']K2dNpb%M"Jqus=&<0X8&']F8'Aiglc%ZDG=Ro<!rTd>ZW!8;\M+sB"9C1A\e)7U(\I=TUVDaihb9gZ+XgMp1VKH=)b*7R.*=ALNrdYr+C7cFW2IH];/3pIH4nqR[-p24g26(Scmih>6#7%0AfWc'$n;W$kq$V-&EEl?lQK\.R,j'\`,@hZX+*-LmgUtSJ21p^I10RXYgU[YT!JQTEY7?js]C3pBZ'0.0(R6,!J@U>j"dm#2K=r`7E%KtlYJt*_JTs%E`L%,2Bm6V!.a,%X>4doGSr;r[E>`o~>endstream
endobj
xref
0 31
0000000000 65535 f
0000000061 00000 n
0000000144 00000 n
0000000251 00000 n
0000000366 00000 n
0000000478 00000 n
0000000673 00000 n
0000000868 00000 n
0000001063 00000 n
0000001146 00000 n
0000001341 00000 n
0000001461 00000 n
0000001657 00000 n
0000001853 00000 n
0000002049 00000 n
0000002127 00000 n
0000002323 00000 n
0000002519 00000 n
0000002715 00000 n
0000002785 00000 n
0000003119 00000 n
0000003240 00000 n
0000003901 00000 n
0000005993 00000 n
0000008355 00000 n
0000010383 00000 n
0000012824 00000 n
0000015063 00000 n
0000017427 00000 n
0000018743 00000 n
0000019280 00000 n
trailer
<<
/ID
[<8c841a256005e9c14418567efe6f7d83><8c841a256005e9c14418567efe6f7d83>]
% ReportLab generated PDF document -- digest (opensource)
/Info 19 0 R
/Root 18 0 R
/Size 31
>>
startxref
20136
%%EOF

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,4 @@
WARNING: Unknown tag 'iorm'. Not in taxonomy.
WARNING: Unknown tag 'storage'. Not in taxonomy.
Added: FF-202604-001 [MEDIUM] ExaCS iormcal fails silently when storage server count < 3 — validate IORM plan after apply

Binary file not shown.

Binary file not shown.

434
examples/proposal-spec.yaml Normal file
View File

@@ -0,0 +1,434 @@
# OCI Deal Accelerator — Proposal Spec
# Customer: MELI (Mercado Libre) | Project: KVS
# Drives: oci_deck_gen.py (.pptx) + oci_pdf_gen.py (.pdf)
metadata:
customer: "Mercado Libre (MELI)"
project: "KVS — OCI NoSQL Database"
subtitle: "Key-Value Store Architecture Proposal"
architect: "Carlos Mendoza"
firm: "Oracle Cloud Infrastructure"
date: "2026-03-18"
summary:
why: >
MELI operates a mission-critical KVS platform on AWS DynamoDB serving 70M RPM
at peak across 30,000 tables. Noisy neighbor effects cause unpredictable latency,
and the team faces memory leak issues with DynamoDB table instances. MELI requires
strong consistency, dedicated infrastructure isolation, and a simpler pricing model
at hyperscale.
current_state:
- "AWS DynamoDB — 30,000 tables across 3 projects"
- "70M RPM peak / 15M RPM average throughput"
- "Item sizes: 50KB-400KB avg, up to 1MB"
- "Noisy neighbor performance variability"
- "Memory leak concerns in table instances"
- "No DAX usage — in-memory cache managed internally"
- "Strong consistency required — currently eventual on many reads"
target_state: >
OCI NoSQL Database on Elastic Pod Dedicated infrastructure with strong consistency
(ABSOLUTE mode), predictable sub-6ms p99 latency, and throughput-based pricing
without per-request overage.
timeline: "PoC Q2 2026 → Phased migration Q3 2026 (conditional on PoC success)"
service_tiering:
- name: "KVS Production Tables"
tier: "Gold"
uptime: "99.99%"
rto: "4 hours"
rpo: "15 minutes"
justification: "Business-critical operational data store; strong consistency required"
- name: "KVS PoC / Benchmarking"
tier: "Bronze"
uptime: "98%"
rto: "Best effort"
rpo: "Best effort"
justification: "Evaluation environment; disposable"
architecture_principles:
design:
- id: "D-01"
name: "Operational Simplicity"
summary: "Prefer managed services over self-managed infrastructure"
rationale: "OCI NoSQL is fully managed — no DBA overhead for KVS operations"
- id: "D-03"
name: "Use-Case Fit"
summary: "Select services optimized for the specific workload pattern"
rationale: "OCI NoSQL is purpose-built for key-value/document workloads at scale"
- id: "D-05"
name: "HA for Business Continuity"
summary: "Design for high availability proportional to business impact"
rationale: "70M RPM workload requires Gold-tier availability (99.99%)"
deployment:
- id: "P-03"
name: "API-Centric Integration"
summary: "All service interactions via well-defined APIs"
rationale: "OCI NoSQL SDK supports Java/Python with conditional expressions"
architecture:
description: >
Single-region OCI NoSQL deployment on Elastic Pod Dedicated infrastructure in
São Paulo region. MELI applications connect via OCI NoSQL SDK through Service
Gateway for private network access. Dedicated infrastructure eliminates noisy
neighbor effects and provides predictable performance at 70M RPM peak.
Key components:
• OCI NoSQL Database — Elastic Pod Dedicated (isolated compute/storage)
• 30,000 tables with provisioned read/write capacity
• Strong consistency (ABSOLUTE) on all operations
• Service Gateway for private access from MELI VCN
• OCI Monitoring + Logging for operational visibility
diagram_path: "architecture.drawio"
visual:
regions:
- name: "São Paulo"
services:
- name: "OCI NoSQL (Elastic Pod Dedicated)"
type: "database"
- name: "Service Gateway"
type: "networking"
- name: "OCI Monitoring"
type: "observability"
decisions:
- title: "OCI NoSQL over ADB-S JSON"
decision: "Use OCI NoSQL Database instead of Autonomous Database JSON collections"
rationale: >
OCI NoSQL is purpose-built for key-value operations at 70M RPM with provisioned
throughput. ADB-S JSON tables have higher latency for simple key-value lookups
and don't support the same throughput model.
alternatives: "ADB-S JSON Collections, OCI MySQL HeatWave"
- title: "Elastic Pod Dedicated over Elastic Pod"
decision: "Use Elastic Pod Dedicated for isolated infrastructure"
rationale: >
MELI's primary concern is noisy neighbor effects. Elastic Pod Dedicated provides
fully isolated compute and storage, eliminating shared-tenancy performance variability.
alternatives: "Elastic Pod (shared), Provisioned standalone"
- title: "Strong Consistency (ABSOLUTE)"
decision: "Configure all tables with ABSOLUTE consistency level"
rationale: >
MELI requires strong consistency as a MUST. OCI NoSQL ABSOLUTE consistency
guarantees reads return the latest committed value at the cost of slightly
higher latency (within target < 6ms).
alternatives: "EVENTUAL consistency (rejected — does not meet requirements)"
- title: "Provisioned Capacity over On-Demand"
decision: "Use provisioned capacity with auto-scaling for cost predictability"
rationale: >
At 70M RPM peak, on-demand pricing would be unpredictable. Provisioned capacity
with auto-scaling between 15M-70M RPM provides cost control with burst capability.
alternatives: "On-Demand (higher cost, unpredictable)"
- title: "São Paulo Region"
decision: "Deploy in OCI São Paulo (sa-saopaulo-1) region"
rationale: >
MELI is headquartered in Latin America. São Paulo region provides lowest
latency to MELI's primary user base and infrastructure.
alternatives: "Ashburn (higher latency), Santiago (limited services)"
- title: "Oracle 23ai for AI Agent Memory (Phase 4)"
decision: "Use Oracle ADB-S 23ai with AI Vector Search as semantic memory tier for AI agents"
rationale: >
Oracle 23ai combines vector search + relational + JSON + graph in one engine.
Eliminates need for a separate vector DB (Pinecone/Weaviate). Provides ACID
guarantees on memory operations. Two-tier architecture: NoSQL (hot memory at
70M RPM) + ADB-S (semantic recall via vector similarity at < 50ms). Incremental
cost < 10% of KVS infrastructure.
alternatives: "Pinecone (no relational/ACID), pgvector (less scalable), All-in-NoSQL (no vector search)"
- title: "SDK Migration Approach"
decision: "Migrate from boto3 DynamoDB SDK to OCI NoSQL SDK"
rationale: >
OCI NoSQL SDK supports conditional expressions (IfAbsent, IfPresent, IfVersion)
and transactional writes (WriteMultiple), providing feature parity with
DynamoDB's ConditionalCheck and TransactWriteItems.
alternatives: "REST API (lower-level, more development effort)"
ha_dr:
description: >
Initial deployment is single-region (São Paulo) for PoC evaluation.
Production HA relies on OCI NoSQL's built-in data replication across
fault domains within the region. DR strategy to be defined post-PoC
based on MELI's RPO/RTO requirements.
tiers:
- tier: "Gold — KVS Production"
technology: "OCI NoSQL Elastic Pod Dedicated, multi-FD replication, cross-region DR (Phase 2)"
rto: "4 hours"
rpo: "15 minutes"
- tier: "Bronze — KVS PoC"
technology: "OCI NoSQL Elastic Pod, single region, no DR"
rto: "N/A"
rpo: "N/A"
security:
controls:
identity:
- "OCI IAM policies for NoSQL table access"
- "API key authentication for SDK access"
- "Compartment-based isolation per project"
network:
- "Private subnet — no public endpoint"
- "Service Gateway for OCI service access"
- "NSG rules limiting access to MELI app subnets"
data_protection:
- "Encryption at rest (AES-256, OCI-managed keys)"
- "Encryption in transit (TLS 1.2+)"
monitoring:
- "OCI Monitoring for throughput/latency metrics"
- "OCI Logging for audit trail"
- "Alarms on throughput throttling"
compliance: []
environment_catalogue:
environments:
- name: "Production"
sizing: "Elastic Pod Dedicated — full provisioned capacity (70M RPM peak)"
isolation: "Dedicated compute/storage"
cost_pct: 100
- name: "Pre-Production / Staging"
sizing: "Elastic Pod — 25% of production capacity"
isolation: "Shared infrastructure"
cost_pct: 25
- name: "PoC / Benchmarking"
sizing: "Elastic Pod — variable capacity for benchmark testing"
isolation: "Shared infrastructure"
cost_pct: 15
cost_notes: "PoC environment cost is temporary (8 weeks). Pre-Prod runs at 25% capacity."
cost:
line_items:
- component: "OCI NoSQL — Elastic Pod Dedicated (Prod)"
monthly_payg: "$85,000"
notes: "30K tables, 70M RPM peak / 15M RPM avg"
- component: "OCI NoSQL — Storage (300TB)"
monthly_payg: "$2,550"
notes: "$0.0085/GB/month"
- component: "OCI NoSQL — Pre-Production (25%)"
monthly_payg: "$21,250"
notes: "Shared Elastic Pod"
- component: "OCI NoSQL — PoC Environment"
monthly_payg: "$5,000"
notes: "Temporary — 8 weeks"
- component: "OCI Networking (VCN, SGW)"
monthly_payg: "$0"
notes: "No cost for basic networking"
- component: "OCI Monitoring & Logging"
monthly_payg: "$500"
notes: "Based on ingestion volume"
- component: "TOTAL"
monthly_payg: "$114,300"
notes: ""
assumptions:
- "Pricing estimated based on OCI NoSQL provisioned capacity model"
- "Actual cost depends on final read/write unit provisioning"
- "Storage estimate based on 30K tables × 10MB average (300TB)"
- "Pre-Production at 25% of production capacity"
- "PoC is temporary (8 weeks) and will be decommissioned"
- "No FastConnect or VPN costs included (MELI to provide connectivity)"
- "No BYOL applicable — OCI NoSQL is cloud-native service"
show_byol: false
cost_comparison:
title: "Cost Comparison: OCI NoSQL vs AWS DynamoDB"
col_headers: ["Component", "AWS DynamoDB (Current)", "OCI NoSQL (Proposed)", "Delta"]
rows:
- item: "Provisioned Capacity (70M RPM peak)"
current: "$120,000/mo"
oci: "$85,000/mo"
savings: "-29%"
- item: "Storage (300TB)"
current: "$75,000/mo"
oci: "$2,550/mo"
savings: "-97%"
- item: "Pre-Production (25%)"
current: "$30,000/mo"
oci: "$21,250/mo"
savings: "-29%"
- item: "Data Transfer"
current: "$15,000/mo"
oci: "$0 (within OCI)"
savings: "-100%"
- item: "Monitoring"
current: "Included"
oci: "$500/mo"
savings: "+$500"
- item: "TOTAL MONTHLY"
current: "$240,000/mo"
oci: "$109,300/mo"
savings: "-54%"
- item: "TOTAL ANNUAL"
current: "$2,880,000/yr"
oci: "$1,311,600/yr"
savings: "-$1.57M/yr"
migration:
phases:
- name: "Phase 1: PoC & Benchmarking"
duration: "8 weeks"
description: >
Set up OCI NoSQL environment, create representative tables, run benchmarks
at target throughput, validate feature compatibility.
milestones:
- "OCI tenancy provisioned"
- "Representative schema created (subset of 30K tables)"
- "SDK integration validated"
- "Benchmark results at 70M RPM"
- "Go/No-Go decision"
- name: "Phase 2: Pilot Migration (1 project)"
duration: "6 weeks"
description: >
Migrate one of the 3 projects (~10K tables) to OCI NoSQL. Run in parallel
with DynamoDB. Validate data consistency and performance in production.
milestones:
- "Data migration tooling validated"
- "SDK abstraction layer for dual-write"
- "Production traffic on OCI NoSQL for 1 project"
- "Performance comparison in production"
- name: "Phase 3: Full Migration"
duration: "8 weeks"
description: >
Migrate remaining 2 projects. Decommission DynamoDB tables.
milestones:
- "All 30K tables migrated"
- "DynamoDB decommissioned"
- "Cost optimization review"
- name: "Phase 4: Memory for Agent — Oracle AI Database Integration"
duration: "10 weeks"
description: >
Extend MELI's KVS platform with AI agent memory capabilities using
Oracle Database 23ai. Deploy Autonomous Database with AI Vector Search
to serve as persistent, semantic memory for MELI's AI agents. The KVS
layer (OCI NoSQL) handles high-throughput operational state, while
Oracle AI Database provides long-term semantic memory with vector
similarity search, contextual recall, and knowledge graph capabilities.
This creates a two-tier memory architecture: hot memory (NoSQL KVS)
for real-time agent state + warm/cold memory (Oracle 23ai) for
semantic retrieval, conversation history, and learned patterns.
milestones:
- "Oracle ADB-S 23ai provisioned with AI Vector Search enabled"
- "Memory schema designed (episodic, semantic, procedural memory types)"
- "Vector embedding pipeline deployed (OCI GenAI or MELI model)"
- "Agent Memory SDK integrated with MELI's agent framework"
- "NoSQL ↔ ADB-S memory tier sync implemented"
- "Semantic recall benchmarked (recall@k, latency, relevance)"
- "Production agent memory serving live traffic"
tools:
- "OCI NoSQL SDK (Java, Python) for data migration"
- "Custom migration scripts for schema mapping"
- "OCI Data Integration (if applicable)"
- "Oracle Database 23ai — AI Vector Search for agent memory"
- "OCI Generative AI Service — embedding generation"
- "DBMS_VECTOR / DBMS_VECTOR_CHAIN PL/SQL packages"
downtime: "Zero downtime — dual-write migration pattern"
operational_raci:
model: "co_managed"
raci_items:
- activity: "NoSQL Table Provisioning"
oracle: "C"
customer: "R"
- activity: "Capacity Planning & Scaling"
oracle: "C"
customer: "R"
- activity: "Infrastructure Patching"
oracle: "R"
customer: "I"
- activity: "Monitoring & Alerting"
oracle: "C"
customer: "R"
- activity: "Backup & Recovery"
oracle: "R"
customer: "C"
- activity: "Security (IAM, NSG)"
oracle: "C"
customer: "R"
- activity: "Incident Response"
oracle: "C"
customer: "R"
- activity: "Cost Optimization"
oracle: "C"
customer: "R"
- activity: "SDK / Application Support"
oracle: "C"
customer: "R"
risks:
- risk: "30,000 tables may exceed OCI NoSQL tenancy limits"
severity: "HIGH"
probability: "Medium"
mitigation: "Validate table limits with OCI product team; request limit increase if needed"
- risk: "Elastic Pod Dedicated feature gap (identified in discovery)"
severity: "HIGH"
probability: "Medium"
mitigation: "Clarify specific feature gap with NoSQL product team before PoC"
- risk: "Latency targets (20μs write/10μs read) may not be achievable"
severity: "MEDIUM"
probability: "High"
mitigation: "These are likely in-process DynamoDB latencies; network RTT applies to both. Benchmark actual end-to-end latency"
- risk: "SDK migration effort — conditional expressions API differences"
severity: "MEDIUM"
probability: "Medium"
mitigation: "Build abstraction layer during PoC; map DynamoDB expressions to OCI NoSQL equivalents"
- risk: "Data type mapping gaps between DynamoDB and OCI NoSQL"
severity: "LOW"
probability: "Low"
mitigation: "Both support JSON-native types; map during Phase 1"
- risk: "In-memory cache integration with OCI NoSQL"
severity: "LOW"
probability: "Low"
mitigation: "MELI manages cache internally — SDK-level integration only"
scorecard:
pillars:
- name: "Security & Compliance"
status: "PASS_WITH_RECOMMENDATIONS"
passed: 21
total: 26
- name: "Reliability & Resilience"
status: "PASS_WITH_RECOMMENDATIONS"
passed: 6
total: 8
- name: "Performance & Cost"
status: "PASS_WITH_RECOMMENDATIONS"
passed: 4
total: 5
- name: "Operational Efficiency"
status: "PASS_WITH_RECOMMENDATIONS"
passed: 8
total: 10
- name: "Distributed Cloud"
status: "N/A"
passed: 0
total: 0
recommendations:
- "39/49 checks passed — architecture is well-designed for PoC stage"
- "2 remaining HIGH gaps are validation engine keyword limitations, not real gaps"
- "Define DR strategy for production post-PoC (cross-region replication)"
- "Validate table limit (30K) with OCI product team"
next_steps:
steps:
- "Provision OCI tenancy for MELI KVS PoC — Carlos / Amit — by 2026-04-01"
- "Clarify Elastic Pod Dedicated feature gap with NoSQL product team — Carlos — by 2026-03-25"
- "Validate 30K table limit and request increase if needed — Carlos — by 2026-03-25"
- "Provide benchmark test plan and success criteria — Mario — by 2026-04-07"
- "Schedule weekly sync for PoC duration — Amit / Luciano — by 2026-04-01"
contact_info: "Carlos Mendoza — Solutions Architect, Oracle Cloud Infrastructure"

Binary file not shown.

19
kb/CHANGELOG.md Normal file
View File

@@ -0,0 +1,19 @@
# KB Changelog
Recent changes to the Knowledge Base. The skill shows the latest entry in the welcome banner.
## 2026-04-14
- Diagram generator: icon sizing calibrated from 37 Oracle Architecture Center .drawio files (63px services, 42px gateways)
- Diagram generator: auto-sizing containers, DRG placement outside VCN, edge label offsets
- Diagram generator: VCN/subnet dash pattern corrected to "4 2" (Oracle ref standard)
- New: `scripts/validate-diagram.py` — automated diagram quality validation
- New: `--check-links` in refresh_arch_catalog.py — detects broken URLs in catalog
- New: weekly KB health CI workflow (`.gitea/workflows/kb-health.yaml`)
- SKILL.md: anti-hallucination guardrails (closed whitelist + mandatory pre-generation review)
- SKILL.md: structured data intake (Extraction Receipt + Completeness Gate)
## 2026-04-01
- KB validation: 30 corrections across 16 files (ExaCS storage, ECPU transition, IOPS fixes)
## 2026-03-16
- Architecture Center catalog refreshed: 123 entries verified

122
kb/README.md Normal file
View File

@@ -0,0 +1,122 @@
# Knowledge Base — Contributor Guide
The KB is the moat. It encodes Oracle field experience, OCI service quirks,
and architecture patterns that aren't in the official docs. Tools and the
skill itself read these YAMLs at runtime.
## Directory map
| Directory | Purpose | Format |
|---|---|---|
| `services/` | One file per OCI service. Capabilities, limits, gotchas, when-to-use. | Frontmatter + structured body |
| `patterns/` | Composable architecture blocks (HA, DR, hub-spoke, RACI, ECAL artefacts). | Frontmatter + body, often nested dirs |
| `sizing/` | CPU/memory/storage conversion ratios, IOPS limits, scaling rules. | Body only |
| `pricing/` | `oci-sku-catalog.yaml` (200+ SKUs, auto-refreshed) + `compute.yaml` (shape-level, auto-refreshed). Both pull from the Oracle public pricing API. | Frontmatter + body |
| `competitive/` | OCI vs AWS / Azure / GCP service mapping and objection handling. | Frontmatter + body |
| `compatibility/` | Feature matrices (e.g. ADB-S features). Currently thin — expected to grow. | Frontmatter + body |
| `well-architected/` | 5-pillar checklists, landing zone patterns, persona views. | Frontmatter + body |
| `architecture-center/` | Auto-curated index of Oracle Architecture Center reference architectures. | Single `catalog.yaml` |
| `field-knowledge/` | Real-world gotchas, lessons learned, undocumented limits. | Frontmatter + body |
| `field-findings/` | Tracker of newly logged field issues with confidence decay. | Single `tracker.yaml` |
| `diagram/` | OCI icon library and reference layouts for diagram generation. | Mixed |
## Required frontmatter
Every YAML file under `kb/` should start with a frontmatter block:
```yaml
---
last_verified: 2026-04-08 # YYYY-MM-DD, when the file was last reviewed against current Oracle docs
source: https://docs.oracle.com/... # primary source(s) used during last verification
description: One-line summary of what this file contains
---
# body starts here
key: value
```
The freshness checker (`tools/kb_freshness.py`) reads `last_verified` and warns
if a file is older than the thresholds in `config/kb-governance.yaml`
(default: warning at 180 days, stale at 365 days). The KB linter
(`tools/kb_linter.py`) accepts `last_updated` and `last_refreshed` as fallback
field names but new files should use `last_verified`.
## How to add a new service card
1. Copy an existing card with similar structure: `cp kb/services/adb-serverless.yaml kb/services/<your-service>.yaml`.
2. Update the frontmatter (`last_verified` to today, `source` to the docs URL you used).
3. Fill in fields. Keep gotchas honest — if the service has a limitation, write it down. The KB's value is honesty, not marketing.
4. Run `python tools/kb_linter.py` and fix any issues it reports for your file.
5. Run `make freshness` to confirm your new file is FRESH.
## How to add a pattern
Patterns can be either single-file (e.g. `kb/patterns/business-drivers.yaml`)
or directory-based for larger blocks (e.g. `kb/patterns/database-ha/`).
Use a directory when you need multiple files (pattern + diagrams + ADRs).
## Refresh tooling
| File | Refresh tool |
|---|---|
| `kb/pricing/oci-sku-catalog.yaml` | `python tools/refresh_sku_catalog.py --refresh` (Oracle pricing API) |
| `kb/pricing/compute.yaml` | `python tools/refresh_sku_catalog.py --refresh-domain compute` (same API, shape-level) |
| `kb/architecture-center/catalog.yaml` | `python tools/refresh_arch_catalog.py --whats-new` (web crawl) |
| Other `kb/pricing/<domain>.yaml` | Not yet automated. Add a new entry to `DOMAIN_REGISTRY` in `tools/refresh_sku_catalog.py` and write a domain-specific refresher (see `refresh_compute_yaml` as a template). |
| Everything else | **Manual** — review against Oracle docs, bump `last_verified` |
The shortcut for everyone:
```bash
make freshness # report stale files
make freshness-refresh # run automatic refreshes for files that support them
```
## Pricing files
There are exactly **two** pricing files, both auto-refreshed from the
[Oracle public pricing API](https://apexapps.oracle.com/pls/apex/cetools/api/v1/products/?currencyCode=USD):
1. **`kb/pricing/oci-sku-catalog.yaml`** — 200+ SKUs across 20 categories
(compute, storage, database, networking, observability, security, AI/ML,
GenAI, etc.). Refresh: `python tools/refresh_sku_catalog.py --refresh`.
2. **`kb/pricing/compute.yaml`** — shape-level estimation pricing
(VM.Standard.E5.Flex hourly, monthly, etc.). Different abstraction from
the SKU catalog — useful for SA estimation. Refresh:
`python tools/refresh_sku_catalog.py --refresh-domain compute`.
**Pricing context that ISN'T a price** (billing models, BYOL rules, free
tiers, service nuances, hyperscaler comparisons) lives in
`kb/field-knowledge/pricing-knowledge.yaml`. That file is non-numeric where
possible and does not need API refresh.
There are no other pricing files. The previous `kb/pricing/database.yaml`,
`storage.yaml`, `networking.yaml`, etc. were removed on 2026-04-08 — their
prices were drift-prone and 30-800% off the live API; their notes were
migrated to `kb/field-knowledge/pricing-knowledge.yaml`.
## Linter
```bash
python tools/kb_linter.py # all checks
python tools/kb_linter.py --show-decay # confidence decay only
python tools/kb_linter.py --check-tags # tag taxonomy only
python tools/kb_linter.py --check-owners # domain owner assignments only
```
The linter reports STALE / WARNING for files past their freshness threshold,
unknown tags in field findings, and missing domain owners. Exit code is 1 if
any issues are found.
## Review cadence
- **Field findings**: confidence decays automatically — see `config/kb-governance.yaml`
- **Service cards**: review at least every 6 months, or when Oracle publishes a major update
- **Patterns**: review at least once a year
- **Pricing**: ideally every quarter — Oracle changes prices ~2x per year for major SKUs
## Thin directories
`compatibility/` and `field-findings/` currently hold a single file each.
Both are expected to grow as more SAs contribute. If after 6 months they
remain at 1 file, consider consolidating with a parent directory.

View File

@@ -9,12 +9,12 @@
# STRONG MATCH: ≥2 service matches + ≥1 tag match
# MODERATE MATCH: ≥1 service match + ≥2 tag matches
#
# Last refreshed: 2026-03-16
# Last verified: 2026-03-16
# Entry count: 123
# To refresh: python tools/refresh_arch_catalog.py --whats-new
# =============================================================================
last_refreshed: "2026-03-16"
last_verified: "2026-03-16"
source: "https://docs.oracle.com/en/solutions/oracle-architecture-center/"
entry_count: 123

View File

@@ -1,7 +1,5 @@
---
last_verified: 2026-03-14
description: Common customer objections about OCI and evidence-based responses.
---
objections:
- id: OBJ-001

View File

@@ -0,0 +1,295 @@
# Oracle Architecture Center Reference Diagram Measurements
Extracted from official Oracle .drawio source files (draw.io/28.0.4, Visio-exported).
Sources analyzed:
1. Hub-and-Spoke DRG (hub-spoke-network-drg) - single-region, 3 VCNs, hub topology
2. Essbase Cross-Region DR (cross-region-dr-essbase-oci) - dual-region, 3 ADs each, DR topology
Tool: draw.io 28.0.4 (Electron), exported from Visio (.vsdx)
---
## 1. Canvas / Page Settings
| Property | Hub-Spoke DRG | Essbase DR |
|----------|--------------|------------|
| pageWidth | 850 | 850 |
| pageHeight | 1100 | 1100 |
| gridSize | 10 | 10 |
| Actual content W | 693 | 2339 |
| Actual content H | 846 | 1154 |
---
## 2. Font Specifications
| Usage | Font Family | Font Size | Style |
|-------|------------|-----------|-------|
| Region/VCN/service labels | Oracle Sans | 16.93px (~17px) | Bold for region title |
| Annotation text | Oracle Sans | 14.82px (~15px) | Regular |
| Label box height | - | 20px | - |
| Annotation box height | - | 17px | - |
---
## 3. Color Palette
| Element | Hex |
|---------|-----|
| OCI Region fill | #f5f4f2 |
| OCI Region stroke | #9e9892 |
| VCN / Subnet border (dashed) | #aa643b |
| Connector lines / solid borders | #312d2a |
| Service icon primary (teal) | #2d5967 |
| Connector lines (Essbase) | #161513 |
| AD fill (multi-AD diagrams) | #e4e1dd |
| Background | #FFFFFF |
| Accent brown | #ae562c |
---
## 4. Container Dimensions
### 4.1 OCI Region
- Hub-Spoke: 456x845 at (236,0), fill=#f5f4f2, stroke=#9e9892
- Essbase Left: 995x849 at (0,305)
- Essbase Right: 1080x849 at (1258,304)
- Pattern: Double-rendered (fill layer + stroke layer as separate shapes)
### 4.2 VCN
- DMZ VCN (Hub-Spoke): 226x354 at (456,26)
- Spoke VCN 1: 226x205 at (456,406)
- Spoke VCN 2: 226x202 at (457,634)
- Essbase left VCN: 894x766 at (30,355)
- Essbase right VCN: 872x766 at (1328,354)
- Style: strokeColor=#aa643b, strokeWidth=2, dashed=1, dashPattern=4.00 2.00
### 4.3 Subnet
- Management Subnet: 176x134 at (498,76)
- Services Subnet: 176x134 at (498,238)
- Workload Subnet 1: 175x143 at (500,458)
- Workload Subnet 2: 175x142 at (500,686)
- Style: Same as VCN (strokeColor=#aa643b, strokeWidth=2, dashed)
### 4.4 Availability Domain (Essbase)
- Width: 188, Height: 815
- Positions: x=211, 425, 632 (left region), x=1508, 1724, 1930 (right region)
- AD-to-AD gap: 18-28px (~25px avg)
- Style: fill=#e4e1dd, stroke=#9e9892
### 4.5 On-Premises Box (Essbase)
- 260x251 at (997,0) - centered between two regions
- Style: fill=#f5f4f2, stroke=#9e9892
### 4.6 Workload Rows (Essbase)
- Standard row: 807x111
- Bottom row (expanded): 807x149
- Y positions: 415, 552, 690, 828, 962
- Row-to-row gap: 23-27px (~25px)
### 4.7 Compartment Boxes (Essbase)
- 189x49 - placed at AD/row intersections
---
## 5. Icon Dimensions
### 5.1 Service Icons (VM, Bastion, Database, etc.)
- 3-layer nesting: 63x63 outer > 61x61 middle > 60x60 inner
- Standard service icon = 60px rendered in 63px box
- Internal details: 13x13 grid cells, 43x13 bottom bar, 3x3 dots
### 5.2 Gateway Icons (IGW, NAT, SGW, DRG attachments)
- 3-layer nesting: 42x42 outer > 41x41 middle > 40x40 inner
- Central symbol: 29x26, internal detail: 22x29
- Status indicators: 4x4 dots, 5x1 bars
### 5.3 OCI Toolkit Icons (Bastion-type)
- 40x63 outer > 39x61 middle > 34x58 inner (portrait orientation)
### 5.4 Database/Storage Icons
- 59x63 outer > 58x61 middle > inner symbol 39x26 + 21x21
### 5.5 External Icons (Internet, On-Premises)
- Same 63x63 as service icons
---
## 6. Spacing Rules
### 6.1 Vertical Spacing
| Measurement | Value |
|-------------|-------|
| Region label Y offset | 7px from region top |
| VCN/Subnet label Y offset | 8px from container top |
| VCN top to first subnet | 50px |
| Subnet-to-subnet gap | 28px |
| VCN-to-VCN gap | 26px |
| Workload row gap | 23-27px (~25px) |
| Gateway Y within VCN | 29px from VCN top |
### 6.2 Horizontal Spacing
| Measurement | Value |
|-------------|-------|
| VCN to subnet left indent | 42-44px |
| Service icon X within subnet | 80px from subnet left |
| Gateway X from VCN left | 168px |
| AD-to-AD gap | 18-28px (~25px) |
| Inter-region gap (Essbase) | 263px |
### 6.3 Label Spacing
| Measurement | Value |
|-------------|-------|
| Label box height | 20px (standard) |
| Annotation box height | 17px |
| Line-to-line spacing | 17px |
---
## 7. Connector Styles
Oracle Visio-exported .drawio files do NOT use draw.io native edges. Connectors are thin rectangles:
- Horizontal: Wx1 rectangles, stroke=#312d2a
- Vertical: 2xH or 1xH rectangles
- Cross-region (Essbase): stroke=#161513
- Examples:
- Internet-to-Gateway: 350x1 at (80,153)
- Mid-connections: 156x1 at (98,524)
- DR replication: 549x1 at (391,1045)
- Vertical link: 1x65 at (1128,365)
---
## 8. Border/Stroke Styles
| Element | strokeColor | strokeWidth | dashed | dashPattern |
|---------|------------|-------------|--------|-------------|
| Region | #9e9892 | 1 | No | - |
| VCN | #aa643b | 2 | Yes | 4.00 2.00 |
| Subnet | #aa643b | 2 | Yes | 4.00 2.00 |
| AD | #9e9892 | 1 | No | - |
| Solid grouping | #312d2a | 2 | No | - |
| Connector | #312d2a/#161513 | 1 | No | - |
---
## 9. Double-Layer Container Rendering
Oracle renders each container as TWO overlapping shapes:
1. Fill layer: fillColor=<color>, strokeColor=none
2. Stroke layer: fillColor=none, strokeColor=<color>
This pattern applies to Region, VCN, Subnet, and AD containers.
---
## 10. Key Proportional Ratios
| Ratio | Value | Description |
|-------|-------|-------------|
| Gateway:Service icon | 42:63 = 0.67 | Gateways 2/3 size of service icons |
| VCN:Subnet width | 226:176 = 1.28 | VCN ~28% wider than subnet |
| VCN left padding | 42-44px | Subnet indent |
| VCN top padding | 50px | To first subnet |
| VCN bottom padding | ~22-26px | After last subnet |
| Region aspect (hub-spoke) | 456:845 = 0.54 | Portrait |
| AD aspect (multi-AD) | 188:815 = 0.23 | Very tall/narrow |
| Workload row aspect | 807:111 = 7.27 | Very wide/short |
---
## 11. Recommended Calibration for oci_diagram_gen.py
```yaml
region:
min_width: 456
min_height: 845
fill: "#f5f4f2"
stroke: "#9e9892"
stroke_width: 1
corner_radius: 0
vcn:
min_width: 226
typical_height_hub: 205
typical_height_dmz: 354
stroke: "#aa643b"
stroke_width: 2
dashed: true
dash_pattern: "4 2"
subnet:
width: 176
typical_height: 134-143
stroke: "#aa643b"
stroke_width: 2
dashed: true
dash_pattern: "4 2"
availability_domain:
width: 188
height: 815
fill: "#e4e1dd"
stroke: "#9e9892"
service_icon:
outer: 63
rendered: 60
gateway_icon:
outer: 42
rendered: 40
inner_symbol: 29x26
spacing:
vcn_to_vcn_gap: 26
subnet_to_subnet_gap: 28
vcn_top_to_first_subnet: 50
vcn_left_to_subnet: 42
subnet_to_service_icon: 80
gateway_x_from_vcn_left: 168
gateway_y_from_vcn_top: 29
label_y_offset: 8
region_label_y: 7
workload_row_gap: 25
ad_to_ad_gap: 25
inter_region_gap: 263
fonts:
family: "Oracle Sans"
label_size: 17
annotation_size: 15
label_box_height: 20
annotation_box_height: 17
colors:
region_fill: "#f5f4f2"
region_stroke: "#9e9892"
vcn_stroke: "#aa643b"
subnet_stroke: "#aa643b"
ad_fill: "#e4e1dd"
icon_primary: "#2d5967"
text_dark: "#312d2a"
connector: "#312d2a"
background: "#FFFFFF"
```
---
## 12. Layout Patterns
### Single-Region Hub-Spoke
- VCNs stacked vertically
- External icons (Internet, On-Prem) at far left
- Gateways between external and VCN
- DRG centered with route table
- Service icons right-aligned within subnets
### Dual-Region DR
- Regions side by side horizontally
- On-Premises box centered above/between regions
- ADs as vertical columns within each region
- Workload tiers as horizontal rows crossing all ADs
- Compartment boxes at AD-row intersections
- DR arrows as horizontal lines between matching rows

View File

@@ -47,8 +47,12 @@ findings:
- id: "FF-202603-008"
date: "2026-03-14"
reported_by: "Diego Cabrera"
contributor:
name: "Diego Cabrera"
team: "Field Architecture"
client: "Vector Search Customer"
context: "AI Vector Search engagement"
confidence: "validated"
product: "ADB-S"
version: "23ai"
severity: "HIGH"

View File

@@ -0,0 +1,419 @@
---
last_verified: 2026-04-08
source: Migrated from former kb/pricing/<domain>.yaml files (removed 2026-04-08).
Stable, non-numeric pricing knowledge that does not need API refresh.
All actual price numbers live in kb/pricing/oci-sku-catalog.yaml (auto-refreshed).
description: Pricing context, billing models, free tiers, BYOL rules, and
cross-service estimation knowledge for the OCI Deal Accelerator.
---
# =============================================================================
# OCI Pricing Knowledge
# =============================================================================
#
# This file is the human-readable companion to kb/pricing/oci-sku-catalog.yaml.
# The catalog has live SKU prices (auto-refreshed). This file has the *context*
# a Solutions Architect needs to estimate accurately:
# - Pricing models and when to use each
# - BYOL rules and savings
# - Free-tier rules per service
# - Service-specific billing nuances
# - Cost comparison framing vs hyperscalers
#
# This file is intentionally non-numeric where possible. Specific prices that
# change should NOT be added here — add them to the SKU catalog instead.
# Where a percentage or range is unavoidable (e.g. "BYOL ~50% off"), prefer
# stable rules of thumb over exact figures.
# =============================================================================
# ── PRICING MODELS ────────────────────────────────────────────────
pricing_models:
payg:
name: Pay As You Go
commitment: none
billing: Per second (compute), per hour (database), per month (storage)
when_to_use:
- Variable / unpredictable workloads
- Short-term projects
- Dev / test environments
- Initial cloud adoption (before committing)
monthly_flex:
name: Monthly Flex (Universal Credits)
commitment: Minimum $1,000/month or custom commitment
billing: Committed credits consumed by usage
discount_tiers:
- spend_band: $1K-$10K/month
approx_discount: 5-10%
- spend_band: $10K-$50K/month
approx_discount: 10-20%
- spend_band: $50K+/month
approx_discount: 20-30% (negotiated)
when_to_use:
- Steady-state production workloads
- Known baseline consumption
- Multiple services across OCI
annual_flex:
name: Annual Flex (Committed)
commitment: 1-year or 3-year
discount: Deeper than Monthly Flex
when_to_use:
- Established production workloads with predictable spend
- Organizations committed to OCI long-term
byol:
name: Bring Your Own License
approx_savings: ~50% on database ECPU/OCPU costs
eligible:
- Oracle Database Enterprise Edition
- Oracle Database Standard Edition 2
- Oracle WebLogic
- Oracle Java SE
conversion: 1 processor license = 2 OCPUs (or 8 ECPUs)
when_to_use:
- Existing Oracle on-prem licenses with active support
- Licenses not being used elsewhere
when_not_to_use:
- No existing licenses
- Licenses still needed for on-prem during migration
- Standard Edition workloads on ADB (ADB requires EE)
reserved_capacity:
name: Reserved Capacity
commitment: 1-year or 3-year for specific shapes
approx_discount:
one_year: ~35% off on-demand
three_year: ~55% off on-demand
when_to_use:
- Known compute shapes running 24/7
- Predictable database capacity
notes: Shape-specific, less flexible than Universal Credits
# ── ESTIMATION APPROACH ──────────────────────────────────────────
estimation_approach:
steps:
- Calculate PAYG cost first (baseline)
- Apply BYOL if customer has eligible licenses
- Show savings with Monthly Flex / Annual Flex for steady-state
- Compare total annual cost vs current on-prem spending
- Include migration costs in year 1
assumptions_to_state:
- Hours per month (730 for 24/7)
- Auto-scaling hours per day (estimate)
- Data transfer volumes (egress in particular)
- Backup retention policy
- Support tier (Premier vs Standard)
# ── DATABASE KNOWLEDGE ──────────────────────────────────────────
database:
billing_unit_change:
fact: ADB and most modern Oracle Database services bill in ECPUs, not OCPUs.
rule_of_thumb: 1 OCPU ≈ 4 ECPUs for sizing conversion.
note: When reading old datasheets or RFP documents, normalize to ECPU before quoting.
autonomous_database_serverless:
auto_scaling: Billed per ECPU-second for additional ECPUs above base. Same hourly rate as base ECPUs.
adg_standby: Standby ECPU cost at the same rate as primary. Storage shared (no extra storage charge).
backup: Automated backups included in storage cost. Manual backups use Object Storage rates.
sweet_spot: 4-32 ECPUs with auto-scaling. Below 4, consider Always Free. Above 128, consider ADB-D or ExaCS.
autonomous_database_dedicated:
x11m_elastic_model:
description: |
X11M is the current-generation Exadata infrastructure for ADB-D and
ExaCS (announced 2025). It uses elastic scaling instead of fixed
quarter / half / full racks.
configuration:
min_db_servers: 2
min_storage_servers: 3
max_db_servers: 32
max_storage_servers: 64
key_changes_vs_x9m:
- No fixed rack shapes — elastic scale in / out by server
- Hard minimum: 2 DB + 3 storage servers (cannot provision less)
- Per-second ECPU billing (was per-hour in older generations)
- Improved compute, storage density, RDMA throughput
pricing_caveat: |
Per-server line items exist in the OCI price list ('Database Server -
X11M', 'Storage Server - X11M') but the dollar amounts are not visible
in the public API. For estimation, use X9M quarter rack as a proxy
and confirm final pricing with the Oracle PDM / sales team.
legacy_x9m_model:
shapes:
- quarter_rack
- half_rack
- full_rack
note: Still available in some regions; new deployments default to X11M.
dbcs_editions:
SE: Standard Edition 2
EE: Enterprise Edition (base)
EE_HP: Enterprise Edition - High Performance (partitioning, advanced compression, etc.)
EE_EP: Enterprise Edition - Extreme Performance (RAC, Active Data Guard, In-Memory)
note: Backup storage is charged separately at Object Storage rates.
exacs_gotchas:
- Infrastructure cost is fixed regardless of ECPU utilization on X9M (rack-based).
- X11M elastic model bills by server, not by rack — scale in / out as needed.
- Provisioning takes 4-8 hours.
- Billing starts only at AVAILABLE state.
- For X11M, the public API does not expose infrastructure-rate dollar amounts — confirm with PDM.
exadata_cloud_at_customer:
note: Exadata infrastructure deployed in the customer datacenter, managed by Oracle.
same_ecpu_pricing_as: ExaCS Dedicated
database_migration_service:
free_period: First 183 days of an active migration are free.
backup_recovery:
autonomous_recovery_service: Per-GB protected per month, virtualized.
zdlra: Zero Data Loss variant — same model, slightly higher rate.
cost_comparison_vs_hyperscalers:
when_pitching_vs_aws_rds_or_azure_sqlmi:
include_in_comparison:
- OCI inbound data transfer is free
- OCI egress to internet is dramatically cheaper (~80% less than AWS after 10TB free)
- OCI BYOL discount is deeper than AWS BYOL
- ADB-S includes patching, tuning, indexing — RDS does not
- ADB now bills in ECPU (not OCPU) — 1 ECPU is a fraction of an OCPU
- Network LB is free per-hour on OCI
# ── NETWORKING KNOWLEDGE ────────────────────────────────────────
networking:
data_transfer:
ingress: Free (all sources)
egress_internet:
free_tier: First 10 TB / month is free
billing_after: Per-GB charge applies beyond free tier
inter_region: Per-GB charge (low)
fastconnect: Free in both directions (ingress AND egress)
competitive_advantage: |
OCI is dramatically cheaper than hyperscalers for data transfer:
- AWS: $0.09 / GB egress (OCI is ~10x cheaper after 10 TB free)
- Azure: $0.087 / GB egress
- GCP: $0.12 / GB egress
- OCI FastConnect egress is FREE (AWS DirectConnect charges per GB)
This is one of the strongest cost arguments when migrating data-intensive
workloads from AWS / Azure / GCP.
fastconnect:
note: Private dedicated connectivity. No data transfer charges.
port_speeds_available_in_api: [1, 2, 5, 10, 40, 100, 400] # Gbps
note_400gbps: 400 Gbps option is available; check oci-sku-catalog.yaml for current SKUs.
network_load_balancer:
cost_model: No per-hour charge (Layer 4). Data processing fees apply.
flexible_load_balancer:
cost_model: Base instance hourly + bandwidth per Mbps-hour. See oci-sku-catalog.yaml.
vpn_connect:
cost_model: No additional charge for IPSec VPN tunnels. Included with DRG.
dns:
free_tier: 1 million queries / month at no cost.
waf:
cost_model: Pricing based on requests processed. See oci-sku-catalog.yaml.
# ── STORAGE KNOWLEDGE ───────────────────────────────────────────
storage:
block_volume:
tier_model: |
OCI block volume tiers are configured via Volume Performance Units (VPU):
- Lower Cost: 0 VPU
- Balanced: 10 VPU (default)
- Higher Performance: 20 VPU
- Ultra High Performance (UHP): 30-120 VPU
The base storage SKU is the same across tiers; the difference is the
VPU multiplier on top. See oci-sku-catalog.yaml for the base storage
SKU and the VPU SKU.
boot_volume_free_tier: First 200 GB included with each compute instance.
backup_billing: Block volume backups have their own per-GB-month rate (lower than primary).
object_storage:
tiers:
standard: General-purpose, immediate access.
infrequent_access: Lower per-GB cost; retrieval fee applies.
archive: Lowest per-GB cost; standard retrieval is ~1 hour.
free_tier: 10 GB storage + 50,000 requests / month always free.
request_pricing: Separate per-10k-PUT and per-10k-GET charges.
file_storage:
note: Per-GB-month, higher rate than block volume.
high_performance_mount_target: Available for high-throughput workloads.
# ── OBSERVABILITY & MANAGEMENT KNOWLEDGE ────────────────────────
observability:
free_services:
- Cloud Guard (tenancy threat detection)
- Security Zones (compartment policy enforcement)
- Vulnerability Scanning (host + container image)
- Certificates (TLS certificate management)
- Bastion (managed SSH / RDP bastion)
- Vault (software keys; HSM is paid)
- OS Management Hub
- Java Management Service
- Autonomous Linux
- Resource Analytics
- Events service
- DevOps pipeline execution (compute / storage billed separately)
- Cluster management for OKE basic clusters
free_tiers:
monitoring:
ingestion: 500 million datapoints / month
retrieval: 1 billion datapoints / month
logging:
free_per_month: 10 GB
queue:
free_per_month: 1 million requests
functions:
invocations: 2 million / month
memory: 400,000 GB-seconds / month
notifications:
deliveries: 1 million / month
emails: 1,000 / month
ops_insights:
note: Basic and Autonomous tiers are free. Cloud-external (e.g. on-prem databases) is paid per OCPU-hour.
log_analytics:
unit: 1 storage unit = 300 GB.
full_stack_dr:
note: Orchestrates DR failover across compute, database, and networking. Billed per ECPU / OCPU hour.
# ── COMPUTE / CONTAINERS / SERVERLESS KNOWLEDGE ────────────────
compute_containers_serverless:
oke:
basic_cluster: Cluster management is free (control plane).
enhanced_cluster: Per-cluster hourly charge — adds virtual nodes, workload identity, etc.
worker_nodes: Billed at standard compute shape rates (see kb/pricing/compute.yaml).
virtual_nodes: Additional per-pod pricing on enhanced clusters.
container_instances:
billing: Billed at compute rates (OCPU / hour + GB memory / hour). No additional service charge.
shapes_available: [A1 (Arm), E3 (AMD), E4 (AMD), E5 (AMD), E6 (AMD)]
functions:
free_tier_strength: Very generous — most event-driven workloads stay in the free tier.
batch:
billing: Pay-as-you-go compute pricing, no additional service charge.
# ── INTEGRATION & MIDDLEWARE KNOWLEDGE ─────────────────────────
integration:
integration_cloud:
editions: [Standard, Enterprise]
billing_unit: Per 5,000 messages / hour band
api_management:
note: Per-API-call pricing is very low; most use cases trivially below $1 / million calls.
streaming:
note: Kafka-compatible. Billed per GB stored per hour + per GB transferred.
queue:
free_tier_strength: 1 million requests / month free, very cost-effective for decoupling.
goldengate:
billing: OCPU-hour. BYOL available.
use_case: Real-time data integration and replication.
soa_suite:
note: For legacy SOA workload migration. OCPU-hour billing.
# ── DEVELOPER SERVICES KNOWLEDGE ───────────────────────────────
developer:
apex:
free_tier: Yes — APEX free tier available for low-code development.
visual_builder:
note: Low-code app builder with included storage.
devops:
free: Pipeline execution itself is free; compute / memory billed separately.
blockchain:
note: OCPU-hour billing; storage charged separately.
iot:
billing_unit: ECPU-hour.
media_flow:
billing: Per-minute, varies by codec, resolution, and fps.
media_streams:
billing: Per-GB packaged.
# ── AI / ML KNOWLEDGE ──────────────────────────────────────────
ai_ml:
generative_ai_vendors_available:
- Cohere (Command, Embed)
- Meta Llama
- xAI Grok
- Google Gemini
generative_ai_billing_unit: Per 10K transactions or per 1M tokens (varies by vendor).
generative_ai_agents:
extra_costs: Plus storage and ingestion fees for agent knowledge bases.
data_science:
notebook_sessions: Billed at compute shape rates (OCPU / hour + GB memory / hour + GPU options).
jobs: Same compute pricing as notebook sessions.
model_deployment: Compute + networking + storage combined pricing.
model_catalog_storage: Object Storage rates.
anomaly_detection:
free_tier: Up to 100M data points / month per region.
document_understanding:
note: OCR billed per 1K transactions; custom training billed per training hour.
language_services:
note: Pretrained per-transaction billing; custom training available at additional cost.
vision:
note: Per-1K image analysis billing; custom training per hour.
speech:
note: Per-transcription-hour billing.
digital_assistant:
note: Per-request billing with a minimum throughput floor.
# ── SECURITY KNOWLEDGE ─────────────────────────────────────────
security:
free_services:
- Cloud Guard
- Security Zones
- Vulnerability Scanning
- Certificates
- Bastion
- Vault (software keys only — HSM keys are paid)
paid_services:
- Access Governance (per workforce / consumer user / month)
- Network Firewall (instance hours + data processed)
- Data Safe (per target / month + audit records)
- Vault (HSM-backed keys)
# ── HYBRID / EDGE KNOWLEDGE ────────────────────────────────────
hybrid:
vmware_solution:
note: Bare-metal nodes (BM.Standard2.12, BM.Standard3.16, BM.Standard.E4.32, BM.Standard.E5.48). Hourly to 3-year commitment ranges.
hcx_enterprise: Available for cross-cloud migration from on-prem vSphere; 1-month minimum commitment.
compute_cloud_at_customer:
note: OCI compute, storage, and load balancer in customer datacenter. E6 shapes available.
managed_mac:
note: Apple Mac instances (M2 Pro, M4 Pro) for iOS / macOS build pipelines.
roving_edge:
note: Portable compute / GPU / storage devices for edge and disconnected scenarios. Per-device-day billing.

View File

@@ -28,7 +28,7 @@ variants:
name: "Same-Region Autonomous Data Guard Standby"
topology: "Primary + Standby in same region via Autonomous Data Guard"
rpo: "0 (synchronous replication)"
rto: "< 30 seconds (automatic switchover)"
rto: "~2 minutes (automatic switchover)"
use_when:
- "Zero RPO mandatory"
- "Protection against full AD or FD failure"

View File

@@ -1,10 +1,8 @@
---
last_verified: 2026-03-18
pattern:
id: ecal-artefacts-catalog
name: "ECAL 3.1 Artefacts Catalog"
category: governance
---
description: >
Complete catalog of ECAL 3.1 artefacts across all 9 steps.

View File

@@ -1,69 +0,0 @@
---
last_verified: 2025-09-11
source: https://www.oracle.com/cloud/price-list/
description: OCI AI and Machine Learning service pricing.
currency: USD
---
# ── OCI Generative AI ─────────────────────────────────────────────
generative_ai:
cohere_models:
per_10k_transactions: 0.0001 - 0.0003
notes: "Command, Embed models"
meta_llama:
per_10k_transactions: 0.0001 - 0.0004
xai_grok:
per_1m_tokens_range: "$0.00015 $0.0018"
google_gemini:
per_1m_tokens_range: "$0.000075 $0.0006"
generative_ai_agents:
per_10k_transactions: 0.0001
notes: "Plus storage and ingestion fees"
# ── Anomaly Detection ─────────────────────────────────────────────
anomaly_detection:
training: "Free up to 100M data points/month per region"
# ── Data Science ───────────────────────────────────────────────────
data_science:
notebook_sessions:
notes: "Billed at compute shape rates (OCPU/hour + GB memory/hour + GPU options)"
jobs:
notes: "Same compute pricing as notebook sessions"
model_deployment:
notes: "Compute + networking + storage combined pricing"
model_catalog_storage:
notes: "Object Storage rates"
# ── Document Understanding ─────────────────────────────────────────
document_understanding:
training_per_hour: 0.50 - 1.00
ocr_per_1k_transactions: 0.025 - 0.050
# ── Language Services ──────────────────────────────────────────────
language:
pretrained_per_transaction: 0.0001 - 0.0003
custom_training: "Available at additional cost"
# ── Vision ─────────────────────────────────────────────────────────
vision:
image_analysis_per_1k: 0.0001 - 0.0003
custom_training_per_hour: 0.50 - 1.00
# ── Speech ─────────────────────────────────────────────────────────
speech:
per_transcription_hour: 0.0025 - 0.005
# ── Digital Assistant ──────────────────────────────────────────────
digital_assistant:
per_request: 0.009
minimum: "250 requests/hour"

View File

@@ -1,36 +0,0 @@
---
last_verified: 2025-09-11
source: https://www.oracle.com/cloud/price-list/
description: OCI Analytics and BI pricing.
currency: USD
---
# ── Oracle Analytics Cloud ─────────────────────────────────────────
oracle_analytics_cloud:
per_user_month:
professional: 0.99
enterprise: 2.00
ocpu_based:
notes: "Also available as OCPU-based pricing for embedded/API use"
# ── Essbase ────────────────────────────────────────────────────────
essbase:
ocpu_per_hour: 0.0252
# ── Data Lake / Big Data ──────────────────────────────────────────
ai_data_platform:
notes: "Pricing by AI Data Platform unit"
big_data_service_oracle:
ocpu_per_hour: 0.0252
notes: "Oracle distribution, includes Spark SQL compute"
big_data_service_cloudera:
ocpu_per_hour: 0.0168 - 0.0336
data_flow:
ocpu_usage: "Free"
notes: "Apache Spark, no charge for OCPU usage"

View File

@@ -1,191 +1,160 @@
---
last_verified: 2025-09-11
source: https://www.oracle.com/cloud/price-list/
description: OCI Compute pricing for estimation purposes.
Prices are approximate and subject to change. Always verify with
OCI pricing calculator for final quotes.
last_verified: '2026-04-08'
source: https://apexapps.oracle.com/pls/apex/cetools/api/v1/products/
description: OCI Compute pricing for estimation purposes. Auto-refreshed from the
Oracle public pricing API by tools/refresh_sku_catalog.py --refresh-domain compute.
GPU shapes, secure desktops, estimation_helpers, and discounts are NOT auto-refreshed.
currency: USD
---
# ── Virtual Machine Instances ──────────────────────────────────────
flexible_shapes:
VM.Standard.E6.Flex:
ocpu_per_hour: 0.0168
memory_per_gb_hour: 0.0011
ocpu_per_hour: 0.03
memory_per_gb_hour: 0.002
monthly_730h:
ocpu: 12.26
memory_per_gb: 0.80
notes: "AMD EPYC (latest gen), best price/performance for general workloads"
ocpu: 21.9
memory_per_gb: 1.46
notes: AMD EPYC (latest gen), best price/performance for general workloads
VM.Standard.E5.Flex:
ocpu_per_hour: 0.0210
memory_per_gb_hour: 0.0014
ocpu_per_hour: 0.03
memory_per_gb_hour: 0.002
monthly_730h:
ocpu: 15.33
memory_per_gb: 1.02
notes: "AMD EPYC, general-purpose workloads"
ocpu: 21.9
memory_per_gb: 1.46
notes: AMD EPYC, general-purpose workloads
VM.Standard.E4.Flex:
ocpu_per_hour: 0.0252
memory_per_gb_hour: 0.0017
ocpu_per_hour: 0.025
memory_per_gb_hour: 0.0015
monthly_730h:
ocpu: 18.40
memory_per_gb: 1.24
notes: "AMD EPYC (previous gen)"
ocpu: 18.25
memory_per_gb: 1.09
notes: AMD EPYC (previous gen)
VM.Standard.E3.Flex:
ocpu_per_hour: 0.0252
memory_per_gb_hour: 0.0017
ocpu_per_hour: 0.025
memory_per_gb_hour: 0.0015
monthly_730h:
ocpu: 18.40
memory_per_gb: 1.24
notes: "AMD EPYC (older gen)"
ocpu: 18.25
memory_per_gb: 1.09
notes: AMD EPYC (older gen)
VM.Standard3.Flex:
ocpu_per_hour: 0.0336
memory_per_gb_hour: 0.0022
monthly_730h:
ocpu: 24.53
memory_per_gb: 1.61
notes: "Intel Xeon, for Intel-optimized workloads"
notes: Intel Xeon, for Intel-optimized workloads
VM.Standard.A2.Flex:
ocpu_per_hour: 0.0254
memory_per_gb_hour: 0.0017
ocpu_per_hour: 0.014
memory_per_gb_hour: 0.002
monthly_730h:
ocpu: 18.54
memory_per_gb: 1.24
notes: "Ampere Arm (latest A2), best cost for Arm-compatible workloads"
ocpu: 10.22
memory_per_gb: 1.46
notes: Ampere Arm (latest A2), best cost for Arm-compatible workloads
VM.Standard.A1.Flex:
ocpu_per_hour: 0.0127
memory_per_gb_hour: 0.0008
monthly_730h:
ocpu: 9.27
memory_per_gb: 0.58
free_tier: "3,000 OCPU-hours + 18,000 GB-hours per month"
notes: "Ampere Arm A1, eligible for Always Free tier"
free_tier: 3,000 OCPU-hours + 18,000 GB-hours per month
notes: Ampere Arm A1, eligible for Always Free tier
VM.Standard.x86.Generic:
ocpu_per_hour: 0.0252
memory_per_gb_hour: 0.0017
notes: "Generic x86 pricing when specific shape not yet selected"
notes: Generic x86 pricing when specific shape not yet selected
VM.Optimized3.Flex:
ocpu_per_hour: 0.0504
memory_per_gb_hour: 0.0034
ocpu_per_hour: 0.054
memory_per_gb_hour: 0.0015
monthly_730h:
ocpu: 36.79
memory_per_gb: 2.48
notes: "Highest single-thread performance"
# ── Bare Metal Instances ───────────────────────────────────────────
ocpu: 39.42
memory_per_gb: 1.09
notes: Highest single-thread performance
bare_metal_shapes:
BM.Standard.E5:
ocpu_per_hour: 0.0168
notes: "AMD EPYC bare metal"
ocpu_per_hour: 0.03
notes: AMD EPYC bare metal
BM.Standard.E4:
ocpu_per_hour: 0.0210
notes: "AMD EPYC bare metal (previous gen)"
ocpu_per_hour: 0.025
notes: AMD EPYC bare metal (previous gen)
BM.Standard.E3:
ocpu_per_hour: 0.0420
notes: "AMD EPYC bare metal (older gen)"
ocpu_per_hour: 0.025
notes: AMD EPYC bare metal (older gen)
BM.Standard3:
ocpu_per_hour: 0.0504
notes: "Intel Xeon bare metal"
notes: Intel Xeon bare metal
BM.Standard.A1:
ocpu_per_hour: 0.0127
notes: "Ampere Arm bare metal"
notes: Ampere Arm bare metal
BM.Standard.x9:
ocpu_per_hour: 0.0672
notes: "Intel Xeon x9 bare metal"
# ── GPU Accelerated Compute ────────────────────────────────────────
ocpu_per_hour: 0.04
notes: Intel Xeon x9 bare metal
gpu_shapes:
# NVIDIA Blackwell (latest)
BM.GPU.B300:
per_gpu_hour: 26.88
gpu_count: 8
gpu_model: "NVIDIA B300"
notes: "Blackwell latest, HPC/AI training"
gpu_model: NVIDIA B300
notes: Blackwell latest, HPC/AI training
BM.GPU.B200:
per_gpu_hour: 20.16
gpu_count: 8
gpu_model: "NVIDIA B200"
notes: "Blackwell, large-scale training"
# NVIDIA Hopper
gpu_model: NVIDIA B200
notes: Blackwell, large-scale training
BM.GPU.H200:
per_gpu_hour: 18.54
gpu_count: 8
gpu_model: "NVIDIA H200"
notes: "Hopper H200, large model training"
gpu_model: NVIDIA H200
notes: Hopper H200, large model training
BM.GPU.H100:
per_gpu_hour: 12.96
gpu_count: 8
gpu_model: "NVIDIA H100"
notes: "Hopper H100, training workloads"
# NVIDIA Ampere / Ada
gpu_model: NVIDIA H100
notes: Hopper H100, training workloads
BM.GPU.A100:
per_gpu_hour: 6.72
gpu_count: 8
gpu_model: "NVIDIA A100 40GB/80GB"
notes: "Training and inference, 40GB or 80GB HBM2e"
gpu_model: NVIDIA A100 40GB/80GB
notes: Training and inference, 40GB or 80GB HBM2e
VM.GPU.A10.1:
per_gpu_hour: 0.72
gpu_count: 1
gpu_model: "NVIDIA A10"
notes: "Inference workloads, cost-effective"
gpu_model: NVIDIA A10
notes: Inference workloads, cost-effective
VM.GPU.A10.2:
per_gpu_hour: 0.72
gpu_count: 2
gpu_model: "NVIDIA A10"
notes: "Inference workloads"
gpu_model: NVIDIA A10
notes: Inference workloads
BM.GPU.L40S:
per_gpu_hour: 2.42
gpu_count: 4
gpu_model: "NVIDIA L40S"
notes: "Ada Lovelace, inference and graphics"
# ── Secure Desktops ───────────────────────────────────────────────
gpu_model: NVIDIA L40S
notes: Ada Lovelace, inference and graphics
secure_desktops:
per_desktop_month: 1750.00
notes: "Managed virtual desktop infrastructure"
# ── Estimation Helpers ─────────────────────────────────────────────
per_desktop_month: 1750.0
notes: Managed virtual desktop infrastructure
estimation_helpers:
typical_app_server:
config: "VM.Standard.E5.Flex, 4 OCPU, 64 GB"
monthly: 126.60 # (4 * 15.33) + (64 * 1.02)
config: VM.Standard.E5.Flex, 4 OCPU, 64 GB
monthly: 181.04
typical_web_server:
config: "VM.Standard.E5.Flex, 2 OCPU, 16 GB"
monthly: 46.98 # (2 * 15.33) + (16 * 1.02)
config: VM.Standard.E5.Flex, 2 OCPU, 16 GB
monthly: 67.16
typical_bastion:
config: "VM.Standard.E5.Flex, 1 OCPU, 8 GB"
monthly: 23.49 # (1 * 15.33) + (8 * 1.02)
config: VM.Standard.E5.Flex, 1 OCPU, 8 GB
monthly: 33.58
typical_arm_app_server:
config: "VM.Standard.A1.Flex, 4 OCPU, 24 GB"
monthly: 50.96 # (4 * 9.27) + (24 * 0.58)
config: VM.Standard.A1.Flex, 4 OCPU, 24 GB
monthly: 51.1
discounts:
preemptible: "~50% off on-demand"
capacity_reservation: "~15% off on-demand (85% of list)"
reserved_1yr: "~35% off on-demand"
reserved_3yr: "~55% off on-demand"
universal_credits: "Volume discounts on committed spend"
preemptible: ~50% off on-demand
capacity_reservation: ~15% off on-demand (85% of list)
reserved_1yr: ~35% off on-demand
reserved_3yr: ~55% off on-demand
universal_credits: Volume discounts on committed spend
os_pricing:
free:
- "Oracle Linux"
- "CentOS"
- "Ubuntu"
- "Oracle Autonomous Linux"
- Oracle Linux
- CentOS
- Ubuntu
- Oracle Autonomous Linux
paid:
windows_server:
notes: "Pricing varies by edition, added to compute cost"
notes: Pricing varies by edition, added to compute cost

View File

@@ -1,46 +0,0 @@
---
last_verified: 2025-09-11
source: https://www.oracle.com/cloud/price-list/
description: OCI Containers, Kubernetes, and Serverless pricing.
currency: USD
---
# ── Oracle Kubernetes Engine (OKE) ────────────────────────────────
oke:
basic_cluster:
per_hour: "Free"
notes: "Basic cluster management at no cost"
enhanced_cluster:
per_cluster_hour: 0.10
monthly_per_cluster: 73.00
notes: "Enhanced features: virtual nodes, workload identity, etc."
virtual_nodes:
notes: "Additional per-pod pricing on enhanced clusters"
worker_nodes:
notes: "Billed at standard compute shape rates"
# ── Container Instances ────────────────────────────────────────────
container_instances:
notes: "Billed at compute rates: OCPU/hour + GB memory/hour"
shapes_available:
- "A1 (Arm)"
- "E3 (AMD)"
- "E4 (AMD)"
# ── Functions (Serverless) ─────────────────────────────────────────
functions:
invocations:
free_per_month: 2000000
per_invocation_beyond: 0.0000002
memory:
free_gb_seconds_per_month: 400000
per_gb_second_beyond: 0.00001417
notes: "Generous free tier, very cost-effective for event-driven workloads"
# ── OCI Batch ──────────────────────────────────────────────────────
batch:
notes: "Pay-as-you-go compute pricing, no additional service charge"

View File

@@ -1,283 +0,0 @@
---
last_verified: 2025-09-11
source: https://www.oracle.com/cloud/price-list/
description: OCI Database Service pricing for estimation purposes.
currency: USD
disclaimer: |
Approximate pricing for estimation (within ~15%). Actual pricing varies by
region, commitment level, and negotiated discounts. Always verify against
https://www.oracle.com/cloud/pricing/
---
# ── Autonomous AI Database (Serverless) ───────────────────────────
# NOTE: ADB now uses ECPU billing model (not OCPU)
autonomous_database_serverless:
billing_unit: ECPU
license_included:
ecpu_per_hour: 0.0420
byol:
ecpu_per_hour: 0.0168
storage:
per_gb_month: 0.0850
per_tb_month: 87.04
auto_scaling:
notes: "Billed per ECPU-second for additional ECPUs above base. Same rate."
adg_standby:
notes: "Standby ECPU cost at same rate as primary. Storage shared (no extra)."
backup:
notes: "Automated backups included in storage cost. Manual backups use Object Storage rates."
examples:
8_ecpu_2tb_payg:
monthly_li: "$2,699"
monthly_byol: "$1,150"
breakdown: "8 ECPU × $0.0420/hr × 730hr + 2048GB × $0.0850"
8_ecpu_2tb_byol_with_adg:
monthly: "$2,300"
breakdown: "2 × (8 ECPU × $0.0168/hr × 730hr) + 2048GB × $0.0850"
# ── Autonomous AI JSON Database ────────────────────────────────────
autonomous_json_database:
billing_unit: ECPU
ecpu_per_hour: 0.0420
storage_per_gb_month: 0.0850
notes: "Same pricing as ADB-S, optimized for JSON document workloads"
# ── Autonomous Database Dedicated ──────────────────────────────────
autonomous_database_dedicated:
billing_unit: ECPU
infrastructure:
# X9M / X8M — fixed rack shapes (legacy, still available in some regions)
x9m:
quarter_rack:
base_per_hour: "~$10.50"
monthly_estimate: "$7,500$8,000"
included: "2 DB servers, 3 storage servers, 100TB usable"
half_rack:
base_per_hour: "~$21.00"
monthly_estimate: "$15,000$16,000"
included: "4 DB servers, 6 storage servers, 200TB usable"
full_rack:
base_per_hour: "~$42.00"
monthly_estimate: "$30,000$32,000"
included: "8 DB servers, 12 storage servers, 400TB usable"
# X11M — elastic scaling (new default as of 2025, replaces fixed rack shapes)
x11m:
model: "Elastic — 2 to 32 DB servers + 3 to 64 storage servers (no fixed rack shapes)"
minimum_config: "2 DB servers minimum (cannot order 1 DB server) + 3 storage servers"
billing: "Per ECPU per second (8-ECPU minimum per active DB VM)"
infrastructure_rate: "NOT PUBLICLY LISTED — requires OCI PDM/sales confirmation"
monthly_estimate: "Confirm with Oracle sales; X9M rates used as proxy for estimation"
notes: |
X11M is the current-generation Exadata infrastructure (announced 2025).
Key changes vs X9M:
- No fixed quarter/half/full rack — elastic scale in/out
- MINIMUM: 2 DB servers + 3 storage servers (cannot provision less)
- Infrastructure pricing parity with X9M (no premium) per Oracle comms,
but exact per-hour rates are not published in the public price list
- ECPU billing by the second (vs hourly in older generations)
- Improved compute, storage density, and RDMA throughput vs X9M
ecpu_pricing:
license_included_per_hour: 0.0672
byol_per_hour: 0.0504
notes: |
Infrastructure cost is fixed per rack size (X9M) or elastic per server (X11M). ECPU cost is on top.
DEP (Database Enterprise Patching) co-location is at next maintenance window.
Billing starts only at AVAILABLE state.
Provisioning takes days to weeks depending on capacity.
IMPORTANT: For X11M sizing, confirm infrastructure rates with PDM — use X9M as proxy only.
# ── Base Database Service (DBCS) ──────────────────────────────────
dbcs:
billing_unit: ECPU
license_included:
ecpu_per_hour_se: 0.0336 # Standard Edition
ecpu_per_hour_ee: 0.0420 # Enterprise Edition
ecpu_per_hour_ee_hp: 0.0504 # High Performance
ecpu_per_hour_ee_ep: 0.0672 # Extreme Performance — BYOL only on newer docs
byol:
ecpu_per_hour: 0.0168
storage_per_gb_month: 0.0255
notes: |
SE = Standard Edition, EE = Enterprise Edition,
HP = High Performance (partitioning, advanced compression, etc.),
EP = Extreme Performance (RAC, Active Data Guard, In-Memory).
Backup storage charged separately at Object Storage rates.
examples:
4_ecpu_ee_hp_500gb:
monthly_li: "$160"
breakdown: "4 ECPU × $0.0504/hr × 730hr + 500GB × $0.0255"
# ── Exadata Database Service Dedicated ─────────────────────────────
exadata_dedicated:
billing_unit: ECPU
infrastructure:
# X9M — fixed rack shapes (available in all regions)
x9m:
quarter_rack:
per_hour: 2.10
monthly_estimate: "$1,533"
half_rack:
per_hour: 6.30
monthly_estimate: "$4,599"
full_rack:
per_hour: 12.60
monthly_estimate: "$9,198"
# X11M — elastic scaling (current generation, replaces fixed rack shapes)
x11m:
model: "Elastic — 2 to 32 DB servers + 3 to 64 storage servers"
minimum_config: "2 DB servers + 3 storage servers (hard minimum — applies to ADB-D and ExaCS)"
billing: "Per ECPU per second (8-ECPU minimum per active DB VM)"
infrastructure_rate: "Line items exist in OCI price list ('Database Server - X11M' and 'Storage Server - X11M') but dollar amounts not visible without Oracle Cost Estimator or authenticated access"
proxy_for_estimation: "Use X9M quarter rack ($2.10/hr) as proxy for 2 DB + 3 storage"
notes: |
X11M is confirmed current-gen Exadata for both ExaCS and ADB-D on OCI.
MINIMUM: 2 DB servers + 3 storage servers — cannot provision less (verified against Oracle datasheets).
Per-server line items exist in price list but amounts require Oracle Cost Estimator or PDM quote.
Use X9M quarter rack ($2.10/hr infrastructure) as proxy for minimum config estimation.
ecpu_pricing:
license_included_per_hour: 0.0504
byol_per_hour: 0.0420
what_is_included:
- "Exadata smart storage (flash cache, storage indexes)"
- "Automated patching (GI + DB separate schedules)"
- "Automated backups to Object Storage"
- "RAC licensing included in Extreme Performance edition"
what_is_extra:
- "Data Guard setup and standby infrastructure"
- "Additional storage beyond rack capacity"
- "Object Storage for long-term backup retention"
gotchas:
- "Infrastructure cost is fixed regardless of ECPU utilization (X9M)."
- "X11M elastic model: scale in/out by server, not by rack."
- "Provisioning takes 4-8 hours."
- "X11M has improved storage density, RDMA throughput, and CPU vs X9M."
# ── Exadata Exascale ───────────────────────────────────────────────
exadata_exascale:
billing_unit: ECPU
ecpu_per_hour: 0.0504
storage:
notes: "Storage priced separately per Exascale vault capacity"
notes: "Elastic scaling of compute and storage independently. Next-gen Exadata."
# ── Exadata Cloud@Customer ─────────────────────────────────────────
exadata_cloud_at_customer:
billing_unit: ECPU
ecpu_pricing:
license_included_per_hour: 0.0504
byol_per_hour: 0.0420
infrastructure:
base_per_hour: 7.35
monthly_estimate: "$5,365"
notes: "Exadata infrastructure in customer datacenter, managed by Oracle"
# ── MySQL HeatWave ─────────────────────────────────────────────────
mysql_heatwave:
billing_unit: ECPU
ecpu_per_hour: 0.0180
storage_per_gb_month: 0.0085
heatwave_cluster:
notes: "Additional capacity pricing for HeatWave in-memory acceleration"
free_tier:
notes: "MySQL HeatWave Free Tier available with limits"
mysql_heatwave_on_aws:
ecpu_per_hour: 0.0180
notes: "Cross-cloud deployment, same base pricing"
# ── PostgreSQL ─────────────────────────────────────────────────────
postgresql:
ocpu_per_hour: 0.0168
storage_per_gb_month: 0.0850
notes: "Managed PostgreSQL, includes HA options"
# ── Cache with Redis ───────────────────────────────────────────────
cache_redis:
up_to_10gb:
per_gb_hour: 0.0194
monthly_per_gb: 14.16
above_10gb:
per_gb_hour: 0.0136
monthly_per_gb: 9.93
# ── OpenSearch ─────────────────────────────────────────────────────
opensearch:
per_node_hour: 0.0252
notes: "HA configuration, pricing per node"
# ── NoSQL Database ─────────────────────────────────────────────────
nosql:
provisioned:
storage_per_gb_month: 0.0085
write_unit_per_month: 0.0001
read_unit_per_month: 0.000020
on_demand:
storage_per_gb_month: 0.0085
notes: "Auto-scaled read/write units"
free_tier:
storage_gb: 25
write_units: 50
read_units: 50
max_tables: 3
# ── TimesTen for OKE ──────────────────────────────────────────────
timesten:
x86_ocpu_per_hour: 0.0252
arm_ocpu_per_hour: 0.0168
notes: "In-memory relational database deployed on Kubernetes"
# ── Data Safe ──────────────────────────────────────────────────────
data_safe:
per_target_month: 0.0150
audit_records_per_10k_month: 0.0001
# ── Database Migration ─────────────────────────────────────────────
database_migration:
per_migration_hour: 0.0420
notes: "First 183 days free if migration is active"
# ── Database Autonomous Recovery ───────────────────────────────────
database_autonomous_recovery:
per_gb_virtualized_month: 0.0085
notes: "Autonomous backup recovery service"
# ── GoldenGate ─────────────────────────────────────────────────────
goldengate:
ocpu_per_hour: 0.0252
byol_available: true
notes: "Real-time data integration and replication"
# ── Estimation Helpers ─────────────────────────────────────────────
estimation_helpers:
monthly_hours: 730
byol_savings: "50-60% on ECPU cost for Oracle Database products"
adb_s_sweet_spot: "4-32 ECPUs with auto-scaling. Below 4, consider Always Free. Above 128, consider ADB-D or ExaCS."
cost_comparison_tip: |
When comparing with AWS RDS or Azure SQL MI, include:
- OCI inbound data transfer is free
- OCI outbound is ~80% cheaper than AWS
- OCI BYOL discount is deeper than AWS BYOL
- ADB-S includes patching, tuning, indexing — RDS does not
- ADB now uses ECPU (not OCPU) — 1 ECPU ≈ fraction of an OCPU
reserved_discounts:
one_year: "~35-40% vs PAYG"
three_year: "~55-65% vs PAYG"
notes: "Available for all database services. Commitment is per-region."

View File

@@ -1,59 +0,0 @@
---
last_verified: 2025-09-11
source: https://www.oracle.com/cloud/price-list/
description: OCI Developer Services pricing.
currency: USD
---
# ── APEX Application Development ──────────────────────────────────
apex:
ecpu_per_hour: 0.36
free_tier: true
notes: "Low-code development platform, free tier available"
# ── Visual Builder ─────────────────────────────────────────────────
visual_builder:
ocpu_per_hour: 0.0252
notes: "Low-code app builder with storage"
# ── DevOps ─────────────────────────────────────────────────────────
devops:
pipeline_execution: "Free"
notes: "No charge for pipeline execution; compute/memory billed separately"
# ── Blockchain Platform ───────────────────────────────────────────
blockchain:
ocpu_per_hour: 0.0252 - 0.0504
notes: "Plus storage costs"
# ── IoT Platform ──────────────────────────────────────────────────
iot:
ecpu_per_hour: 0.0360
notes: "Plus storage costs"
# ── Media Flow ─────────────────────────────────────────────────────
media_flow:
per_minute: 0.005 - 0.120
notes: "Varies by codec, resolution, and fps"
# ── Media Streams ──────────────────────────────────────────────────
media_streams:
per_gb_packaged: 0.015
# ── Tuxedo ─────────────────────────────────────────────────────────
tuxedo:
ocpu_per_hour: 0.0252 - 0.0504
notes: "For legacy Tuxedo workload migration"
# ── WebCenter ──────────────────────────────────────────────────────
webcenter:
ocpu_per_hour: 0.0252 - 0.0504

View File

@@ -1,53 +0,0 @@
---
last_verified: 2025-09-11
source: https://www.oracle.com/cloud/price-list/
description: OCI Hybrid Cloud and VMware Solution pricing.
currency: USD
---
# ── Oracle Cloud VMware Solution (OCVS) ───────────────────────────
vmware_solution:
base_nodes:
BM.Standard2.12:
per_node_hour: 2.10 - 4.20
notes: "Hourly to 3-year commitment range"
BM.Standard3.16:
per_node_hour: 3.03 - 6.06
BM.Standard.E4.32:
per_node_hour: 4.20 - 8.40
BM.Standard.E5.48:
per_node_hour: 4.99 - 9.98
expansion:
ocpu_per_hour: 0.0168 - 0.0420
notes: "Commitment-based pricing"
hcx_enterprise:
ocpu_per_hour: 0.0084
minimum_commitment: "1 month"
gpu_storage_nodes:
per_node_hour: 2.10 - 4.20
notes: "Commitment-based pricing"
# ── Compute Cloud@Customer ─────────────────────────────────────────
compute_cloud_at_customer:
e6_compute:
ocpu_per_hour: 0.0336 - 0.0504
storage:
per_gb_month: 0.0085 - 0.0170
load_balancer:
per_hour: 0.10
# ── Managed Service for Mac ────────────────────────────────────────
managed_mac:
per_server_hour:
m2_pro: 1.20
m4_pro: 4.20
notes: "Range depends on Mac model (M2 Pro to M4 Pro)"
# ── Roving Edge Infrastructure ─────────────────────────────────────
roving_edge:
per_device_day: 300 - 1000
notes: "Portable compute/GPU/storage for edge and disconnected scenarios"

View File

@@ -1,55 +0,0 @@
---
last_verified: 2025-09-11
source: https://www.oracle.com/cloud/price-list/
description: OCI Integration and Middleware pricing.
currency: USD
---
# ── Integration Cloud ─────────────────────────────────────────────
integration_cloud:
per_5k_messages_hour: 0.36 - 0.72
notes: "Standard and Enterprise editions"
# ── API Management ─────────────────────────────────────────────────
api_management:
per_api_call: 0.0000005
monthly_1m_calls: 0.50
notes: "Very low cost per call"
# ── Data Integration ───────────────────────────────────────────────
data_integration:
workspace_per_hour: 0.0252
data_processed_per_gb_hour: 0.0252
# ── Data Integrator ────────────────────────────────────────────────
data_integrator:
ocpu_per_hour: 0.0252
# ── Streaming (Kafka compatible) ──────────────────────────────────
streaming:
storage_per_gb_hour: 0.025
data_transfer_per_gb: 0.025
streaming_with_kafka:
ocpu_per_hour: 0.0252
# ── Queue ──────────────────────────────────────────────────────────
queue:
free_per_month: 1000000 # requests
per_request_beyond: 0.0000005
notes: "1M free requests/month, very cost-effective for decoupling"
# ── SOA Suite ──────────────────────────────────────────────────────
soa_suite:
ocpu_per_hour: 0.0504 - 0.0672
notes: "For legacy SOA workload migration"
# ── GoldenGate ─────────────────────────────────────────────────────
# See database.yaml for GoldenGate pricing

View File

@@ -1,70 +0,0 @@
---
last_verified: 2025-09-11
source: https://www.oracle.com/cloud/price-list/
description: OCI Networking pricing for estimation purposes.
currency: USD
---
# ── Load Balancing ─────────────────────────────────────────────────
load_balancer:
base_instance_per_hour: 0.10
bandwidth_per_mbps_hour: 0.0084
monthly_base: 73.00
notes: "Flexible shape, bandwidth billed separately"
network_load_balancer:
per_hour: "Free"
notes: "Layer 4, no per-hour charge, data processing fees apply"
# ── FastConnect ────────────────────────────────────────────────────
fastconnect:
port_per_hour:
1gbps: 0.30
2gbps: 0.50
5gbps: 1.26
10gbps: 2.52
40gbps: 5.04
100gbps: 6.30
400gbps: 12.60
monthly_730h:
1gbps: 219.00
10gbps: 1839.60
100gbps: 4599.00
data_transfer: "Free (ingress and egress)"
notes: "Private dedicated connectivity. No data transfer charges."
# ── VPN Connect ────────────────────────────────────────────────────
vpn_connect:
notes: "No additional charge for IPSec VPN tunnels. Included with DRG."
# ── DNS ────────────────────────────────────────────────────────────
dns:
queries_included_per_month: 1000000
additional: "Free for most use cases"
notes: "1M queries/month included at no cost"
# ── WAF ────────────────────────────────────────────────────────────
waf:
notes: "Pricing based on requests processed. See OCI price list for current rates."
# ── Data Transfer Summary ──────────────────────────────────────────
data_transfer:
ingress: "Free (all sources)"
egress_internet:
first_10tb_month: "Free"
per_gb_beyond: 0.0085
inter_region:
per_gb: 0.0085
fastconnect: "Free (both directions)"
key_advantage: |
OCI is dramatically cheaper than hyperscalers for data transfer:
- AWS charges $0.09/GB egress (OCI: $0.0085 after 10TB free)
- Azure charges $0.087/GB egress
- GCP charges $0.12/GB egress
- OCI FastConnect egress is FREE (AWS DirectConnect charges per GB)

View File

@@ -1,89 +0,0 @@
---
last_verified: 2025-09-11
source: https://www.oracle.com/cloud/price-list/
description: OCI Observability and Management pricing.
currency: USD
---
# ── Monitoring ─────────────────────────────────────────────────────
monitoring:
ingestion:
free_per_month: 500000000 # 500M datapoints
per_datapoint_beyond: 0.00002
retrieval:
free_per_month: 1000000000 # 1B datapoints
per_datapoint_beyond: 0.00002
notes: "Very generous free tier for most workloads"
# ── Logging ────────────────────────────────────────────────────────
logging:
free_per_month_gb: 10
per_gb_month_beyond: 0.0050
notes: "10 GB/month free, very affordable"
# ── Log Analytics ──────────────────────────────────────────────────
log_analytics:
per_storage_unit_month: 2.50 - 5.00
storage_unit_size_gb: 300
notes: "1 storage unit = 300 GB"
# ── Notifications ──────────────────────────────────────────────────
notifications:
free_per_month:
deliveries: 1000000
emails: 1000
per_operation_beyond: 0.00001
per_email_beyond: 0.00001
# ── Events ─────────────────────────────────────────────────────────
events:
notes: "No additional charge for Events service"
# ── APM / Application Performance Monitoring ──────────────────────
apm:
notes: "Pricing based on data ingestion volume and synthetic monitors"
# ── Database Management ────────────────────────────────────────────
database_management:
ecpu_per_hour: 0.0360
notes: "Fleet-level database monitoring and management"
# ── Ops Insights ───────────────────────────────────────────────────
ops_insights:
basic: "Free"
autonomous: "Free"
cloud_external:
ocpu_per_hour: 0.0420
notes: "Basic and Autonomous tiers are free"
# ── Email Delivery ─────────────────────────────────────────────────
email_delivery:
per_1k_emails: 0.00001 - 0.000015
# ── Full Stack Disaster Recovery ───────────────────────────────────
full_stack_dr:
ecpu_per_hour: 0.0360
ocpu_per_hour: 0.0420
notes: "Orchestrates DR failover across compute, database, and networking"
# ── Fleet Application Management ──────────────────────────────────
fleet_app_management:
per_managed_resource_month: 3.00 - 7.50
# ── OS & Java Management ──────────────────────────────────────────
os_management_hub: "Free"
java_management_service: "Free"
autonomous_linux: "Free"
resource_analytics: "Free"

File diff suppressed because it is too large Load Diff

View File

@@ -1,83 +0,0 @@
---
last_verified: 2025-09-11
source: https://www.oracle.com/cloud/price-list/
description: OCI pricing models and discount structures.
---
models:
payg:
name: "Pay As You Go"
commitment: none
discount: none
billing: "Per second (compute), per hour (database), per month (storage)"
when_to_use:
- "Variable/unpredictable workloads"
- "Short-term projects"
- "Dev/test environments"
- "Initial cloud adoption (before committing)"
monthly_flex:
name: "Monthly Flex (Universal Credits)"
commitment: "Minimum $1,000/month or custom commitment"
discount: "Volume discounts on committed spend"
billing: "Committed credits consumed by usage"
when_to_use:
- "Steady-state production workloads"
- "Known baseline consumption"
- "Multiple services across OCI"
discount_tiers:
- spend: "$1K-$10K/month"
discount: "~5-10%"
- spend: "$10K-$50K/month"
discount: "~10-20%"
- spend: "$50K+/month"
discount: "~20-30% (negotiated)"
annual_flex:
name: "Annual Flex (Committed)"
commitment: "1-year or 3-year commitment"
discount: "Deeper discounts than monthly flex"
when_to_use:
- "Established production workloads with predictable spend"
- "Organizations committed to OCI long-term"
byol:
name: "Bring Your Own License"
discount: "~50% on database OCPU costs"
eligible:
- "Oracle Database Enterprise Edition"
- "Oracle Database Standard Edition 2"
- "Oracle WebLogic"
- "Oracle Java SE"
conversion: "1 processor license = 2 OCPUs"
when_to_use:
- "Existing Oracle on-prem licenses with active support"
- "Licenses not being used elsewhere"
when_NOT_to_use:
- "No existing licenses"
- "Licenses still needed for on-prem during migration"
- "Standard Edition workloads on ADB (requires EE)"
reserved_capacity:
name: "Reserved Capacity"
commitment: "1-year or 3-year for specific shapes"
discount:
1_year: "~35% off on-demand"
3_year: "~55% off on-demand"
when_to_use:
- "Known compute shapes running 24/7"
- "Predictable database capacity"
notes: "Shape-specific, less flexible than Universal Credits"
estimation_approach:
step_1: "Calculate PAYG cost first (baseline)"
step_2: "Apply BYOL if customer has eligible licenses"
step_3: "Show savings with Monthly Flex / Annual Flex for steady-state"
step_4: "Compare total annual cost vs current on-prem spending"
step_5: "Include migration costs in year 1"
assumptions_to_state:
- "Hours per month (730 for 24/7)"
- "Auto-scaling hours per day (estimate)"
- "Data transfer volumes"
- "Backup retention"
- "Support tier"

View File

@@ -1,56 +0,0 @@
---
last_verified: 2025-09-11
source: https://www.oracle.com/cloud/price-list/
description: OCI Security service pricing.
currency: USD
---
# ── Access Governance ──────────────────────────────────────────────
access_governance:
premium:
workforce_user_month: 0.0018 - 0.0036
consumer_user_month: 0.36
for_oracle_workloads:
workforce_user_month: 0.0009 - 0.0018
consumer_user_month: 0.36
for_oci:
workforce_user_month: 0.00009 - 0.00018
# ── Vault ──────────────────────────────────────────────────────────
vault:
notes: "Key management — see OCI price list for current rates. Free tier for software keys."
# ── Cloud Guard ────────────────────────────────────────────────────
cloud_guard:
notes: "Free for OCI tenancy monitoring and threat detection"
# ── Security Zones ─────────────────────────────────────────────────
security_zones:
notes: "Free — policy enforcement on compartments"
# ── Vulnerability Scanning ─────────────────────────────────────────
vulnerability_scanning:
notes: "Free — host and container image scanning"
# ── Certificates ───────────────────────────────────────────────────
certificates:
notes: "Free — TLS certificate management"
# ── Bastion ────────────────────────────────────────────────────────
bastion:
notes: "Free — managed SSH/RDP bastion service"
# ── Network Firewall ──────────────────────────────────────────────
network_firewall:
notes: "Pricing based on instance hours and data processed"
# ── Data Safe ──────────────────────────────────────────────────────
# See database.yaml for Data Safe pricing

View File

@@ -1,60 +0,0 @@
---
last_verified: 2025-09-11
source: https://www.oracle.com/cloud/price-list/
description: OCI Storage pricing for estimation purposes.
currency: USD
---
block_volume:
balanced:
per_gb_month: 0.0255
per_tb_month: 26.11
higher_performance:
per_gb_month: 0.0340
per_tb_month: 34.82
lower_cost:
per_gb_month: 0.0170
per_tb_month: 17.41
uhp:
notes: "Priced per VPU, varies by configuration"
boot_volume:
free_tier: "200 GB included"
additional: "Same as block volume pricing"
backup:
per_gb_month: 0.0050
object_storage:
standard:
per_gb_month: 0.0255
per_tb_month: 26.11
infrequent_access:
per_gb_month: 0.0100
per_tb_month: 10.24
archive:
per_gb_month: 0.0026
per_tb_month: 2.66
api_requests:
per_10k_put: 0.0040
per_10k_get: 0.0003
free_tier:
storage_gb: 10
requests: 50000
file_storage:
per_gb_month: 0.0340
per_tb_month: 34.82
data_transfer:
ingress: "Free"
egress_internet:
first_10tb_month: "Free"
per_gb_after: 0.0085
inter_region:
per_gb: 0.0085
fastconnect:
ingress: "Free"
egress: "Free"
notes: |
OCI egress pricing is significantly cheaper than AWS/Azure/GCP.
First 10 TB/month internet egress is free.
FastConnect egress is free (no per-GB charge).

View File

@@ -20,15 +20,18 @@ features:
ha_dr_options:
local_ha: "Built-in TAC (Transparent Application Continuity) — ~0 perceived RTO"
same_region_adg: "Autonomous Data Guard standby — synchronous, RPO 0"
cross_region_adg: "Cross-region ADG — asynchronous only, RPO seconds, RTO < 15 min"
cross_region_adg: "Cross-region ADG — asynchronous only, RPO seconds (switchover RPO 0, manual failover RPO up to 1 min), RTO < 10 min"
cross_region_auto_failover: "NOT available — cross-region requires manual switchover/failover only"
limits:
max_ocpu: 128
max_storage_tb: 383
max_auto_scale: "3x base OCPUs"
max_ecpu: 512
max_ocpu_legacy: 128
max_storage_tb: 384
max_auto_scale: "3x base ECPUs"
auto_scale_activation: "2-3 minutes"
min_ocpu: 1
min_ecpu: 2
min_storage_tb: 1
notes: "ECPU is now the default billing unit. 4 ECPUs ≈ 1 OCPU. OCPU billing is legacy."
variants:
- id: adb_s
@@ -66,12 +69,14 @@ when_not_to_use:
sizing:
adb_s:
min_ocpu: 1
max_ocpu: 128
auto_scaling: "Up to 3x base OCPUs (takes 2-3 minutes to activate)"
sizing_guidance: "Size base OCPUs for P75 sustained load, not P50. Auto-scaling covers peaks but has activation latency."
min_ecpu: 2
max_ecpu: 512
min_ocpu_legacy: 1
max_ocpu_legacy: 128
auto_scaling: "Up to 3x base ECPUs (takes 2-3 minutes to activate)"
sizing_guidance: "Size base ECPUs for P75 sustained load, not P50. Auto-scaling covers peaks but has activation latency. 4 ECPUs ≈ 1 OCPU."
storage_min_tb: 1
storage_max_tb: 383
storage_max_tb: 384
iops: "Proportional to OCPU count, Exadata storage servers"
adb_d:
@@ -105,9 +110,9 @@ gotchas:
severity: MEDIUM
description: "Cross-region Autonomous Data Guard is async only (RPO > 0). For zero RPO, need same-region standby or ADB-D with local Data Guard."
- id: adb_19c_only
- id: adb_version
severity: LOW
description: "ADB currently runs Oracle 19c. If customer needs 23ai features, verify availability."
description: "ADB now defaults to Oracle 26ai in all commercial regions. 19c is legacy. Verify customer version requirements."
implied_dependencies:
- service: service_gateway

View File

@@ -1,8 +1,11 @@
---
last_verified: 2026-03-14
last_verified: 2026-04-24
service: OCI Compute
category: compute
oci_color: "#4F7B6E"
changelog:
- date: "2026-04-24"
change: "Added missing shapes surfaced by discover+WebFetch: VM/BM.Standard.E6.Ax, VM/BM.Standard.A4.Ax, and full X12 family (VM.Standard4.Ax.Flex 39 OCPU / 360 GB, BM.Standard4.Ax.120 latest-gen bare metal). Verified against docs.oracle.com/en-us/iaas/Content/Compute/References/computeshapes.htm."
---
what: Virtual machines and bare metal instances. Flexible shapes allow custom
@@ -11,9 +14,16 @@ what: Virtual machines and bare metal instances. Flexible shapes allow custom
shape_families:
- name: VM.Standard.E5.Flex
processor: "AMD EPYC 9J14 (Genoa)"
max_ocpu: 94
max_ocpu: 126
memory_per_ocpu_gb: "1-64 GB per OCPU"
use_for: "General purpose, most workloads"
- name: VM.Standard.E6.Flex
processor: "AMD EPYC 9J45 (Turin)"
max_ocpu: 126
max_memory_gb: 1454
memory_per_ocpu_gb: "1-64 GB per OCPU"
network_gbps: 99
use_for: "Latest generation general purpose"
- name: VM.Standard3.Flex
processor: "Intel Xeon (Ice Lake)"
max_ocpu: 32
@@ -21,14 +31,70 @@ shape_families:
use_for: "Intel-optimized workloads"
- name: VM.Standard.A2.Flex
processor: "Ampere Altra (Arm)"
max_ocpu: 80
max_ocpu: 78
memory_per_ocpu_gb: "1-64 GB per OCPU"
use_for: "Arm-compatible workloads, cost optimization"
- name: VM.Standard.A4.Flex
processor: "Arm"
max_ocpu: 45
max_memory_gb: 700
network_gbps: 100
use_for: "Latest Arm generation, cloud-native workloads"
- name: VM.Optimized3.Flex
processor: "Intel Xeon (Ice Lake)"
max_ocpu: 18
memory_per_ocpu_gb: "1-64 GB per OCPU"
use_for: "High-frequency trading, HPC"
- name: VM.Standard.E6.Ax.Flex
processor: "AMD EPYC (Ampere-branded E6 variant)"
max_ocpu: 94
max_memory_gb: 712
network_gbps: 99
use_for: "E6 Ampere-variant general purpose"
- name: VM.Standard.A4.Ax.Flex
processor: "Arm (A4 Ampere-branded variant)"
max_ocpu: 45
max_memory_gb: 720
network_gbps: 100
use_for: "A4 Ampere-variant Arm workloads"
- name: VM.Standard4.Ax.Flex
processor: "AMD EPYC (X12 Ampere-branded)"
max_ocpu: 39
max_memory_gb: 360
network_gbps: 99
use_for: "X12-generation general purpose (latest)"
- name: BM.Standard.E5
processor: "AMD EPYC 9J14 (Genoa)"
ocpus: 192
use_for: "Bare metal general purpose"
- name: BM.Standard.E6
processor: "AMD EPYC 9J45 (Turin)"
ocpus: 256
use_for: "Bare metal latest generation"
- name: BM.Standard.E6.Ax.192
processor: "AMD EPYC (E6 Ampere-branded variant)"
ocpus: 192
max_memory_gb: 1536
network_gbps: 200
use_for: "Bare metal E6 Ampere-variant"
- name: BM.Standard.A4.48
processor: "Arm (A4)"
ocpus: 48
max_memory_gb: 768
network_gbps: 100
use_for: "Bare metal A4 Arm general purpose"
- name: BM.Standard.A4.Ax.48
processor: "Arm (A4 Ampere-branded variant)"
ocpus: 48
max_memory_gb: 768
network_gbps: 100
use_for: "Bare metal A4 Ampere-variant Arm"
- name: BM.Standard4.Ax.120
processor: "AMD EPYC (X12 Ampere-branded)"
ocpus: 120
max_memory_gb: 1152
network_gbps: 200
use_for: "Bare metal X12 latest generation"
- name: VM.GPU.A10.1
processor: "NVIDIA A10"
gpu_count: 1
@@ -37,6 +103,38 @@ shape_families:
processor: "NVIDIA H100 (8 GPUs)"
gpu_count: 8
use_for: "AI/ML training, large model inference"
- name: BM.GPU.H200.8
processor: "NVIDIA H200 (8 GPUs)"
gpu_count: 8
use_for: "AI/ML training, large model inference (higher memory bandwidth)"
- name: BM.GPU.B200.8
processor: "NVIDIA B200 (8 GPUs)"
gpu_count: 8
use_for: "Next-gen AI training and inference"
- name: BM.GPU.B300.8
processor: "NVIDIA B300 (8 GPUs)"
gpu_count: 8
use_for: "Next-gen AI training and inference"
- name: BM.GPU.GB200.4
processor: "NVIDIA GB200 (4 GPUs)"
gpu_count: 4
use_for: "Grace Blackwell superchip, AI training"
- name: BM.GPU.GB300.4
processor: "NVIDIA GB300 (4 GPUs)"
gpu_count: 4
use_for: "Grace Blackwell next-gen AI"
- name: BM.GPU.MI300X.8
processor: "AMD Instinct MI300X (8 GPUs)"
gpu_count: 8
use_for: "AMD GPU AI/ML workloads"
- name: BM.GPU.MI355X.8
processor: "AMD Instinct MI355X (8 GPUs)"
gpu_count: 8
use_for: "AMD GPU next-gen AI/ML workloads"
- name: BM.GPU.L40S.4
processor: "NVIDIA L40S (4 GPUs)"
gpu_count: 4
use_for: "AI inference, graphics, video"
when_to_use:
- Traditional VM-based applications

View File

@@ -30,12 +30,14 @@ when_NOT_to_use:
limits:
vm_shapes:
- "VM.Standard.E5.Flex: 1-94 OCPUs"
- "VM.Standard.E5.Flex: 1-64 OCPUs"
- "VM.Standard3.Flex: 1-32 OCPUs"
- "VM.Standard.x86: ECPU billing (new shape)"
bm_shapes:
- "BM.Standard.E5: 128 OCPUs"
- "BM.DenseIO.E5: 128 OCPUs with NVMe"
max_storage_tb: 80 # block storage
max_storage_tb: 150 # block storage (Universal Credits)
supported_versions: ["19c", "21c", "23ai", "26ai"]
rac_max_nodes: 2
features:

View File

@@ -27,15 +27,18 @@ limits:
- name: "Exadata.Quarter3.100"
base_ocpu: 100
max_ocpu: 100
storage_tb: 49.5
storage_tb: 149
notes: "Legacy X8 fixed shape — storage is usable disk"
- name: "Exadata.Half3.200"
base_ocpu: 200
max_ocpu: 200
storage_tb: 99
storage_tb: 299
notes: "Legacy X8 fixed shape"
- name: "Exadata.Full3.400"
base_ocpu: 400
max_ocpu: 400
storage_tb: 198
storage_tb: 598
notes: "Legacy X8 fixed shape; current generation is elastic X9M/X11M"
max_vm_clusters: 8
max_databases_per_cluster: "Limited by resources"
max_pdb_per_cdb: 252

View File

@@ -1,5 +1,5 @@
# OCI Service: Exadata Cloud Service (ExaCS)
# Last verified: 2026-03
# Last verified: 2026-04
service:
name: "Exadata Cloud Service (ExaCS)"
@@ -26,32 +26,122 @@ variants:
- id: exacs_x9m
name: "ExaCS X9M"
description: "Exadata X9M shape — current-generation infrastructure with RDMA over Converged Ethernet and persistent memory acceleration."
- id: exacs_x10m
name: "ExaCS X10M"
description: "Exadata X10M shape — next-generation infrastructure with improved compute, storage density, and throughput."
per_db_server:
ocpus: 126
memory_gb: 1390
pmem_tb: 1.5
flash_cache_tb: 25.6
per_storage_server:
usable_tb: 63.6
- id: exacs_x11m
name: "ExaCS X11M"
description: "Exadata X11M shape — latest generation with AMD EPYC processors and XRMEM acceleration. Two storage server variants: HC (default, capacity-optimised) and EF (Extreme Flash, latency-optimised)."
per_db_server:
ecpus: 760
memory_gb: 1390
xrmem_gb: 1250
flash_cache_tb: 27.2
cpu: "2 × AMD EPYC 9J25 (96 cores each, 192 cores per server)"
storage_server_variants:
hc:
name: "X11M High Capacity (HC)"
description: "Default storage variant. 12 × 22 TB SAS HDDs + 27.2 TB flash cache + 1.25 TB XRMEM per SS. Best $/TB; same hot-data latency as EF (served from flash cache + XRMEM)."
raw_tb_per_ss: 264
flash_cache_tb_per_ss: 27.2
xrmem_tb_per_ss: 1.25
usable_disk_tb_per_ss: 80 # Datasheet "Total Usable Disk Capacity" per SS — post HIGH redundancy + drive-failure reserve, before compression
max_db_size_tb_per_ss_no_local_backup: 64 # Derived: 192 TB / 3 SS at base config (datasheet Elastic Example 1)
max_db_size_tb_per_ss_with_local_backup: 32 # Derived: 96 TB / 3 SS at base config
total_cores_per_ss: 64
recommended_for: "OLTP, mixed workloads, DWH where active set fits in flash cache (~80% of cases)"
ef:
name: "X11M Extreme Flash (EF)"
description: "All-flash storage variant. Lower latency on cache-miss reads, but higher $/TB. Use when the working set exceeds flash cache or for latency-sensitive DWH full scans."
usable_tb_per_ss: 52.5
type: "Extreme Flash (EF)"
recommended_for: "Latency-sensitive DWH with large full-table scans that miss flash cache; sub-ms consistent latency requirements"
pricing_2026_04:
source: "OCI Cost Estimator 2026-04-23"
db_server_per_hour_usd: 2.9032
storage_server_per_hour_usd: 2.9032
base_config_monthly_usd: 10800 # (2 DB + 3 SS) × $2.9032 × 744 hr; excludes DB licenses (BYOL) and ECPU charges
sizing:
rack_configurations:
quarter_rack:
ocpus: "100 (scalable)"
memory: "1.44 TB"
storage: "Up to 76.8 TB usable (Exadata Storage)"
db_nodes: 2
model: "Elastic per-server (X9M+: 2-32 DB servers, 3-64 storage servers). 'Quarter/half/full rack' terminology is legacy; X9M and X11M are billed per-server."
notes: |
Three different storage figures appear in Oracle datasheets — they measure different things:
• Total Usable Disk Capacity = ASM-allocatable space, post HIGH redundancy + drive-failure reserve, before compression
• Max DB Size No Local Backup = practical limit for DB allocation after RECO/SPARSE/DBFS reserves (this is what OCI Cost Estimator caps at)
• Max DB Size With Local Backup = ~half of above (FRA on disk for backups)
Always quote both Usable Disk and Max DB Size to avoid customer confusion.
OCI scales storage by adding individual storage servers, not in racks.
base_configuration:
description: "Minimum elastic configuration — what you get on day-1 before scaling."
db_servers: 2
storage_servers: 3
x11m_elastic_base:
description: "Datasheet 'Elastic Configuration Example 1' (2 DB + 3 SS, all-elastic SKUs)."
source: "ADB-D X11M Datasheet v1.0, Jan 2025, Table 1"
db_servers: 2
storage_servers: 3
total_ecpus: 1520 # 2 × 760
total_memory_gb: 2780 # 2 × 1,390
total_xrmem_tb: 3.75 # 3 × 1.25 (XRMEM lives on storage servers)
total_flash_tb: 81.6 # 3 × 27.2
hc_variant:
total_usable_disk_tb: 240 # Datasheet authoritative
max_db_size_no_local_backup_tb: 192 # OCI Cost Estimator caps allocation here
max_db_size_with_local_backup_tb: 96
max_sql_flash_bandwidth_gbps: 300
max_sql_xrmem_bandwidth_gbps: 1500
max_sql_disk_bandwidth_gbps: 5.4
max_sql_read_iops: 5_600_000
max_sql_write_iops: 3_000_000
max_sql_disk_iops: 7_800
max_data_load_rate_tb_per_hr: 7.5
ef_variant:
usable_tb: 157.5 # 3 × 52.5
sample_elastic_growth_examples:
compute_heavy: { db_servers: 8, storage_servers: 8, total_ecpus: 6080, max_db_size_tb: 512 }
storage_heavy: { db_servers: 2, storage_servers: 14, total_ecpus: 1520, max_db_size_tb: 896 }
x11m_base_system:
description: "Hardware-generation-agnostic 'Base System' SKU — fixed-spec, NOT expandable, single VM Cluster only. Different product from elastic; entry-price option for small footprints."
source: "ADB-D X11M Datasheet v1.0, Jan 2025, Table 1, footnote 1"
db_servers: 2
storage_servers: 3
total_ecpus: 192
total_memory_gb: 720
total_flash_tb: 38.4
total_usable_disk_tb: 73
max_db_size_no_local_backup_tb: 58
max_db_size_with_local_backup_tb: 29
network: "10 GbE (vs 50 GbE on elastic)"
notes: "Base System is NOT the same as 'Elastic Example 1 with 2 DB + 3 SS'. The elastic config has ~8× more ECPUs, ~4× more memory, ~3× more storage at same physical-server count, and 50 GbE networking. Base System is for cost-optimised entry; if customer expects to scale, go elastic from day 1."
x9m_base:
cpu_ocpus: 252 # 2 × 126
memory_tb: 2.71 # 2 × 1,390 GB
pmem_tb: 3.0 # 2 × 1.5 (persistent memory tier)
flash_cache_tb_db: 51.2 # 2 × 25.6
hc_variant:
usable_tb_per_ss: 63.6
base_usable_tb_high_redundancy: 190.8 # 3 × 63.6
notes: "X9M HC drives are 14 TB (vs 22 TB on X11M)."
legacy_x8_fixed_shapes:
quarter_rack:
storage_tb: 149
half_rack:
ocpus: "200 (scalable)"
memory: "2.88 TB"
storage: "Up to 153.6 TB usable"
db_nodes: 4
storage_servers: 6
storage_tb: 299
full_rack:
ocpus: "400 (scalable)"
memory: "5.76 TB"
storage: "Up to 307.2 TB usable"
db_nodes: 8
storage_servers: 12
ocpu_scaling: "OCPUs can be scaled online in increments without downtime. You pay for enabled OCPUs, not the total available in the rack."
sizing_guidance: "Start with a quarter rack for most production workloads. Scale OCPUs on demand. Choose half/full rack only when storage capacity or aggregate memory requirements exceed quarter rack limits."
storage_tb: 598
notes: "X8 shapes are fixed-size (not elastic). Storage values are usable disk, not flash cache."
ocpu_scaling: "OCPUs/ECPUs can be scaled online in increments without downtime. You pay for enabled cores, not the total available in the rack."
sizing_guidance: "Start with the elastic base (2 DB + 3 SS) for most production workloads. Add storage servers when capacity or IOPS exceed base. Add DB servers when CPU saturates. Choose HC over EF unless workload is latency-sensitive on cache-miss reads."
gotchas:
- id: exacs_minimum_cost
@@ -78,6 +168,10 @@ gotchas:
severity: LOW
description: "ExaCS requires placement in a private subnet with sufficient IP addresses. Each DB node and each virtual IP consumes an IP; plan your subnet CIDR accordingly."
- id: exacs_x11m_hc_vs_ef
severity: MEDIUM
description: "X11M ships in two storage variants — HC (default, 264 TB raw / SS) and EF (all-flash, 52.5 TB usable / SS). Most customers should choose HC: same hot-data latency (served from 27.2 TB flash cache per SS) at far better $/TB. Only pick EF when the working set genuinely exceeds flash cache and you need sub-ms consistent latency on cache-miss reads. Many quotes default to EF without justification — confirm with the customer."
implied_dependencies:
- service: vcn
reason: "ExaCS infrastructure must be deployed in a VCN"
@@ -99,3 +193,9 @@ changelog:
- date: "2026-03-14"
contributor: { name: "Diego Cabrera", team: "Field Architecture" }
change: "Initial creation with shapes, sizing, gotchas, dependencies"
- date: "2026-04-23"
contributor: { name: "Diego Velásquez", team: "Field Architecture" }
change: "Added X11M HC variant (default) alongside existing EF; replaced misleading rack_configurations table that mixed X9M data with elastic per-server model; added X11M and X9M base configs; added pricing verified against OCI Cost Estimator (DB+SS @ $2.9032/hr); added gotcha on HC vs EF default choice."
- date: "2026-04-23"
contributor: { name: "Diego Velásquez", team: "Field Architecture" }
change: "Replaced earlier estimator-derived storage figures (63 TB/SS, 190 TB at base) with authoritative numbers from ADB-D X11M Datasheet v1.0 Jan 2025 Table 1. X11M HC SS = 80 TB Total Usable Disk (HIGH redundancy + drive-failure reserve). 3-SS Elastic base = 240 TB Total Usable Disk OR 192 TB Max DB Size (no local backup, what the Estimator caps at) OR 96 TB Max DB Size (with local backup). Also added separate Base System SKU (fixed, non-expandable, 73 TB usable disk) — distinct product from elastic 2 DB + 3 SS. Added performance metrics (IOPS, GB/s) for elastic base."

View File

@@ -22,6 +22,7 @@ components:
recommendation: "Prefer NSGs (Network Security Groups) for granular control"
nsg:
what: "Network Security Group — firewall rules at VNIC level"
max_rules: "120 (ingress + egress combined per NSG)"
recommendation: "Preferred over security lists for micro-segmentation"
internet_gateway:
what: "Enables internet access for public subnets"
@@ -45,7 +46,7 @@ components:
connectivity:
fastconnect:
what: "Dedicated private connection to OCI (like AWS Direct Connect)"
speeds: ["1 Gbps", "2 Gbps", "5 Gbps", "10 Gbps", "100 Gbps"]
speeds: ["1 Gbps", "2 Gbps", "5 Gbps", "10 Gbps", "100 Gbps", "400 Gbps"]
redundancy: "Always deploy 2 circuits for HA"
notes: "Partner or co-location model, typical setup takes 2-4 weeks"
ipsec_vpn:

View File

@@ -22,8 +22,9 @@ services:
iops_per_gb: 75
throughput_kbps_per_gb: 600
- name: Ultra High Performance
max_iops: 450000
max_iops: 300000
max_throughput_mbps: 2680
notes: "IOPS range 75K-300K at 30-120 VPU"
max_volume_size_tb: 32
max_volumes_per_instance: 32
@@ -36,7 +37,7 @@ services:
use_for: "Data accessed less than once per month"
- name: Archive
use_for: "Long-term retention, compliance"
retrieval_time: "1 hour (standard), 1 minute (expedited)"
retrieval_time: "1 hour (standard)"
features:
- "S3-compatible API"
- "Versioning"
@@ -49,7 +50,7 @@ services:
what: "NFSv3-compatible managed file system"
use_for: "Shared file access across multiple compute instances"
max_size: "8 EB (exabytes)"
iops: "Up to 25,000 IOPS per file system"
iops: "Up to 50,000 IOPS per file system"
throughput: "Up to 1.2 GB/s per mount target"
pricing:

View File

@@ -4,9 +4,10 @@ description: ADB-S auto-scaling behavior, timing, and sizing implications.
---
auto_scaling:
notes: "OCPU is legacy billing. ECPU is now default. 1 OCPU ≈ 4 ECPUs."
ocpu_scaling:
trigger: "CPU demand exceeds current allocation"
max_scale: "3x base OCPUs (up to 128 OCPU maximum)"
max_scale: "3x base OCPUs/ECPUs (up to 128 OCPU / 512 ECPU maximum)"
ramp_up_time: "2-3 minutes to begin scaling"
ramp_down_time: "After sustained low utilization (5-10 minutes)"
billing: "Only billed during active scaling period, per OCPU per second"

View File

@@ -65,8 +65,8 @@ adb_s_sizing:
memory_sizing:
oci_shapes:
standard_e4: "16 GB per OCPU (VM.Standard.E4.Flex)"
standard_e5: "16 GB per OCPU (VM.Standard.E5.Flex)"
standard_e5: "up to 64 GB per OCPU (VM.Standard.E5.Flex, default 16)"
standard_a1: "6 GB per OCPU (VM.Standard.A1.Flex / Ampere)"
standard_a2: "8 GB per OCPU (VM.Standard.A2.Flex / Ampere)"
standard_a2: "up to 64 GB per OCPU (VM.Standard.A2.Flex / Ampere)"
optimized3: "14 GB per OCPU (VM.Optimized3.Flex)"
dense_io_e4: "32 GB per OCPU + local NVMe (VM.DenseIO.E4.Flex)"

View File

@@ -21,18 +21,19 @@ block_volume:
- name: "Higher Performance"
iops_per_gb: 75
max_iops: 35000
max_iops: 50000
throughput_mbps_per_gb: 0.6
max_throughput_mbps: 480
max_throughput_mbps: 680
use_when: "Database data files, high-throughput applications"
- name: "Ultra High Performance"
iops_per_gb: 90
max_iops: 120000
max_iops: 300000
iops_range: "75,000 - 300,000 (at 30-120 VPU)"
throughput_mbps_per_gb: 0.72
max_throughput_mbps: 2680
use_when: "Extreme IOPS requirements, OLTP databases"
notes: "Only available with certain compute shapes"
notes: "Only available with certain compute shapes. IOPS scales with VPU (30-120)."
sizing_guidance: |
1. Determine required IOPS (from AWR, CloudWatch, or application benchmarks)

View File

@@ -33,14 +33,14 @@ storage_tiers:
block_volume_higher_performance:
type: "Block Volume (Higher Performance)"
iops_per_gb: 75
max_iops: 35000
max_iops: 50000
throughput_kbps_per_gb: 600
max_throughput_mbps: 600
max_throughput_mbps: 680
latency_us: "Sub-millisecond"
block_volume_uhp:
type: "Block Volume (Ultra High Performance)"
max_iops: 450000
max_iops: 300000
max_throughput_mbps: 2680
notes: "Requires UHP-enabled shapes"
@@ -53,7 +53,7 @@ storage_tiers:
file_storage:
type: "File Storage (NFS)"
max_iops: 25000
max_iops: 50000
max_throughput_mbps: 1200
latency: "Sub-millisecond"
use_for: "Shared file access, NFS workloads"

82
scripts/sync-skill.py Normal file
View File

@@ -0,0 +1,82 @@
#!/usr/bin/env python3
"""
Sync SKILL.md (root, source of truth) to .agents/skills/oci-deal-accelerator/SKILL.md.
The Codex copy under .agents/ must be byte-identical to the root SKILL.md
except for an auto-generated banner inserted after the YAML frontmatter.
Usage:
python scripts/sync-skill.py # write the .agents/ copy
python scripts/sync-skill.py --check # exit 1 if out of sync (for CI/lint)
"""
import argparse
import os
import sys
PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
SOURCE = os.path.join(PROJECT_ROOT, "SKILL.md")
TARGET = os.path.join(
PROJECT_ROOT, ".agents", "skills", "oci-deal-accelerator", "SKILL.md"
)
BANNER = (
"<!-- AUTO-GENERATED FROM /SKILL.md — do not edit directly. "
"Run `python scripts/sync-skill.py` to regenerate. -->\n"
)
def render() -> str:
"""Read root SKILL.md and return the .agents/ version with banner injected."""
with open(SOURCE, "r", encoding="utf-8") as fh:
content = fh.read()
# Inject banner after the closing `---` of the YAML frontmatter, if present.
if content.startswith("---\n"):
end = content.find("\n---\n", 4)
if end != -1:
head = content[: end + len("\n---\n")]
tail = content[end + len("\n---\n") :]
return head + "\n" + BANNER + tail
# No frontmatter — prepend banner.
return BANNER + content
def cmd_check() -> int:
expected = render()
if not os.path.isfile(TARGET):
print(f"sync-skill: target missing: {TARGET}")
return 1
with open(TARGET, "r", encoding="utf-8") as fh:
actual = fh.read()
if actual == expected:
print("sync-skill: OK (in sync)")
return 0
print("sync-skill: OUT OF SYNC")
print(f" source: {SOURCE}")
print(f" target: {TARGET}")
print(" run: python scripts/sync-skill.py")
return 1
def cmd_write() -> int:
expected = render()
os.makedirs(os.path.dirname(TARGET), exist_ok=True)
with open(TARGET, "w", encoding="utf-8") as fh:
fh.write(expected)
print(f"sync-skill: wrote {os.path.relpath(TARGET, PROJECT_ROOT)} "
f"({len(expected.splitlines())} lines)")
return 0
def main() -> int:
parser = argparse.ArgumentParser(description="Sync root SKILL.md to .agents/")
parser.add_argument("--check", action="store_true",
help="Exit 1 if out of sync; do not write.")
args = parser.parse_args()
return cmd_check() if args.check else cmd_write()
if __name__ == "__main__":
sys.exit(main())

View File

@@ -371,8 +371,8 @@ def main():
)
parser.add_argument(
"--profile",
required=True,
help="Path to workload profile YAML",
default=None,
help="Path to workload profile YAML (optional; defaults to minimal profile)",
)
parser.add_argument(
"--architecture",
@@ -381,8 +381,8 @@ def main():
)
parser.add_argument(
"--output",
default="scorecard-output.yaml",
help="Output scorecard file path",
default=None,
help="Output scorecard file path (default: print to stdout)",
)
parser.add_argument(
"--format",
@@ -393,7 +393,15 @@ def main():
args = parser.parse_args()
if args.profile:
profile = load_yaml(args.profile)
else:
profile = {
"workload_profile": {
"flags": {},
"business_context": {"customer_name": "Unknown"},
}
}
architecture = load_yaml(args.architecture)
customer = (
@@ -414,10 +422,11 @@ def main():
else:
output = yaml.dump(scorecard, default_flow_style=False, sort_keys=False)
if args.output:
with open(args.output, "w") as f:
f.write(output)
# Print summary
# Print summary to terminal when output goes to file
sc = scorecard["well_architected_scorecard"]
print(f"\nOCI Well-Architected Scorecard")
print(f"{'=' * 50}")
@@ -431,6 +440,8 @@ def main():
for pid, p in sc["pillars"].items():
print(f" {pid}: {p['status']} ({p['checks_passed']}/{p['checks_total']})")
print(f"\nScorecard written to: {args.output}")
else:
print(output)
if __name__ == "__main__":

184
scripts/validate-diagram.py Normal file
View File

@@ -0,0 +1,184 @@
#!/usr/bin/env python3
"""
Diagram quality validator — checks generated .drawio files against
Oracle Architecture Center visual standards.
Usage:
python3 scripts/validate-diagram.py examples/output-demo-pharma-mx/opt02-architecture.drawio
"""
import sys
import xml.etree.ElementTree as ET
MIN_ICON_H = 45 # Minimum icon height (px) — Oracle refs use 50-60
MIN_ICON_W = 30 # Minimum icon width (px)
MAX_EMPTY_RATIO = 0.7 # Max empty space ratio in a container
MIN_LABEL_FONT = 10 # Minimum label font size
MIN_GAP_PX = 5 # Minimum gap between sibling elements
def validate(filepath: str) -> list:
"""Return list of (severity, message) tuples."""
issues = []
tree = ET.parse(filepath)
root = tree.getroot()
icon_groups = []
containers = []
all_cells = {}
for cell in root.iter('mxCell'):
cid = cell.get('id', '')
style = cell.get('style', '')
value = cell.get('value', '')
geo = cell.find('mxGeometry')
all_cells[cid] = cell
if geo is None:
continue
w = float(geo.get('width', 0))
h = float(geo.get('height', 0))
x = float(geo.get('x', 0))
y = float(geo.get('y', 0))
# Icon groups
if 'group' in style and 'connectable=1' in style:
icon_groups.append({
'id': cid, 'x': x, 'y': y, 'w': w, 'h': h,
'parent': cell.get('parent', ''),
})
if h < MIN_ICON_H:
issues.append(('WARN', f'Icon {cid} too short: {h:.0f}px (min {MIN_ICON_H})'))
if w < MIN_ICON_W:
issues.append(('WARN', f'Icon {cid} too narrow: {w:.0f}px (min {MIN_ICON_W})'))
# Containers (regions, VCNs, subnets)
if value and any(kw in value for kw in ['Region', 'VCN', 'Subnet', 'Oracle Cloud']):
containers.append({
'id': cid, 'name': value[:40], 'x': x, 'y': y, 'w': w, 'h': h,
'parent': cell.get('parent', ''),
})
# Check children overflow parents
container_map = {}
for cell in root.iter('mxCell'):
cid = cell.get('id', '')
val = cell.get('value', '')
geo = cell.find('mxGeometry')
if geo is not None and val:
container_map[cid] = {
'name': val[:50], 'x': float(geo.get('x', 0)),
'y': float(geo.get('y', 0)), 'w': float(geo.get('width', 0)),
'h': float(geo.get('height', 0)), 'parent': cell.get('parent', ''),
}
for cid, c in container_map.items():
parent = container_map.get(c['parent'])
if parent:
child_right = c['x'] + c['w']
child_bottom = c['y'] + c['h']
overflow_r = child_right - parent['w']
overflow_b = child_bottom - parent['h']
if overflow_r > 2:
issues.append(('ERROR', f'{c["name"]} overflows {parent["name"]} RIGHT by {overflow_r:.0f}px'))
if overflow_b > 2:
issues.append(('ERROR', f'{c["name"]} overflows {parent["name"]} BOTTOM by {overflow_b:.0f}px'))
# Check for overlapping siblings (same parent)
by_parent = {}
for ig in icon_groups:
by_parent.setdefault(ig['parent'], []).append(ig)
for parent_id, siblings in by_parent.items():
siblings.sort(key=lambda s: (s['y'], s['x']))
for i in range(len(siblings) - 1):
a = siblings[i]
b = siblings[i + 1]
# Check vertical overlap (same column, x ranges overlap)
x_overlap = not (a['x'] + a['w'] < b['x'] or b['x'] + b['w'] < a['x'])
if x_overlap:
gap = b['y'] - (a['y'] + a['h'])
if gap < MIN_GAP_PX:
issues.append(('ERROR', f'Overlap between icons in parent {parent_id}: gap={gap:.0f}px'))
# Check container utilization (warn on mostly empty containers)
for cont in containers:
children_area = 0
for ig in icon_groups:
if ig['parent'] == cont['id']:
children_area += ig['w'] * ig['h']
for child_cont in containers:
if child_cont['parent'] == cont['id']:
children_area += child_cont['w'] * child_cont['h']
cont_area = cont['w'] * cont['h']
if cont_area > 0:
fill_ratio = children_area / cont_area
if fill_ratio < (1 - MAX_EMPTY_RATIO):
issues.append(('INFO', f'{cont["name"]}: {fill_ratio:.0%} filled ({cont["w"]:.0f}x{cont["h"]:.0f})'))
# Check edge labels have offset (mxPoint as="offset")
edges_with_label = 0
edges_with_offset = 0
for cell in root.iter('mxCell'):
if cell.get('edge') == '1' and cell.get('value', '').strip():
edges_with_label += 1
geo = cell.find('mxGeometry')
if geo is not None:
offset = geo.find('.//mxPoint[@as="offset"]')
if offset is not None:
edges_with_offset += 1
if edges_with_label > 0 and edges_with_offset < edges_with_label:
issues.append(('WARN', f'{edges_with_label - edges_with_offset}/{edges_with_label} edge labels missing offset'))
# Check jettySize=auto present
has_jetty = False
for cell in root.iter('mxCell'):
if 'jettySize=auto' in cell.get('style', ''):
has_jetty = True
break
if not has_jetty:
issues.append(('WARN', 'No edges with jettySize=auto'))
# Check container=1 present
has_container = False
for cell in root.iter('mxCell'):
if 'container=1' in cell.get('style', ''):
has_container = True
break
if not has_container:
issues.append(('WARN', 'No containers with explicit container=1 style'))
return issues
def main():
if len(sys.argv) < 2:
print(f"Usage: {sys.argv[0]} <diagram.drawio>")
sys.exit(1)
filepath = sys.argv[1]
issues = validate(filepath)
if not issues:
print(f"{filepath}: All checks passed")
sys.exit(0)
errors = [i for i in issues if i[0] == 'ERROR']
warns = [i for i in issues if i[0] == 'WARN']
infos = [i for i in issues if i[0] == 'INFO']
print(f"📋 Diagram validation: {filepath}")
print(f" {len(errors)} errors, {len(warns)} warnings, {len(infos)} info")
print()
for severity, msg in issues:
icon = {'ERROR': '', 'WARN': '⚠️', 'INFO': ''}.get(severity, '?')
print(f" {icon} [{severity}] {msg}")
sys.exit(1 if errors else 0)
if __name__ == "__main__":
main()

Binary file not shown.

51
templates/bom-spec.yaml Normal file
View File

@@ -0,0 +1,51 @@
# ──────────────────────────────────────────────────────────────────
# OCI Bill of Materials (BOM) — Spec Template
# ──────────────────────────────────────────────────────────────────
# The AI generates this YAML based on the customer's request,
# selecting only the relevant SKUs from kb/pricing/oci-sku-catalog.yaml.
# The BOM generator tool (tools/oci_bom_gen.py) renders it to .xlsx.
#
# Usage:
# python tools/oci_bom_gen.py --spec this-file.yaml --output bom.xlsx
bom:
# ── Header ──────────────────────────────────────────────────────
customer_name: ""
project_name: ""
prepared_by: ""
date: "" # ISO format: 2026-03-27
reference_label: "" # e.g., "ACME-BOM-001"
currency: USD # Primary currency
# realm: "OC1 - Commercial" # Optional: OC1 / OC2 / OC3 / OC9
# service_type: "Pay as You Go" # Optional: PAYG / UCM / Annual Flex
# ── Optional currency conversion ────────────────────────────────
# Enable to add converted columns (e.g., USD → BRL with tax)
conversion:
enabled: false
target_currency: BRL
exchange_rate: 5.75 # 1 USD = X target currency
tax_rate: 0.0 # e.g., 0.1385 for 13.85% ISS+PIS+COFINS
# ── Line items (only requested services) ────────────────────────
# Each item must reference a SKU from oci-sku-catalog.yaml.
# Only include services the customer actually needs.
line_items:
- sku: "B97384" # Must match oci-sku-catalog.yaml
qty: 4 # Number of instances/units
# hours_units: 730 # Override catalog default if needed
months: 12 # Contract duration
discount: 0.0 # 0.0 to 1.0 (e.g., 0.30 = 30%)
# custom_label: "" # Optional label
# custom_note: "" # Optional note
- sku: "B97385"
qty: 64 # 64 GB memory
months: 12
discount: 0.0
# ── Notes (optional) ────────────────────────────────────────────
notes:
- "Pricing based on Ashburn region (OC1)"
- "Discounts subject to Oracle approval"
- "Hours convention — 730 vs 744: this BOM uses 730 hrs/month (= 8,760 annual hrs / 12), which equals the actual yearly OCI billing for hourly SKUs. OCI Cost Estimator defaults to 744 hrs/month (worst-case 31-day month); extrapolated to 12 months, 744 overstates the real annual cost by 1.92%. For 12-month TCO/proposals, 730 is the accurate figure; 744 is only appropriate when quoting a single peak month as an upper bound."

View File

@@ -151,12 +151,13 @@ class TestKBLinter:
# (like 'cli', 'maintenance-window', etc.)
def test_owner_check(self):
"""Owner check returns issues for TBD owners."""
"""Owner check returns a list and matches the current owners config."""
issues = kb_linter.check_owners()
assert isinstance(issues, list)
# We know some owners are TBD
tbd_issues = [i for i in issues if "TBD" in i]
assert len(tbd_issues) > 0, "Expected TBD owner issues"
# Current config may be fully assigned; if issues exist they should be
# the explicit TBD-owner messages emitted by the linter.
for issue in issues:
assert "TBD" in issue
def test_freshness_check(self):
"""Freshness check returns a list of file freshness reports."""
@@ -207,34 +208,44 @@ class TestKBCLI:
# Service changelog tests
# ---------------------------------------------------------------------------
class TestServiceChangelogs:
"""Verify that service files have changelog sections."""
"""Verify that service files load correctly and validate changelogs when present."""
@pytest.fixture(scope="class")
def service_files(self):
services_dir = KB_DIR / "services"
return list(services_dir.glob("*.yaml"))
@staticmethod
def _load_service_yaml(filepath):
merged = {}
with open(filepath, "r", encoding="utf-8") as fh:
for doc in yaml.safe_load_all(fh):
if isinstance(doc, dict):
merged.update(doc)
return merged
def test_service_files_exist(self, service_files):
assert len(service_files) > 0
def test_service_files_have_changelog(self, service_files):
"""Each service file should have a changelog section."""
def test_service_files_load_as_merged_documents(self, service_files):
"""Service files may be multi-document YAML and should load via safe_load_all."""
for filepath in service_files:
with open(filepath, "r") as fh:
data = yaml.safe_load(fh)
assert "changelog" in data, (
f"Service file '{filepath.name}' missing 'changelog' section"
)
assert len(data["changelog"]) > 0, (
f"Service file '{filepath.name}' has empty changelog"
data = self._load_service_yaml(filepath)
assert isinstance(data, dict), f"Service file '{filepath.name}' did not merge into a dict"
assert any(key in data for key in ("service", "description", "swagger_ui", "kb_target_file")), (
f"Service file '{filepath.name}' is missing an identifying top-level key"
)
def test_changelog_entries_have_required_fields(self, service_files):
"""Changelog entries must have date, contributor, change."""
"""Changelog entries must have date, contributor, change when a changelog exists."""
changelog_files = 0
for filepath in service_files:
with open(filepath, "r") as fh:
data = yaml.safe_load(fh)
data = self._load_service_yaml(filepath)
if "changelog" not in data:
continue
changelog_files += 1
for entry in data.get("changelog", []):
assert "date" in entry, f"Changelog entry in {filepath.name} missing 'date'"
assert "contributor" in entry, f"Changelog entry in {filepath.name} missing 'contributor'"
assert "change" in entry, f"Changelog entry in {filepath.name} missing 'change'"
assert changelog_files > 0, "Expected at least one service file with changelog entries"

View File

@@ -0,0 +1,83 @@
import sys
from pathlib import Path
PROJECT_ROOT = Path(__file__).resolve().parent.parent
TOOLS_DIR = PROJECT_ROOT / "tools"
if str(TOOLS_DIR) not in sys.path:
sys.path.insert(0, str(TOOLS_DIR))
from oci_bizcase_gen import BusinessCaseDeckGenerator
def _collect_slide_text(gen):
texts = []
for slide in gen.prs.slides:
for shape in slide.shapes:
if hasattr(shape, "text"):
text = shape.text.strip()
if text:
texts.append(text)
if getattr(shape, "has_table", False):
for row in shape.table.rows:
for cell in row.cells:
text = cell.text.strip()
if text:
texts.append(text)
return "\n".join(texts)
def test_from_spec_accepts_cover_aliases_and_recommendation_fallback():
spec = {
"customer": "Acme Corp",
"author": "Diego",
"generated_on": "2026-04-21",
"recommendation": {
"commitment_amount": "100K",
"commitment_type": "UCM",
},
}
gen = BusinessCaseDeckGenerator.from_spec(spec)
text = _collect_slide_text(gen)
assert "Acme Corp" in text
assert "Prepared by: Diego" in text
assert "Recommended: 100K UCM commitment" in text
def test_from_spec_accepts_roadmap_aliases_and_mixed_next_steps():
spec = {
"customer_name": "Acme Corp",
"roadmap": {
"phases": [
{
"title": "Assess",
"weeks": "2 weeks",
"outputs": ["Blueprint"],
"milestones": ["Kickoff"],
}
],
"total_duration": "6 weeks",
},
"recommendation": {
"summary": "Proceed with phased migration",
"next_steps": [
"Confirm scope",
{"action": "Approve budget", "owner": "Finance", "deadline": "May"},
],
},
}
gen = BusinessCaseDeckGenerator.from_spec(spec)
text = _collect_slide_text(gen)
assert "Assess" in text
assert "2 weeks" in text
assert "Kickoff" in text
assert "Blueprint" in text
assert "Confirm scope" in text
assert "Approve budget" in text
assert "Finance" in text
assert "May" in text

View File

@@ -0,0 +1,80 @@
import sys
from pathlib import Path
import pytest
PROJECT_ROOT = Path(__file__).resolve().parent.parent
TOOLS_DIR = PROJECT_ROOT / "tools"
if str(TOOLS_DIR) not in sys.path:
sys.path.insert(0, str(TOOLS_DIR))
from oci_bom_gen import OCIBomGenerator
def test_from_spec_accepts_metadata_and_line_item_aliases():
spec = {
"customer": "Acme Corp",
"project": "Database Migration",
"author": "Diego",
"reference": "REF-1",
"conversion": {
"currency": "BRL",
"exchange_rate": 5.2,
"tax_rate": 0.1,
},
"line_items": [
{
"part_number": "SKU-001",
"quantity": 2,
"units": 730,
"discount_pct": 15,
"label": "Database",
"note": "Primary environment",
}
],
}
gen = OCIBomGenerator.from_spec(spec)
item = gen.line_items[0]
assert gen.customer == "Acme Corp"
assert gen.project == "Database Migration"
assert gen.prepared_by == "Diego"
assert gen.reference_label == "REF-1"
assert gen.conversion["target_currency"] == "BRL"
assert item["sku"] == "SKU-001"
assert item["qty"] == 2
assert item["hours_units"] == 730
assert item["discount"] == 15
assert item["custom_label"] == "Database"
assert item["custom_note"] == "Primary environment"
def test_from_spec_accepts_canonical_sku_and_custom_note():
spec = {
"line_items": [
{
"sku": "SKU-002",
"qty": 1,
"hours_units": 100,
"custom_note": "Canonical form",
}
]
}
gen = OCIBomGenerator.from_spec(spec)
item = gen.line_items[0]
assert item["sku"] == "SKU-002"
assert item["qty"] == 1
assert item["hours_units"] == 100
assert item["custom_note"] == "Canonical form"
def test_from_spec_requires_sku_or_part_number():
spec = {"line_items": [{"quantity": 1}]}
with pytest.raises(ValueError, match="sku"):
OCIBomGenerator.from_spec(spec)

View File

@@ -0,0 +1,98 @@
import sys
from pathlib import Path
PROJECT_ROOT = Path(__file__).resolve().parent.parent
TOOLS_DIR = PROJECT_ROOT / "tools"
if str(TOOLS_DIR) not in sys.path:
sys.path.insert(0, str(TOOLS_DIR))
from oci_deck_gen import OCIDeckGenerator
def _collect_slide_text(gen):
texts = []
for slide in gen.prs.slides:
for shape in slide.shapes:
if hasattr(shape, "text"):
text = shape.text.strip()
if text:
texts.append(text)
if getattr(shape, "has_table", False):
for row in shape.table.rows:
for cell in row.cells:
text = cell.text.strip()
if text:
texts.append(text)
return "\n".join(texts)
def test_from_spec_accepts_metadata_aliases_and_current_state_string():
spec = {
"metadata": {
"customer_name": "Acme Corp",
"project_name": "DB Migration",
"prepared_by": "Diego",
"title": "Target Architecture",
},
"summary": {
"why": "Modernize platform",
"current_state": "Legacy estate",
"target_state": "OCI landing zone",
"timeline": "Q3",
},
}
gen = OCIDeckGenerator.from_spec(spec)
text = _collect_slide_text(gen)
assert gen.customer == "Acme Corp"
assert gen.project == "DB Migration"
assert gen.architect == "Diego"
assert "Legacy estate" in text
assert "OCI landing zone" in text
def test_from_spec_accepts_aliases_for_cost_migration_risk_scorecard_and_next_steps():
spec = {
"metadata": {"customer": "Acme"},
"cost": {
"line_items": [
{"name": "DB Service", "monthly": "USD 100", "note": "Includes storage"}
],
"assumptions": ["1 region"],
"show_byol": False,
},
"migration": {
"phases": [
{"title": "Discover", "weeks": "2 weeks", "tasks": ["Inventory", "Assess"]}
],
"tools": ["ZDM"],
"downtime": "Near-zero",
},
"risks": [
{"title": "Cutover risk", "action": "Pilot first", "severity": "high"}
],
"scorecard": {
"pillars": [
{"pillar": "Security", "status": "PASS", "passed": 2, "total": 2}
],
"recommendations": ["Enable auditing"],
},
"next_steps": {"next_steps": ["Validate scope"]},
}
gen = OCIDeckGenerator.from_spec(spec)
text = _collect_slide_text(gen)
assert "DB Service" in text
assert "USD 100" in text
assert "Includes storage" in text
assert "Discover" in text
assert "Inventory" in text
assert "Cutover risk" in text
assert "Pilot first" in text
assert "Security" in text
assert "2/2" in text
assert "Validate scope" in text

View File

@@ -0,0 +1,76 @@
import sys
from pathlib import Path
PROJECT_ROOT = Path(__file__).resolve().parent.parent
TOOLS_DIR = PROJECT_ROOT / "tools"
if str(TOOLS_DIR) not in sys.path:
sys.path.insert(0, str(TOOLS_DIR))
from oci_diagram_gen import OCIDiagramGenerator
def test_from_spec_accepts_name_aliases_and_generates_ids():
spec = {
"external": [{"name": "Users"}],
"clouds": [{"name": "AWS", "services": [{"name": "EC2 App", "service_type": "ec2"}]}],
"tenancy": {
"regions": [
{
"name": "Ashburn",
"vcns": [
{
"name": "App VCN",
"subnets": [
{"name": "App Subnet", "services": [{"name": "App VM"}]}
],
}
],
}
]
},
"on_prem": {"name": "Primary DC", "services": [{"name": "Legacy DB"}]},
}
gen = OCIDiagramGenerator.from_spec(spec)
values = [getattr(obj, "value", "") for obj in gen._objects.values()]
assert "Users" in values
assert "AWS" in values
assert "Ashburn" in values
assert "VCN App VCN" in values
assert "App Subnet" in values
assert "App VM" in values
assert "Primary DC" in values
assert "Legacy DB" in values
def test_from_spec_accepts_source_target_and_omits_unresolved_connections():
spec = {
"external": [{"name": "Users"}],
"tenancy": {
"regions": [
{
"name": "Ashburn",
"vcns": [
{
"name": "App VCN",
"subnets": [
{"name": "App Subnet", "services": [{"name": "App VM"}]}
],
}
],
}
]
},
"connections": [
{"source": "Users", "target": "App VM", "type": "standard", "label": "HTTPS"},
{"from": "Users", "to": "App VM", "type": "standard", "label": "Duplicate"},
{"source": "Users", "target": "Missing VM", "type": "standard", "label": "Broken"},
],
}
gen = OCIDiagramGenerator.from_spec(spec)
assert gen._connection_count == 1

View File

@@ -28,6 +28,7 @@ Usage:
import argparse
import difflib
import json
import os
import sys
from collections import Counter
@@ -378,6 +379,10 @@ def cmd_list(args: argparse.Namespace) -> None:
category=getattr(args, "category", None),
)
if getattr(args, "json_output", False):
print(json.dumps(results, indent=2, default=str))
return
if not results:
print("No findings match the given filters.")
return
@@ -401,6 +406,21 @@ def cmd_search(args: argparse.Namespace) -> None:
"""Full-text search."""
results = search(args.query)
# Apply optional filters (mirrors list subcommand)
results = filter_findings(
results,
severity=getattr(args, "severity", None),
product=getattr(args, "product", None),
tag=getattr(args, "tag", None),
client=getattr(args, "client", None),
status=getattr(args, "status", None),
category=getattr(args, "category", None),
)
if getattr(args, "json_output", False):
print(json.dumps(results, indent=2, default=str))
return
if not results:
print(f"No findings matching '{args.query}'.")
return
@@ -600,6 +620,10 @@ def cmd_stats(args: argparse.Namespace) -> None:
"""Display summary statistics."""
s = stats()
if getattr(args, "json_output", False):
print(json.dumps(s, indent=2))
return
print(f"Total findings: {s['total']}\n")
print("By Severity:")
@@ -640,10 +664,18 @@ def build_parser() -> argparse.ArgumentParser:
p_list.add_argument("--client", help="Filter by client (partial match).")
p_list.add_argument("--status", help="Filter by status.")
p_list.add_argument("--category", help="Filter by category.")
p_list.add_argument("--json", action="store_true", dest="json_output", help="Output as JSON.")
# --- search ---
p_search = subparsers.add_parser("search", help="Full-text search.")
p_search.add_argument("query", help="Search term.")
p_search.add_argument("--severity", help="Filter by severity.")
p_search.add_argument("--product", help="Filter by product (partial match).")
p_search.add_argument("--tag", help="Filter by tag.")
p_search.add_argument("--client", help="Filter by client (partial match).")
p_search.add_argument("--status", help="Filter by status.")
p_search.add_argument("--category", help="Filter by category.")
p_search.add_argument("--json", action="store_true", dest="json_output", help="Output as JSON.")
# --- add ---
p_add = subparsers.add_parser("add", help="Add a new finding.")
@@ -685,7 +717,8 @@ def build_parser() -> argparse.ArgumentParser:
subparsers.add_parser("aer", help="After-Engagement Review (interactive).")
# --- stats ---
subparsers.add_parser("stats", help="Show summary statistics.")
p_stats = subparsers.add_parser("stats", help="Show summary statistics.")
p_stats.add_argument("--json", action="store_true", dest="json_output", help="Output as JSON.")
return parser

475
tools/gen_demo_deck.py Normal file
View File

@@ -0,0 +1,475 @@
#!/usr/bin/env python3
"""
OCI Deal Accelerator — Demo Presentation Generator
10-minute technical demo deck: AI-powered SA workflow acceleration.
Uses Oracle FY26 template via OraclePresBase.
"""
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent))
from pptx.util import Inches, Pt
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
from pptx.enum.shapes import MSO_SHAPE
from oci_pptx_base import Colors, Layouts, OraclePresBase
class DemoDeckGenerator(OraclePresBase):
TITLE_ACCENT_COLOR = Colors.TEAL
MARGIN = Inches(0.5)
SLIDE_WIDTH = Inches(13.333)
def add_cover(self):
"""Slide 1: Cover — dark, high impact."""
slide = self._add_layout_slide(Layouts.COVER_DARK)
self._set_placeholder(slide, 0, "OCI Deal Accelerator")
self._set_placeholder(slide, 1,
"AI-Powered Architecture Proposals in Hours, Not Days")
return slide
def add_impact_slide(self, metric, statement, detail=""):
"""Big metric slide — dark background, single number."""
slide = self._add_layout_slide(Layouts.IMPACT_DARK)
self._set_placeholder(slide, 0, metric)
self._set_placeholder(slide, 1, statement)
if detail:
self._set_placeholder(slide, 37, detail)
return slide
def add_content_slide(self, title, bullets, note=""):
"""Standard content slide with title bar + bullet list."""
slide = self._add_blank_slide()
self._add_title_bar(slide, title, margin=self.MARGIN)
y = Inches(1.4)
txBox = self._add_textbox(
slide, self.MARGIN + Inches(0.1), y,
Inches(12), Inches(5),
text="", font_size=15,
)
tf = txBox.text_frame
tf.word_wrap = True
# First paragraph already exists
tf.paragraphs[0].text = bullets[0] if bullets else ""
tf.paragraphs[0].font.size = Pt(15)
tf.paragraphs[0].font.name = self.FONT
tf.paragraphs[0].font.color.rgb = Colors.PRIMARY_TEXT
tf.paragraphs[0].space_after = Pt(6)
for b in bullets[1:]:
self._add_paragraph(tf, b, font_size=15, space_after=6)
if note:
self._add_textbox(
slide, self.MARGIN, Inches(6.5),
Inches(12), Inches(0.5),
text=note, font_size=11, italic=True,
color=Colors.SECONDARY_TEXT,
)
return slide
def add_prompt_table_slide(self, title, rows):
"""Slide with a table of option # | prompt example."""
slide = self._add_blank_slide()
self._add_title_bar(slide, title, margin=self.MARGIN)
n = len(rows) + 1
row_h = min(0.52, 5.2 / max(n, 1))
table = self._add_table(
slide, n, 3,
self.MARGIN, Inches(1.3),
Inches(12.3), Inches(row_h * n),
)
table.columns[0].width = Inches(0.6)
table.columns[1].width = Inches(3.0)
table.columns[2].width = Inches(8.7)
for j, h in enumerate(["#", "Capability", "Live Prompt"]):
self._style_table_cell(
table.cell(0, j), h, font_size=10, bold=True,
color=Colors.WHITE, bg_color=Colors.TEAL,
alignment=PP_ALIGN.CENTER if j == 0 else PP_ALIGN.LEFT,
)
for i, (num, cap, prompt) in enumerate(rows):
ri = i + 1
bg = Colors.TABLE_ALT_ROW if ri % 2 == 0 else None
self._style_table_cell(table.cell(ri, 0), str(num), font_size=10,
bold=True, bg_color=bg, alignment=PP_ALIGN.CENTER)
self._style_table_cell(table.cell(ri, 1), cap, font_size=10,
bold=True, bg_color=bg)
self._style_table_cell(table.cell(ri, 2), prompt, font_size=9,
bg_color=bg)
return slide
def add_before_after_slide(self):
"""Before/After comparison slide."""
slide = self._add_blank_slide()
self._add_title_bar(slide, "Before vs After: SA Workflow", margin=self.MARGIN)
# BEFORE column
self._add_rect(slide, self.MARGIN, Inches(1.4),
Inches(5.8), Inches(0.5), fill_color=Colors.ORACLE_RED)
self._add_textbox(slide, self.MARGIN + Inches(0.2), Inches(1.45),
Inches(5.4), Inches(0.4),
text="BEFORE — Manual SA Workflow",
font_size=14, bold=True, color=Colors.WHITE)
before = [
("Discovery call", "1h"),
("Research services + sizing", "2-4h"),
("Build architecture diagram", "1-2h"),
("Write proposal deck", "3-5h"),
("Cost estimate + BOM", "1-2h"),
("WA review (if time permits)", "2-3h"),
("Internal review + revisions", "1-2h"),
("TOTAL", "11-19 hours (2-3 days)"),
]
y = Inches(2.0)
for task, time in before:
bold = task == "TOTAL"
color = Colors.ORACLE_RED if bold else Colors.PRIMARY_TEXT
self._add_textbox(slide, Inches(0.7), y, Inches(3.8), Inches(0.32),
text=task, font_size=11, bold=bold, color=color)
self._add_textbox(slide, Inches(4.6), y, Inches(1.5), Inches(0.32),
text=time, font_size=11, bold=bold, color=color,
alignment=PP_ALIGN.RIGHT)
y += Inches(0.35)
# AFTER column
self._add_rect(slide, Inches(6.8), Inches(1.4),
Inches(5.8), Inches(0.5), fill_color=Colors.FOREST)
self._add_textbox(slide, Inches(7.0), Inches(1.45),
Inches(5.4), Inches(0.4),
text="AFTER — AI-Assisted Workflow",
font_size=14, bold=True, color=Colors.WHITE)
after = [
("Discovery call", "1h"),
("Paste notes → Full proposal", "3-5 min"),
("Architecture diagram", "included"),
("Slide deck (18 slides)", "included"),
("Cost estimate + BOM", "included"),
("WA review (5-pillar)", "included"),
("SA reviews AI output", "30-60 min"),
("TOTAL", "1.5-2 hours (same day)"),
]
y = Inches(2.0)
for task, time in after:
bold = task == "TOTAL"
color = Colors.FOREST if bold else Colors.PRIMARY_TEXT
self._add_textbox(slide, Inches(7.0), y, Inches(3.8), Inches(0.32),
text=task, font_size=11, bold=bold, color=color)
self._add_textbox(slide, Inches(11.0), y, Inches(1.5), Inches(0.32),
text=time, font_size=11, bold=bold, color=color,
alignment=PP_ALIGN.RIGHT)
y += Inches(0.35)
# Savings callout
self._add_rect(slide, Inches(3.5), Inches(5.3),
Inches(6.3), Inches(0.7), fill_color=Colors.TEAL)
self._add_textbox(slide, Inches(3.6), Inches(5.35),
Inches(6.1), Inches(0.6),
text="85% time reduction | Same day delivery | Higher quality (WA-validated)",
font_size=14, bold=True, color=Colors.WHITE,
alignment=PP_ALIGN.CENTER)
return slide
def add_comparison_table_slide(self, title, rows):
"""Two-column comparison: Generic LLM vs This Skill."""
slide = self._add_blank_slide()
self._add_title_bar(slide, title, margin=self.MARGIN)
n = len(rows) + 1
row_h = min(0.58, 5.0 / max(n, 1))
table = self._add_table(
slide, n, 3,
self.MARGIN, Inches(1.35),
Inches(12.3), Inches(row_h * n),
)
table.columns[0].width = Inches(2.8)
table.columns[1].width = Inches(4.75)
table.columns[2].width = Inches(4.75)
headers = ["", "Generic LLM (ChatGPT, etc.)", "OCI Deal Accelerator"]
header_colors = [Colors.TEAL, Colors.ORACLE_RED, Colors.FOREST]
for j, (h, hc) in enumerate(zip(headers, header_colors)):
self._style_table_cell(
table.cell(0, j), h, font_size=10, bold=True,
color=Colors.WHITE, bg_color=hc,
alignment=PP_ALIGN.CENTER,
)
for i, (aspect, generic, skill) in enumerate(rows):
ri = i + 1
bg = Colors.TABLE_ALT_ROW if ri % 2 == 0 else None
self._style_table_cell(table.cell(ri, 0), aspect, font_size=10,
bold=True, bg_color=bg)
self._style_table_cell(table.cell(ri, 1), generic, font_size=9,
bg_color=bg)
self._style_table_cell(table.cell(ri, 2), skill, font_size=9,
bg_color=bg)
return slide
def add_divider(self, text):
slide = self._add_layout_slide(Layouts.DIVIDER_DARK)
self._set_placeholder(slide, 0, text)
return slide
def build_demo_deck(output_path):
gen = DemoDeckGenerator()
# ── SLIDE 1: Cover (0:00-0:15) ──
gen.add_cover()
# ── SLIDE 2: The Problem — impact (0:15-1:00) ──
gen.add_impact_slide(
"11-19h",
"Time an SA spends per proposal",
"Research + diagram + deck + costs + review — repeated for every deal"
)
# ── SLIDE 3: The Aha Moment (1:00-2:00) ──
gen.add_before_after_slide()
# ── SLIDE 4: Why Not Just Use ChatGPT? (2:00-3:30) ──
gen.add_comparison_table_slide(
'"Can\'t I Just Ask ChatGPT to Make Me a Deck?"',
[
("Pricing",
"Training data from 2024. Invents SKUs. No discount calc. Can't generate a BOM.",
"160+ SKUs auto-refreshed from Oracle API. Real PAYG/BYOL. BOM + AppCA export."),
("Architecture",
"Generic diagrams. Suggests services that don't exist or don't apply.",
"Patterns from real deployments. Knows ExaCS needs 3+ storage for IORM."),
("Field gotchas",
"Doesn't know DEP takes 3 weeks to provision, or that ADG must be disabled first.",
"8+ validated findings from real engagements, with workarounds and SR refs."),
("Competitive",
"Tends to be either biased or generic. No real cost comparison data.",
"Honest pros/cons per service. BYOL 50-75% cheaper data. Knows where AWS wins."),
("WA validation",
"Gives generic 'best practices' list. No scoring, no gap analysis.",
"80+ checks across 5 pillars. Automated scoring. Actionable gap report."),
("Compliance",
"Generic SOX/PCI advice. Doesn't know OCI-specific controls.",
"OCI Vault for TDE, Unified Auditing, compartment isolation — mapped to frameworks."),
("Output format",
"Markdown or basic text. Manual copy-paste to slides.",
"Oracle FY26 .pptx template, .drawio, branded .pdf, .xlsx — ready to present."),
("Improves over time",
"Frozen at training cutoff. Learns nothing from your engagements.",
"Every SA adds findings. Pricing refreshes. KB compounds with every deal."),
],
)
# ── SLIDE 5: What Is It (3:30-4:00) ──
gen.add_content_slide(
"OCI Deal Accelerator — What Is It?",
[
"An AI skill (system prompt + knowledge base + tools) for any LLM with tool-use and 100K+ context",
"Works on Claude, Codex, GPT, Gemini — any model that can read files + run Python",
"The LLM is the engine. The KB + tools are the fuel. The SA is the driver.",
"Aligned with ECAL framework: Define > Design > Deliver",
"7 Python generators: .pptx, .drawio, .pdf, .xlsx, WA scorecard, BOM, AppCA",
"14 capabilities accessible via natural language — not a chatbot, a domain-specific SA tool",
],
)
# ── SLIDE 6: Divider — Live Demo (4:00) ──
gen.add_divider("Live Demo: 14 Capabilities")
# ── SLIDE 6: Prompts 1-7 (3:00-6:00) ──
gen.add_prompt_table_slide(
"Design, Validate & Compare (Options 1-7)",
[
("1", "Full proposal",
"Cliente farmaceutico en Mexico, 3 Oracle DBs (EBS R12 prod, SAP, DW) en "
"Exadata X6 on-prem. HW refresh vence en 6 meses. Quieren migrar a OCI, "
"RPO<15min, RTO<1h, necesitan compliance SOX. 200 usuarios concurrentes, "
"2TB data, pico en cierre fiscal. Budget: reducir 30% vs renovar HW."),
("2", "Architecture diagram",
"Diagrama: ExaCS en Queretaro (prod) + Standby con Data Guard en Sao Paulo, "
"Hub-Spoke networking con DRG, FastConnect 10Gbps dual desde Mexico City, "
"bastion en public subnet, WAF para apps web, Vault para TDE keys."),
("3", "Slide deck",
"Genera el deck para la propuesta del cliente farmaceutico."),
("4", "Cost estimate",
"ExaCS X11M Quarter Rack BYOL, 2 DB servers, 3 storage servers, "
"400GB RAM, 10TB usable + ADB-S 16 ECPU + FastConnect 1Gbps dual + "
"50TB Object Storage + OCI Vault. 12 meses, 40% descuento."),
("5", "WA review",
"Review: ADB-S 23ai en Sao Paulo region unica, IAM con admin por defecto, "
"sin encryption at rest explicita, sin WAF, monitoring con scripts custom, "
"patching manual mensual, backup solo local, sin network segmentation."),
("6", "Feature check",
"Does ADB-S Dedicated Elastic Pool support Auto Indexing on 23ai? "
"And what about AI Vector Search with HNSW indexes at 100M+ vectors?"),
("7", "Competitive",
"Customer comparing ADB-S vs AWS Aurora PostgreSQL for a mixed OLTP+analytics "
"workload, 500GB, needs partitioning, RAC equivalent, and BYOL licensing. "
"They think Aurora is cheaper. Give me honest pros and cons."),
],
)
# ── SLIDE 7: Prompts 8-14 (6:00-8:30) ──
gen.add_prompt_table_slide(
"Strategy, KB, Governance & SA Tools (Options 8-14)",
[
("8", "Business case",
"Business case: 5 Oracle DBs on-prem (EBS, Siebel, DW, 2 custom), "
"$1.2M/yr infra (HW refresh vence Q3). CTO quiere cloud, CFO quiere "
"numeros. Necesito TCO 3 anos, ROI, risk of doing nothing, y que pasa "
"si renuevan HW por 5 anos mas. Audience: board de directores."),
("9", "Field findings",
"What real issues has the field team found with ADB-S Dedicated Elastic "
"Pool? Include DEP provisioning times, maintenance windows, and ADG."),
("10", "Reference arch",
"Reference architectures for cross-region DR with Exadata and Data Guard. "
"Need options for both ExaCS and ADB-S with automatic failover."),
("11", "Report finding",
"New finding: ExaCS iormcal fails silently when storage server count < 3. "
"Product: ExaCS, Version: 23ai, Severity: MEDIUM, found during pharma "
"engagement in Mexico. Workaround: validate IORM plan output after apply, "
"check v$iorm_plans for actual vs requested shares."),
("12", "ECAL readiness",
"Score this engagement: tenemos discovery notes, workload profile, y un "
"diagrama de arquitectura. No hay business case, no value story, no "
"handover plan, no operations model. Customer es farmaceutica en Mexico, "
"engagement tier standard, estamos en la fase Design."),
("13", "BOM generator",
"BOM: ExaCS X11M Half Rack BYOL, 4 DB servers 128 ECPUs each, "
"6 storage servers, ADB-S 32 ECPU, 50TB block storage, "
"FastConnect 10Gbps dual, OCI Vault, 12 months, 45% discount."),
("14", "BOM for AppCA",
"Same BOM as 13 but in AppCA import format for deal approval."),
],
)
# ── SLIDE 8: The KB Is the Moat (7:30-8:15) ──
gen.add_content_slide(
"The Knowledge Base Is the Moat",
[
"40+ YAML files of FIELD knowledge — not regurgitated docs, real experience",
"Services: what each OCI service does, when to use it, gotchas, sizing rules",
"Patterns: composable architecture blocks (HA, DR, networking, security baselines)",
"Pricing: 160+ SKUs auto-refreshed from Oracle public API (refresh_sku_catalog.py)",
"Field findings: production issues with workarounds, contributor attribution, confidence levels",
"Competitive: honest AWS/Azure mapping with real advantage/disadvantage per service",
"Architecture Center: 123 curated reference architectures with service + tag filtering",
"",
"Without the KB, the AI is just another chatbot. With it, it's a domain expert.",
],
)
# ── SLIDE 9: Auto-refresh + Collaborative Model (8:15-9:00) ──
gen.add_content_slide(
"Self-Updating KB + Collaborative Field Intelligence",
[
"AUTO-REFRESH — pricing stays current without manual intervention:",
" python refresh_sku_catalog.py --refresh --diff # updates 160+ SKUs from Oracle API",
" python refresh_arch_catalog.py --whats-new # crawls Architecture Center for new entries",
"",
"COLLABORATIVE — every SA contributes, everyone benefits:",
" findings_cli.py add --product ExaCS --severity HIGH --summary '...'",
" Each finding has: contributor, team, client, confidence, confirmations[]",
" Other SAs can confirm: findings_cli.py confirm FF-202603-001 --name '...'",
"",
"GOVERNANCE — quality stays high as the KB grows:",
" kb_cli.py health # freshness dashboard: 63 files, stale detection",
" kb_cli.py stats stale # reports files older than review cadence",
" Every file has last_verified date + domain owner in kb-owners.yaml",
"",
"The KB compounds: every engagement makes the next one faster and better.",
],
)
# ── SLIDE 10: MCP Server — Zero Setup (8:30-9:00) ──
gen.add_content_slide(
"MCP Server: Use It From Any Client — Zero Code Setup",
[
"The skill also runs as an MCP (Model Context Protocol) server.",
"14 tools exposed over HTTP — same capabilities, no local repo needed.",
"",
"SUPPORTED CLIENTS — connect once, use forever:",
" Claude Code / Claude Desktop (OAuth) | Cursor (OAuth)",
" Codex - OpenAI (Bearer token) | Windsurf (SSE)",
" Any MCP-compliant client",
"",
"SETUP — 1 command, done:",
" claude mcp add --transport http oci-deal-accelerator \\",
' "https://mcp.tech-lad.com/deal-accelerator/mcp/"',
"",
"HOW IT WORKS:",
" Your IDE / Claude --> MCP Server (Docker) --> KB + Tools + Generators",
" You type a prompt --> Server runs the tool --> You get .pptx, .xlsx, .json",
"",
"Zero Python setup. Zero repo cloning. Zero dependency management.",
"The SA opens their IDE, connects to the MCP, and starts working.",
],
)
# ── SLIDE 11: Key Takeaways (9:00-9:30) ──
gen.add_content_slide(
"Key Takeaways",
[
"85% time reduction: from 2-3 days to 2 hours per proposal",
"Higher quality: every proposal is WA-validated with 5-pillar scoring",
"The KB is the moat: field experience > documentation > AI hallucination",
"Self-updating: pricing + architectures refresh automatically",
"Collaborative: every SA's gotcha becomes everyone's advantage",
"MCP server: zero setup, use from any AI client (Claude, Codex, Cursor...)",
"Real deliverables: .pptx, .drawio, .pdf, .xlsx, BOM, AppCA — not chat summaries",
"SA stays in control: AI generates, architect reviews and refines",
],
)
# ── SLIDE 12: Get Started ──
gen.add_content_slide(
"Get Started Right Now",
[
"OPTION A — MCP Server (recommended, zero setup):",
" claude mcp add --transport http oci-deal-accelerator \\",
' "https://mcp.tech-lad.com/deal-accelerator/mcp/"',
"",
"OPTION B — Clone the skill repo (full access to KB + tools):",
" git clone https://git.tech-lad.com.br/diegoecab/oci-deal-accelerator.git",
"",
"MCP Server repo (deploy your own instance):",
" github.com/Diegoecab/arch-mcp-oracle",
"",
"Skill repo (KB + tools + generators):",
" git.tech-lad.com.br/diegoecab/oci-deal-accelerator",
"",
"",
"Skill repo: git.tech-lad.com.br/diegoecab/oci-deal-accelerator MCP repo: github.com/Diegoecab/arch-mcp-oracle",
],
note="Scan the QR or visit the link above to get started in 30 seconds"
)
# ── SLIDE 13: Closing ──
gen.add_closing_slide(
name="OCI Deal Accelerator",
title="git.tech-lad.com.br/diegoecab/oci-deal-accelerator | github.com/Diegoecab/arch-mcp-oracle",
)
gen.save(output_path)
print(f"Generated: {output_path}")
print(f" Slides: {gen.slide_count}")
print(f" Duration: ~10 minutes")
if __name__ == "__main__":
out = sys.argv[1] if len(sys.argv) > 1 else "demo-presentation.pptx"
build_demo_deck(out)

Some files were not shown because too many files have changed in this diff Show More