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>
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>
Diego flagged that Codex, when authoring an absolute_layout, fell
back to grepping ``examples/`` for AWS/OCI multicloud patterns even
though the procedure said not to. The reason was real: the lookup
tool returns a cached ``.drawio`` (canonical Oracle geometry) but
no canonical ``absolute_layout.yaml`` template, so the agent had no
YAML scaffold to copy the spec shape from.
Tighten the rule rather than ban it outright:
• Cached ``.drawio`` = GEOMETRY source. Container nesting,
padding, AD/subnet placement, icon choices come from there.
• ``examples/`` = YAML scaffold reference ONLY (which fields
exist, how connections are authored, fontSize unit). Do NOT
copy geometry numbers — those came from a different topology.
Rule of thumb baked into the SKILL: if you're copying (x, y, w, h)
from examples/, stop and copy from the cached .drawio instead.
(Codex copy auto-synced via the pre-commit hook installed earlier.)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three-layer defense to keep root SKILL.md (Claude Code) and
.agents/skills/oci-deal-accelerator/SKILL.md (Codex) byte-aligned.
Without this, Claude Code and Codex can drift and give the user
contradictory instructions — exactly the failure mode that produced
the workload-driven-mode incident on 2026-04-25.
Layers (least → most enforcement):
1. Local pre-commit hook (.githooks/pre-commit, opt-in via
``make install-hooks`` which sets core.hooksPath). When SKILL.md
is staged, auto-runs scripts/sync-skill.py and stages the
regenerated .agents/ copy in the same commit. Idempotent.
2. ``make install-hooks`` target + a tip line in ``make venv``'s
output so any new clone discovers the hook setup.
3. CI gate (.gitea/workflows/skill-sync.yaml) on every push/PR
touching SKILL.md or the .agents/ copy. Runs
``scripts/sync-skill.py --check`` and fails the build on drift.
Catches anyone who skipped the hook.
README documents the rationale and the three layers.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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>
A Codex session showed the gap: option 2's prose asked the user to
describe the architecture but only mentioned the output formats in
passing ("if you want X / if you want Y"), so the agent never asked
which format(s). Codex also skipped the reference-architecture lookup
and went straight to grepping ``examples/`` for pre-existing specs —
``examples/`` is previous user output, not the authoritative Oracle
catalog.
Two persistent fixes for any agent (Claude Code, Codex, Cursor, …):
1. Option 2 now asks two explicit questions in one message and waits
for both answers before doing anything: (1) describe / paste spec,
(2) pick output format(s) — drawio, native PPTX, or both.
2. The procedure is restated as a numbered list directly under
option 2 (no longer a single-sentence reference to
docs/skill/output-formats.md). Step 1 explicitly says use
``archcenter_pattern_lookup.py`` against the catalog and explicitly
forbids using ``examples/`` as a reference source.
Synced to the Codex copy at .agents/skills/oci-deal-accelerator/SKILL.md
via ``make sync-skill`` so both agents see the same instructions.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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>
Why this set of changes:
- KB pricing was drifting silently — domain files (database.yaml,
storage.yaml, etc.) had prices 30-800% off the live Oracle API and
nobody read them. The skill was auditing as stale on every check
with no path to fix it.
- The skill itself violated Anthropic's spec (`name` field had
uppercase/spaces) and was over the 500-line guideline (647 lines),
hurting discovery and load performance.
- Welcome flow occasionally improvised the menu instead of reading
SKILL.md, missing options.
Pricing — single source of truth, fully automated:
- Extend tools/refresh_sku_catalog.py with --refresh-domain compute,
pulls shape-level prices from the Oracle public pricing API
(apexapps.oracle.com), preserves manual fields (notes, GPU specs,
free-tier annotations, estimation_helpers), recomputes derived
monthly values, and protects $0 free-tier prices from overwrite.
- Delete 12 redundant pricing/<domain>.yaml files. They duplicated
oci-sku-catalog.yaml with worse abstractions and were nobody's
source of truth (no tool consumed them).
- Migrate the genuinely valuable knowledge from those 12 files
(billing models, BYOL rules, free-tier rules, ECPU vs OCPU,
X11M elastic model, hyperscaler comparisons, service nuances)
into kb/field-knowledge/pricing-knowledge.yaml — non-numeric,
no refresh needed.
- Result: pricing freshness check goes from 13 stale files to 0.
KB freshness automation:
- Add tools/kb_freshness.py — wrapper around kb_linter.check_freshness()
with --check, --auto-refresh, --json, --quiet modes. Bridges stale
files to their refresh tools (SKU catalog, compute domain, arch
center). Wired into the welcome flow as a pre-flight banner that
asks the user before refreshing.
- Fix pre-existing kb_linter bug: it crashed on the 45 multi-doc
YAML files (frontmatter + body pattern) because it used safe_load
instead of safe_load_all. Freshness check was effectively dead.
- Standardize timestamp field: linter now accepts last_verified,
last_updated, and last_refreshed; refresh_arch_catalog writes
last_verified instead of last_refreshed.
- Add make freshness / make freshness-refresh targets.
Skill alignment with Anthropic Agent Skills best practices:
- Rename `name: OCI Deal Accelerator` to `oci-deal-accelerator`
to comply with the [a-z0-9-]{1,64} spec.
- Refactor SKILL.md from 674 to 445 lines via progressive disclosure:
extract WA review output format, ECAL readiness format, and output
conventions into docs/skill/*.md referenced from the main file.
- Add scripts/sync-skill.py + make sync-skill: source of truth is
root SKILL.md, .agents/skills/oci-deal-accelerator/SKILL.md is
auto-generated. make lint validates sync.
- Add evaluations/ with 3 manual baseline scenarios (welcome-flow,
full-proposal, wa-review) per the Anthropic best-practices guidance
to "build evaluations first."
Welcome flow hardening:
- Tighten CLAUDE.md to MANDATE reading SKILL.md before showing the
menu (no improvising), and document the freshness pre-flight check
with the ask-before-refresh user flow.
- Update SKILL.md welcome flow to instruct: parse kb_freshness JSON,
show banner with stale count + oldest file, prompt user to refresh
(only when an automated tool exists), fall back silently on errors.
Linter hygiene (zero remaining issues):
- Expand config/kb-tags.yaml taxonomy with features, operations,
metrics, limitations sections covering 31 previously-unknown tags
used in field findings (rac, ecpu, refreshable-clone, hnsw, etc.).
- Assign owners for kb/compatibility/, kb/competitive/,
kb/well-architected/ (Diego Cabrera as default until team grows);
kb/pricing/ marked as "Auto-refreshed" since it no longer needs
human ownership.
- kb_linter accepts top-level `date` as fallback for contributor
block; migrate FF-202603-008 from legacy `reported_by` to
contributor block.
- Result: linter goes from 45 issues to 0.
Other:
- Recompute estimation_helpers monthly values in compute.yaml after
the price refresh (they were derived from the old E5/A1 numbers).
- Add kb/README.md — contributor guide (directory map, frontmatter
spec, refresh tooling, review cadence).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- New tools/oci_bom_gen.py: generates .xlsx BOM from YAML spec with
Oracle Redwood styling, Excel formulas, and Oracle disclaimer.
Supports standard BOM (--output) and AppCA import format (--appca)
- New tools/refresh_sku_catalog.py: refreshes SKU catalog prices from
Oracle's public pricing API (apexapps.oracle.com)
- New kb/pricing/oci-sku-catalog.yaml: ~160 OCI SKUs across 14
categories, validated against Oracle API
- New templates/bom-spec.yaml: input spec template for BOM generation
- Add SA TOOLS section to SKILL.md (options 13-14)
- Register BOM generator in oci_output.py