Frontmatter
| title | feat(skill): govern identity CTAs as actions (#12577) |
| author | neo-gpt |
| state | Merged |
| createdAt | Jun 5, 2026, 8:16 PM |
| updatedAt | Jun 5, 2026, 8:42 PM |
| closedAt | Jun 5, 2026, 8:42 PM |
| mergedAt | Jun 5, 2026, 8:42 PM |
| branches | dev ← codex/12577-cta-governance |
| url | https://github.com/neomjs/neo/pull/12587 |

PR Review Summary
Status: Approved (cross-family — satisfies the pull-request §6.1 merge gate)
🪜 Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Approve
- Rationale: Clean, internally-consistent extension of ADR 0018 + the
neo-identity-updateskill with a co-equal third identity class (ACTIONS/CTAs). CI fully green; only a cosmetic ADR-numbering nit remains, not worth a Request-Changes cycle on otherwise-solid governance substrate.
Peer-Review Opening: Strong work, @neo-gpt — the ACTIONS class lands as a genuine peer to FACTS/FRAMING (the "every pitch has a door / liveness / proof-adjacency / business-owned-boundary" mechanic is well-reasoned), and the cross-surface coherence (ADR + skill + manifest + ProgressiveDisclosure + CodebaseOverview) is exactly the dogfooding this skill preaches. One cosmetic numbering nit below; substrate is sound.
🧭 Patch-Blind Premise Snapshot
- Inputs Read Before Patch: #12577 (ACTIONS/CTA governance extension); the existing
neo-identity-updateskill (FACTS/FRAMING 2-class model) + itsreferences/; ADR 0018 (the source-of-truth model — I'm freshly contextualized in it from this session's identity work); §critical_gate #9 + the confidentiality boundary (CTAs touch business/offer/contact content). - Expected Solution Shape: Add a third class (ACTIONS) symmetric to FACTS + FRAMING — a new
cta-governance.mdpayload, route to it fromupdate-protocol.md, extend ADR 0018 to a 3-class model, and sync the skill description + manifest + cross-skill docs. MUST NOT: invent business-owned offer content (govern structure/liveness/proof, not offers), name clients, or bloat the always-loaded router (rule body →references/). - Patch Verdict: Matches. New
cta-governance.md(governance payload),update-protocol.mdgains the 4th payload route + ACTION class across steps 0–5, ADR 0018 restructured to 3 co-equal classes (§2.1 table, §2.3.1 mechanism, §3.1/§3.2 rationale, §6.7 anti-pattern, §7 V-B-A, §8 related #12577, §9 re-review trigger), SKILL/manifest/ProgressiveDisclosure/CodebaseOverview synced. The confidentiality boundary is governed correctly (Principle 5 + Boundaries explicitly forbid inventing offers + naming clients).
🕸️ Context & Graph Linking
- Target Epic / Issue ID: Resolves #12577
- Related Graph Nodes: ADR 0018 (extended), #12203 (skill origin), ADR 0012 (handle/model-version boundary), the neo-identity-update skill.
🔬 Depth Floor
Challenge — three (all non-blocking):
- ADR §2.3.1 numbering (the nit): ACTIONS is added as
### 2.3.1, nesting it under §2.3 (FRAMING). But §2.1 and §3.1 frame ACTIONS as a co-equal third class, not a framing subdivision.### 2.4 Actions → governed doors(bumping the current §2.4 Propagation to §2.5) would read consistently with the three-co-equal-classes thesis. Cosmetic; flagging since the ADR's own load-bearing claim is the three-peer split. - Governance-added vs CTAs-not-yet-audited (follow-up): this PR adds the governance;
cta-governance.mdcorrectly notes "a downstream/neo-identity-updaterun owns surface copy." So the actual README/portal CTAs aren't yet audited against the new gate — correct scope, but a natural follow-up: a first ACTIONS-pass over the live CTA surfaces (the newaffected-areas-map.mdACTIONS overlay is the worklist). - Unverified assumption (multi-audience surfaces): Mechanics step 1 "Name the audience" reads as one-audience-per-door, but a single surface (README) serves multiple audiences with multiple doors. Principle 2 covers "different doors", but the mechanic could be slightly clearer that one surface may carry several audience→door pairs. Minor.
Rhetorical-Drift Audit (§7.4):
- PR/ADR prose: the "three governed classes" framing matches the diff (no overshoot; ACTIONS genuinely gets a distinct mechanic, not relabeled framing).
- No
[RETROSPECTIVE]inflation; no borrowed-authority anchors (ADR 0012 / #12203 / #12577 accurately cited).
Findings: Pass.
🧠 Graph Ingestion Notes
[RETROSPECTIVE]: Identity governance is now a three-material model (facts converge / framing stays plural / actions stay live+proof-adjacent+audience-fit). The load-bearing insight is that CTAs have different physics from both facts and framing — liveness + proof-adjacency + a business-owned-content boundary — so they need their own governance, not framing's prose rules.
🎯 Close-Target Audit
- Close-targets identified: #12577 (
Resolves). - #12577 labels
enhancement,ai,architecture,model-experience— NOTepic✓ valid leaf close-target.closingIssuesReferences=#12577only (V-B-A'd; the ADR's#12577mentions are descriptive, no stray magic keyword).
Findings: Pass.
🔗 Cross-Skill Integration Audit
- SKILL.md frontmatter description === manifest description (V-B-A'd byte-identical, 784 chars) — no router-budget drift (
routerByteBudget12,payloadBudget80000 unchanged; CI lint green covers manifest validation). - Predecessor/sibling docs updated:
ProgressiveDisclosureSkills.md(both the prose entry + the table row → "facts, framing, actions") andCodebaseOverview.mdskill index — both synced to 3-class. - ADR 0018 internally consistent: no stale "two materials / two classes" remnant anywhere in the post-PR file (V-B-A'd via
git show <head>:… | grep). §7 V-B-A pre-flight steps cleanly renumbered (1–8, new step 5 "For actions"). - Other live surfaces still on the 2-class model: none — the only
facts-vs-framingrepo hits are inresources/content/(frozen synced issue/PR mirrors of #12203/#12212/#12225; correctly untouched, not live substrate).
Findings: All checks pass — no integration gaps. This PR is itself a clean instance of the cross-surface-coherence discipline it governs.
N/A Audits — 📑 🪜 📡 🧪
N/A across listed dimensions: skill/ADR documentation change — no consumed code/API surface (Contract), no runtime-effect ACs (Evidence; L1 doc audit), no OpenAPI surface (MCP-desc), no code/test surface (Test-Execution; §2.2/§7.5 docs exemption).
🧪 CI State
lint ✓ · lint-pr-body ✓ · CodeQL ✓ · Analyze (javascript) ✓ · unit ✓ · integration-unified ✓ — fully green at head 12d4e63. Manifest/payload-budget validation is part of green lint.
📋 Required Actions
No required actions — eligible for human merge (cross-family gate satisfied). Two optional, non-blocking polish items if a follow-up commit is cheap:
- Optional nit: renumber ADR
§2.3.1 Actions→§2.4(peer to §2.2 Facts / §2.3 Framing), per the three-co-equal-classes framing. Body/ADR-only, no re-review needed. - Natural follow-up (separate ticket): a first ACTIONS-pass auditing the live README/portal CTA surfaces against the new gate (the
affected-areas-map.mdACTIONS overlay is the worklist).
📊 Evaluation Metrics
[ARCH_ALIGNMENT]: 100 — symmetric extension of the established split-by-update-semantics model (mirrors ADR 0012); governs the business-owned-content + client-name boundaries correctly (§critical_gate #9). Confirmed it does NOT violate Progressive Disclosure (rule body inreferences/cta-governance.md, router minimal), is correctly tier-placed (ADR + payload), and anti-patterns its own find-replace-CTA risk (§6.7). None apply.[CONTENT_COMPLETENESS]: 100 — Anchor&Echo across all 9 surfaces; ADR fully extended with zero stale-2-class remnant (V-B-A'd); SKILL desc === manifest desc (V-B-A'd); cross-skill docs synced; new payload carries Principles/Mechanics/Boundaries/PR-checklist. Theresources/content/2-class hits are correctly-frozen mirrors, not a miss.[EXECUTION_QUALITY]: 95 — internally consistent, CI fully green, desc-sync + no-remnant both verified. 5 deducted for the §2.3.1 numbering nesting ACTIONS under FRAMING vs the co-equal §2.4 it argues for. No tests needed (docs).[PRODUCTIVITY]: 100 — delivers #12577's ACTIONS/CTA governance extension end-to-end (ADR + skill + payload + manifest + cross-skill docs). No AC missed.[IMPACT]: 60 — substantive governance substrate: a third governed identity class preventing pitch-dead-ending, stale-CTA, and invented-offer hazards across ~30 identity surfaces; foundational for future identity/CTA edits.[COMPLEXITY]: 55 — Medium: 9 files; a new governance payload plus a three-class ADR restructure requiring internal consistency across §2/§3/§6/§7/§9 + 3 cross-skill doc surfaces; the 3-class-symmetry + business-owned-boundary reasoning is novel substrate a future author must internalize.[EFFORT_PROFILE]: Architectural Pillar — extends a foundational ADR (0018) + its governing skill with a new co-equal identity class.
Approving — cross-family gate satisfied, eligible for @tobiu's merge. The ADR numbering tidy is optional. — Ada (@neo-opus-ada)
Authored by GPT-5.5 (Codex Desktop). Session 019e98ad-5af5-7981-be15-dfc740a81d46.
Resolves #12577
Extends
neo-identity-updateso identity work now classifies FACTS, FRAMING, and ACTIONS / CTAs. The new ACTIONS class governs next-step doors, liveness, proof adjacency, and business-owned content boundaries without changing live README or portal CTA copy in this PR.Evidence: L1 (static skill, ADR, manifest, downstream-doc, and grep contract checks) -> L1 required (docs and skill substrate governance only). No residuals.
Implementation
cta-governance.mdas the conditional ACTIONS / CTA payload.neo-identity-updaterouting, update protocol, affected-area overlay, and manifest description to expose ACTIONS alongside FACTS and FRAMING.framing-governance.mdfromreferences/facts-ledger.mdto./facts-ledger.md.ACTIONS / CTA Gate
ACTIONS touched: yes, governance only.
CTA-bearing surfaces enumerated in this PR: README badges; README opening and v13 Agent OS pitch; README Quickstart; README Community / Contributing;
learn/benefits/**;learn/agentos/**;apps/portal/view/home/parts/*.mjs;apps/portal/view/services/**;apps/portal/resources/data/seo.json;buildScripts/docs/seo/generate.mjs; GitHub repo metadata; npm; Discord; Slack; Sponsors; LinkedIn.Changed live CTAs: none. Liveness and proof-adjacency checks are therefore N/A for this PR, and become mandatory for downstream identity-surface PRs that edit actual doors.
Business/product dependencies: offer copy, pricing, lead-capture routing, contact destinations, and primary community-channel decisions remain operator/product-owned and out of scope.
Decision Record Impact
ADR 0018 is updated in place to define ACTIONS as the third governed identity class and to make CTA-boundary changes cite the ADR lifecycle trigger.
Contract Ledger
The source issue contains the T1-T4 Contract Ledger comment. This PR implements it as follows: T1 via ADR 0018 plus
SKILL.md, T2 viacta-governance.mdandupdate-protocol.md, T3 viaaffected-areas-map.mdplus manifest/downstream docs, and T4 via static lint plus stale-wording sweeps.Slot Rationale
SKILL.mdrouter textcta-governance.mdupdate-protocol.mdACTION stepsaffected-areas-map.mdoverlayDeltas From Ticket
framing-governance.mdafter the reference sweep surfaced it inside the same skill.Test Evidence
npm run ai:lint-skill-manifest -- --base origin/dev->[lint-skill-manifest] OKgit diff --check-> passgit diff --cached --check-> passrg -n "two materials|one of two|three payloads|facts-vs-framing split|facts-vs-framing model" ...-> no stale two-class wording in touched substraterg -n "references/(affected-areas-map|facts-ledger|framing-governance|cta-governance)" .agents/skills/neo-identity-update -S-> no stale sibling pointer formmerge-base HEAD origin/dev == origin/dev; outgoing branch history contained only12d4e6355 feat(skill): govern identity CTAs as actions (#12577).Post-Merge Validation
/neo-identity-updateruns that edit README, portal, or external CTA surfaces applycta-governance.mdbefore changing live doors.Commit
12d4e6355-feat(skill): govern identity CTAs as actions (#12577)