Commit Graph

42 Commits

Author SHA1 Message Date
root
a032e7980b Fix drawio OIC icon resolution 2026-04-27 13:07:38 -03:00
root
198861f533 PPTX icon resolver: skip degraded refs from stencil buckets
Symptom on the GCP→OCI PostgreSQL deck: the OCI PostgreSQL icon bbox
rendered as empty space — labels and surrounding ADs all visible,
but no icon where the postgres stencil should be.

Root cause: ``_lookup_icon_ref`` returned the first hit from
``stencils.database_icons`` without checking it was cloneable.
The bucket happens to ship one degraded entry — ``database`` is
``tag=sp`` with ``bbox=None`` (a label-strip leaf, not the real
icon group) — so ``_clone_translated_block`` emitted a zero-size
shape. The 19 viable refs for the same key in
``shape_library.entries`` were ignored because the early-return in
``database_icons`` won.

Fix: extract a shared ``_is_viable_ref`` predicate (slide_path +
child_index/node_path + non-empty bbox + supported tag) and apply
it before returning from BOTH stencil buckets (``database_icons``,
``sample_icon_refs``). On miss, fall through to
``shape_library_entries`` where ``_select_preferred_ref`` already
filtered the same way.

Affects every alias that routes to a degraded stencil entry —
``postgresql`` / ``postgres`` / ``oci_postgresql`` were the obvious
fallout because they all alias to ``database``. The Architecture
Center reconstructions on shape-library-only slugs were unaffected.

Verified by re-rendering examples/output-gcp-virginia-oci-postgres-
adbs-clone/*.pptx — the OCI PostgreSQL bbox now shows the icon
(teal stencil + "Database" intrinsic caption) consistently with
the ADB-S and Refreshable Clone bboxes next to it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 11:03:23 -03:00
root
7f8cba7f30 Skill: kill the lookup-loop time-sink (3 fixes from Codex transcript)
Root cause observed in a real Codex session: the agent burned ~3min
on `make venv` + 4 sequential `make diagram-lookup` queries trying
to find a non-existent ref-arch (OCI PostgreSQL accessed FROM GCP
via Cross-Cloud Interconnect). The catalog has 123 entries; if two
honest queries can't surface a topology, none exists — but nothing
in the skill said "stop." Three coordinated fixes:

1) Makefile: `make venv` is now idempotent.
   Marker file `.venv/.deps-installed` keyed off `requirements.txt`
   mtime — the second `make venv` in a row is a 26ms no-op (was
   1m53s on a Codex sandbox, paid every turn). Force a rebuild with
   `rm .venv/.deps-installed`.

2) kb/architecture-center/catalog.yaml: new `known_gaps` block.
   Surfaced by the lookup tool as a top-of-output banner whenever
   the (synonym-expanded) query tokens match any one of a gap's
   `triggers` token sets. Two gaps seeded from real engagements:

     - gcp-to-oci-native-services — OCI PostgreSQL/OKE/Cache/etc.
       reached FROM GCP via Cross-Cloud Interconnect (the
       Database@Google Cloud entries are the OPPOSITE direction).

     - newer-oci-services-without-icon — OCI Cache (Redis/Valkey)
       and OCI PostgreSQL post-v24.2-toolkit; no ref-arch, no
       toolkit icon, fall back to generic stencil + explicit label.

   Each gap's `notice:` is a copy-paste recommended composition so
   the agent doesn't have to invent a strategy.

3) tools/archcenter_pattern_lookup.py: detects + surfaces gaps.
   `lookup()` now returns `{"matches": ..., "gaps": ...}`. The
   text printer emits a "⚠ KNOWN GAP — <id>" banner with the
   notice block ABOVE the score-based top-K, so the agent sees
   the stop-and-compose signal before ever scrolling to results.
   YAML output mode mirrors the same shape under `gaps:`.

4) SKILL.md (option 2 step 1) + Codex copy via sync-skill.
   New explicit rule: "Lookup budget: max 2 queries — never loop."
   Documents the gap banner, the closest-3-then-ask fallback, and
   the prohibition against grasping at a 3rd refinement.

Verified manually:
  - GCP+postgresql query → gap fires
  - "redis ha multi-az" → newer-OCI gap fires
  - "exadata cross region data guard" → no false-positive gap

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 10:46:27 -03:00
root
1b4828f293 MELI Fraud: case-specific scaffolding scripts (3 chassis variants)
Three one-shot Python scripts that build the MELI Fraud As-Is /
To-Be .drawio pair by cloning an Oracle Architecture Center chassis
and overlaying MELI-specific labels, region renames, and workload
pills. Useful as worked examples of the chassis-then-overlay
transform pattern (drawio_template_transform.DrawioTemplate) that
the diagram procedure recommends:

  • build_meli_fraud_from_adbsplusadbd.py — clones the locally
    accepted ATP-S/ATP-D side-by-side reference and partitions cells
    into AS-IS / TO-BE panels by x-coordinate.
  • build_meli_fraud_from_crossregion.py — uses Oracle's
    exadata-dedicated-cross-region-dataguard ref-arch (two regions
    with DRG + RPC + Data Guard already drawn) as chassis and only
    overlays MELI-specific pills.
  • build_meli_fraud_from_templates.py — combines the in-region and
    cross-region Exadata ref-archs and clones the in-region
    topology to the right for the Montreal DR.

All three honour the standing rule: do not edit text inside Oracle
SVG stencil shapes — overlay new mxCells in whitespace instead.
Outputs land under examples/output-meli-fraud-adbd-migration/.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 09:29:37 -03:00
root
5566a171b0 PPTX: ensure [Content_Types].xml has defaults for every media extension
Symptom: PowerPoint prompted to repair some generated decks. Cause:
when python-pptx (or our native renderer) repacks the .pptx after we
embed Oracle template assets — some of which are SVG-backed —
[Content_Types].xml can lose the Default entry for "svg" (and other
extensions present under ppt/media), which makes Office refuse to
open the file cleanly.

Fix: after writing the deck (and after any native renderer pass),
walk ppt/media, collect the actual extensions in use, and ensure
[Content_Types].xml declares a Default for each one (svg, png, jpg,
jpeg, gif, bmp, tiff, emf, wmf, ico, webp). Repack only when at
least one new Default was added — no-op fast path otherwise.

Lines up with the existing field rule: every embedded media
extension must be declared in [Content_Types].xml Defaults, or
PowerPoint flags the file as corrupt.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 09:29:18 -03:00
root
eef213612c Aliases for newer OCI services without toolkit icons (Redis, PostgreSQL)
Diego pointed at examples/output-ashburn-redis-oke and asked: does
Oracle ship a Redis icon for drawio? Answer: NO. Confirmed against
both libraries:
  - kb/diagram/oci-icons.json (OCI Toolkit v24.2)         → 0 hits
  - kb/diagram/oci-pptx-icons-index.json (OCI_Icons.pptx) → 0 hits
Same for OCI Cache, Valkey, OCI PostgreSQL — all are GA after the
toolkit shipped.

Oracle's own reference architecture
``modernize-app-dev-oci-postgresql-redis-opensearch`` works around
this by embedding inline SVG vector data into ``shape=stencil(...)``
cells — there is no reusable named stencil. The closest reusable
match is the generic ``database`` icon (8 cells in oci-icons.json,
the canonical "Database" stencil).

Persistent fixes:

- TYPE_TO_ICON (PPTX) and ICON_TYPE_ALIASES (drawio) both gain
  aliases for ``redis`` / ``oci_cache`` / ``oci_cache_with_redis`` /
  ``cache`` / ``valkey`` / ``postgresql`` / ``postgres`` /
  ``oci_postgresql`` → ``database``. Plus ``opensearch`` →
  ``database_opensearch`` (which exists) on the PPTX side.

- SKILL.md option 2 step 3 documents the convention: when an OCI
  service doesn't have a toolkit icon, use the generic stencil and
  pair with an explicit ``label:`` carrying the real service name
  (e.g. ``label: "OCI Cache (Redis)"``). When Oracle ships a v25+
  toolkit with these icons, update oci-icons.json + the alias tables
  and the next render picks up the real icon automatically.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 00:00:17 -03:00
root
b77a855a3e Extractor: drawio → absolute_layout YAML scaffold (107/132 cached)
Closes the procedural hole that kept making Codex sessions fall back
to ``examples/`` for YAML scaffolding even after the SKILL forbade it.

The lookup tool returns a canonical Oracle ``.drawio`` as the geometry
source, but the agent had no YAML version of that geometry to copy —
the .drawio is XML with stencil-encoded icons. Without a scaffold,
agents reverse-engineered or fell back to ``examples/`` (which is
forbidden but happened anyway because the alternative was painful).

New tool ``tools/archcenter_drawio_to_template.py`` extracts:
  • canvas dimensions
  • containers (region / vcn / ad / subnet) classified by stroke /
    fill style markers
  • service bounding boxes with ``type: TODO_identify`` (the icon
    type is encoded in stencil bytes — agent fills it from the
    renderer's TYPE_TO_ICON aliases when authoring the spec)
  • edge waypoints (source, target, points)

Output lands at ``kb/diagram/assets/archcenter-refs/<slug>/_template.yaml``
next to the .drawio. Lookup now surfaces it as
``cached: yaml=<path>`` so the agent has a one-step "copy this YAML
and adapt" path.

Ran across all 132 cached folders: 107 templates emitted, 24 had no
.drawio (zip didn't ship one), 1 already cached.

Other persistent guardrails added in this commit:

- SKILL.md option 2 step 3: explicit reminder that valid ``type:``
  values come from ``TYPE_TO_ICON`` / ``ICON_TYPE_ALIASES`` in the
  renderer source plus the icon-index JSON files. Do NOT grep
  ``examples/`` for ``type:`` — that's where the previous Codex
  session was looking, against the rule.

- ``make archcenter-templates-refresh`` Makefile target.

- The lookup index now also indexes ``_template.yaml`` per slug.

- Auto-extracted templates committed under
  ``kb/diagram/assets/archcenter-refs/*/_template.yaml`` so a fresh
  clone has them on first lookup (no extraction step needed).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 23:56:29 -03:00
root
5b8a6ad5ec Lookup index auto-invalidates on KB updates + manual rebuild flag
Diego asked: does the persisted ``archcenter-refs-index.json`` auto-
update when the KB is updated? Partially — mtime on the cache root
catches add/remove of subdirs (POSIX), but NOT changes to files
INSIDE existing subdirs (description.md added, .drawio replaced).

Two fixes:

1. Both KB-update tools now ``touch`` ``kb/diagram/assets/archcenter-refs``
   when they finish a run that produced changes:
   - ``archcenter_description_fetcher.py`` after fetched > 0
   - ``archcenter_zip_downloader.py`` after downloaded / extract /
     overwrite events
   The touch bumps the parent mtime, which the next lookup detects
   and uses to rebuild its persisted index. Closes the silent-drift
   case where description.md fetches landed but the index didn't
   notice.

2. ``archcenter_pattern_lookup.py --rebuild-index`` flag — escape
   hatch for manual KB edits (someone replaces a cached .drawio by
   hand) where neither tool ran. Removes the stale index file before
   the lookup, forcing a cold rebuild.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 23:38:29 -03:00
root
c46219468f Lookup speed (78s → 1s) + drawio ADB-S/RC alias coverage
Two persistent fixes flagged from a Codex session:

1. ``archcenter_pattern_lookup`` ran in 78 s on WSL2 because:
   - ``_cached_assets`` did ``iterdir`` + recursive ``rglob`` over the
     whole 113-folder cache for EVERY catalog entry (123x).
   - ``_patterns_for`` reloaded ``reference-patterns.yaml`` for every
     match (125 reloads = ~5 s).
   - Description text from disk was read for every entry, even those
     that wouldn't make the top-K.

   Now: one-shot scan of the cache dir cached in-memory AND persisted
   to ``kb/diagram/assets/archcenter-refs-index.json`` keyed by mtime;
   patterns YAML loaded once and indexed by URL; a two-pass scoring
   pipeline that only reads description text + cached_assets +
   visual_patterns for the top-K candidates instead of every entry.
   Result: cold run 14 s (one-time index build), warm run 1.1 s.

2. The drawio renderer had no alias for ``adb_s`` / ``adb_serverless``
   / ``autonomous_database_serverless`` / ``refreshable_clone`` —
   Codex's spec used ``type: adb_s`` and the icon never resolved.
   Mapped them to ``autonomous_database`` (the canonical 7-cell
   stencil shipped by the OCI Toolkit), with ``adb_d`` as fallback.
   Same proactive expansion in the drawio side that the PPTX side
   already got (oci_goldengate, dynamic_routing_gateway, atp/adw,
   kms/secret, identity/iam, iac/terraform, oac/oic, kafka).

The persisted lookup index is committed so a fresh clone hits warm
performance on first ``make diagram-lookup``.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 23:33:40 -03:00
root
82d09aeee6 PPTX icon resolver: 50+ proactive aliases + menu-mode 'no code edits' rule
Diego flagged two patterns from the Codex session:

1. Aliases for natural-language slugs were missing — Codex authored
   ``type: refreshable_clone`` and ``type: oci_goldengate`` and the
   resolver returned None for both. Beyond fixing those two, expand
   the table proactively: 50+ slugs an SA / agent might naturally
   reach for (atp, alb, nlb, apigw, lambda, kms, secret, kafka,
   alarm, email, identity, iam, iac, terraform, oac, oic, language /
   speech / vision, rpc / lpg / cpe, health_check, tags, etc.) all
   mapped to canonical icon entries that exist in
   kb/diagram/oci-pptx-icons-index.json.

2. Codex was editing tools/oci_deck_gen.py and the deck-spec while
   fulfilling a menu-driven option-2 request — going off the
   procedure to "fix" perceived bugs in the renderer. New rule in
   SKILL.md § What You Do NOT Do: when the user is in menu mode
   (options 1–14), the agent USES the existing tools, never modifies
   them. Tool gaps (missing aliases, broken paths) get surfaced as
   end-of-reply follow-ups for a separate developer-mode session.
   Two narrow exceptions kept: kb/field-findings/tracker.yaml via
   option 11, and writing customer spec/output YAML under examples/.

Codex copy auto-synced via the pre-commit hook.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 23:18:22 -03:00
root
d86adaf7cc Diagram procedure: forbid workload-driven shape, warn at runtime
The Codex session showed why the workload-driven mode is the wrong
default. Codex authored a spec under
``tenancy → regions → compartments → services`` (the documented
"workload-driven" mode), generated two .drawio files, and reported
success. The output was unusable: services rendered as colored
rectangles with text instead of OCI icon stencils, connector text
went into the edge value (forbidden by the connector-label rule),
and the spec validator never ran because it only fires on
``absolute_layout`` blocks.

Diego: "los drawio son horribles, por que sucede eso?".

Three persistent fixes:

1. SKILL.md option 2 now says ``absolute_layout`` is REQUIRED for
   step 3, calls out workload-driven explicitly as forbidden, and
   explains *why* (no stencils, no validator).

2. docs/skill/output-formats.md § Diagram modes is rewritten — mode
   1 is ``absolute_layout`` (REQUIRED), mode 2 is workload-driven
   (DEPRECATED, back-compat only). Removes the "two acceptable
   shapes" framing that let Codex pick the wrong one.

3. ``oci_diagram_gen.py`` now prints a loud stderr WARNING when a
   spec takes the workload-driven path, naming the procedure docs.
   Catches any agent that skipped reading SKILL.md before generating.

Codex copy synced via ``make sync-skill``.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 22:54:03 -03:00
root
a0a059887a Deck generator: honor output.render_standard_sections, fix principles overlap
Two bugs flagged on the MySQL HeatWave HA example (2026-04-25 round 5):

1. ``render_standard_sections: false`` under the ``output:`` block was
   silently ignored — the generator only checked the top-level key.
   Result: every spec that put the flag where the docs suggest got the
   full standard deck PLUS the custom slide, producing a duplicated
   "Architecture Overview" + dedicated diagram slide. Now the
   generator honors both locations.

2. Architecture Principles slide allocated only 0.4" per bullet —
   exactly one 11pt line. Wrapping principle summaries (e.g. D-03
   Use-Case Fit's 125-char text) overflowed into the next bullet's
   slot, visually overlapping D-02. Diego: "D-03 esta superpuesto a
   D-02, lo mismo pasa en otras columnas". Bumped per-item height to
   0.95" — fits 2-3 wrapped lines with breathing room.

3. PPTX rasterizer (oci_pptx_render.py) gained word-wrap so the
   local PNG preview matches what real PowerPoint draws. Without it,
   long text rendered on a single line off the column and the
   principles fix looked broken in preview when it was actually fine
   in PowerPoint.

Persistent: all three fixes apply to every deck the skill generates.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 22:44:40 -03:00
root
68d1753a74 Spec validator: padding on all 4 edges + connector-over-label check
Closes the gap between what the validator catches and what Diego
flagged on the MySQL HeatWave HA example (2026-04-25 round 4):

- CONTAINER_PADDING_VIOLATION now checks all four edges (top / bottom /
  left / right). Previously only bottom — DB Subnet's left/right edges
  touching the AD borders went unflagged.

- CONNECTOR_OVER_LABEL now runs at SPEC level (was post-render drawio
  only). Catches "Network Load Balancer label sits below the arrows so
  the arrows cross it" before either renderer emits anything; covers
  the PPTX path too.

  Implemented via Liang-Barsky line-rect clipping on every connector
  segment vs every free-floating label bbox.

Renderer policies persist for every new diagram (bent connectors,
icon-group preference, mysql aliases). Spec-level rules are now
enforced earlier and on both render paths, so a spec authored against
the procedure will pass before any artifact is produced.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 22:11:02 -03:00
root
3fb832e578 PPTX connectors: emit native bentConnector2/3/5 instead of disjoint lines
Spec authors hand the renderer a polyline like
``points: [[210,280],[400,280],[700,130]]``. The previous code emitted
one ``prst="line"`` shape per segment, so the elbow was two separate
straight lines that PowerPoint cannot recognise as a connected path.

The OCI template (kb/diagram/assets/OCI_Icons.pptx) uses native
PowerPoint bent connectors instead — 98 ``straightConnector1`` plus
22 ``bentConnector2/3/5`` plus 15 ``line`` across 48 slides. Match
that convention:

  • 2 points  → straightConnector1 (one segment, unchanged)
  • 3 points  → bentConnector2     (one elbow)
  • 4 points  → bentConnector3     (S-shape, two elbows)
  • 5+ points → bentConnector5     (four elbows)

The rasterizer (oci_pptx_render.py) now also understands bentConnectorN
so the local PNG preview matches what real PowerPoint draws — without
this it rendered every connector as one straight diagonal regardless of
the prst.

Persistent: applies to every absolute_layout connector for every spec,
not a per-case patch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 21:49:39 -03:00
root
e384e627d1 PPTX icon resolver: prefer full icon group over text-strip variant
OCI_Icons.pptx ships both a full icon group (tag=grpSp, ~0.7" tall)
and a tiny "label strip" (tag=sp, ~0.2" tall) under the same slug for
many services. The previous resolver picked whichever came first in
the index, which for 'mysql' returned the text strip — so the PPTX
diagram showed a label-only shape instead of the dolphin/HeatWave
icon, while drawio rendered the proper stencil.

Two fixes, both persistent (apply to every icon family, not just MySQL):

- TYPE_TO_ICON for mysql/heatwave now lists 'mysql_heatwave' (the
  grpSp) before 'mysql' (the strip).
- _select_preferred_ref now filters viable refs to those that are
  either grpSp/pic OR have a bbox ≥0.4"x0.4" — text strips fall out
  before the scoring function runs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 21:42:21 -03:00
root
e5a1959585 Diagram tooling: make targets, CI gate, LLM-rewrite hook, refresh docs
Implements points 3–8 of the post-procedure follow-up.

- Make targets: diagram-lookup, diagram-validate-spec, diagram-spec-audit,
  archcenter-descriptions-refresh, archcenter-smoke. Promotes the new
  tools out of "remember the CLI" into discoverable build-automation.
- .gitea/workflows/diagram-validators.yaml — runs spec validator across
  every absolute_layout spec on push/PR, plus a drawio re-render smoke
  test on the canonical example. Hard fail blocks merges.
- archcenter_pattern_lookup --llm-rewrite — opt-in (ANTHROPIC_API_KEY
  env var, mirroring DRAWIO_EXE pattern). Rewrites natural-language
  queries into canonical OCI terminology before scoring; falls back to
  the original query on any error.
- diagram_spec_validator — documents the policy on legacy archcenter
  reproductions: LABEL_NEAR_PARENT_EDGE stays a warning so verbatim
  reconstructions don't lose pixel-fidelity from cosmetic edits.
- README — documents the asset refresh procedure (downloader +
  description fetcher are idempotent, refresh quarterly).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 21:37:28 -03:00
root
b30a4f0d32 Diagram generation: ref-arch-driven procedure + spec validator + KB enrichment
The diagram path now follows a documented standard procedure (lookup
the closest Oracle Architecture Center reference → confirm components
→ author absolute_layout → spec validator → render → visually verify)
and ships persistent guardrails so layout regressions can't recur.

Persistent procedure changes (apply to all users, all sessions):
- tools/diagram_spec_validator.py — geometry checks (CONTAINER_TOO_THIN,
  CONTAINER_PADDING_VIOLATION, LABEL_OVERFLOW_PARENT) run BEFORE either
  renderer (drawio + PPTX). Catches the subnet-collapse / label-overflow
  bugs that the post-render drawio validator missed.
- tools/oci_diagram_gen.py + tools/oci_pptx_diagram_gen.py — call the
  spec validator before emitting any output. Adds mysql / mysql_heatwave
  type aliases.
- tools/archcenter_pattern_lookup.py — scores against cached page
  descriptions (not just the 1-line summary), supports --queries for
  multi-fragment composition, and applies synonym expansion via
  kb/architecture-center/synonyms.yaml so "LB HA cross AD" matches
  "load balancer high availability availability domain".
- kb/architecture-center/synonyms.yaml — canonical synonym table
  (load balancer, autonomous database, data guard, …) used by the
  lookup scorer.

KB enrichment:
- tools/archcenter_description_fetcher.py + 121 cached _description.md
  under kb/diagram/assets/archcenter-refs/<slug>/. Removes the runtime
  dependency on docs.oracle.com when authoring specs and feeds the
  pattern-lookup scorer.
- 110+ cached .drawio / .svg / .png references for offline reuse,
  plus the OCI Toolkit v24.2 import (kb/diagram/assets/oci-toolkit-drawio).

Documentation:
- docs/skill/output-formats.md — new "Standard diagram-generation
  procedure (MANDATORY)" + geometry rules + the new validator entry.
- SKILL.md option 2 — references the mandatory procedure.
- README.md — describes the spec validator, archcenter_pattern_lookup
  and description fetcher, and updates the KB-health table.

Tooling that backs the procedure (cumulative across recent sessions):
tools/archcenter_case_runner.py, archcenter_batch_driver.py,
archcenter_zip_downloader.py, drawio_visual_validator.py,
drawio_fidelity_eval.py, harvest_drawio_icon.py, import_oci_library.py,
oci_pptx_diagram_gen.py, oci_pptx_render.py, refresh_pptx_icon_index.py.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 21:15:21 -03:00
root
9b4d04cf34 Make discover count machine-readable for CI parsing
The workflow's grep-on-free-text approach was fragile: local run correctly
extracted 162, but in the CI run the 'Open issue' step was skipped, meaning
new_count ended up as 0 after parsing. Likely causes: stdout buffering,
color codes, or shell differences between local and the Gitea runner's
shell.

Fix: tools/refresh_sku_catalog.py --discover now emits a deterministic
last-line marker `DISCOVER_MISSING_COUNT=<n>`. The workflow parses that
with sed (anchored, unambiguous) instead of the human-facing summary
line. Also added a diagnostic echo so the parsed value shows up in CI
logs for future debugging.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 12:43:06 -03:00
root
874d40d38a Improve SKU catalog hygiene and BOM accuracy
- 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
9d5cda8986 Fix BOM workbook monthly totals 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
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
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
- 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
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
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
20be7c297e Diagram generator calibrated from 37 Oracle ref architectures + KB health tooling
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
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
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
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
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
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
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
9d269e902b initial version 2026-03-18 18:03:44 -03:00