Skip to main content

GOVERNANCE

ZARA’s Hecate

Purpose

Hecate is the governance and integrity subsystem of Ask ZARA.

Its role is not to answer questions, modify documentation, or approve changes —
its role is to detect, surface, and explain governance drift across the ZAYAZ knowledge system.

Hecate exists to protect institutional truth, not to enforce authority.


Core Principle

Hecate does not decide what is correct.
Hecate detects when the system is drifting away from its own rules.

Hecate is:

  • A sentinel
  • An early-warning system
  • A guardian of boundaries

Hecate is not:

  • An editor
  • An approver
  • A reviewer
  • A process owner

Position in the System

Hecate operates alongside Ask ZARA — not inside it.

ComponentResponsibility
Docusaurus DocsStable system of record
JiraExecution & traceability
ConfluenceEvolving engineering narrative
HubSpot (RFCs)Change governance
Ask ZARAKnowledge retrieval & explanation
HecateGovernance integrity & drift detection

Ask ZARA answers questions.
Hecate flags when answers may be compromised.


What Hecate Monitors

Hecate evaluates relationships, not raw content.

Primary Inputs

  • Documentation metadata (Spec IDs, sections, last_updated)
  • <JiraNeed /> tags
  • Jira issue metadata (status, links, Spec ID)
  • Jira epic structure
  • RFC metadata from HubSpot (status, page_url)
  • (Later) Confluence metadata and Jira ↔ Confluence links

Hecate does not interpret intent or rewrite content.


What Is a Violation?

A violation is not an error.

A violation is a signal that a governance rule may have been breached.

Hecate treats violations as traffic signals, not enforcement actions.


Violation Classes

1. Source-of-Truth Violations (Highest Severity)

Rule
Docusaurus Docs are the system of record.

Examples

  • Jira or Confluence contradicts documented contracts
  • Acceptance criteria redefine documented behavior
  • External narrative diverges from published specs

Hecate Behavior

  • Raises explicit warning
  • Cites the Playbook
  • Defers to Docs as authoritative

2. Traceability Violations

Rule
Every execution item must trace back to Docs.

Examples

  • <JiraNeed /> without a Jira issue
  • Jira issue without Spec ID
  • Epic exists but has no children
  • Doc references a missing epic

3. Freshness & Drift Signals

Rule
Stabilized work must be promoted to Docs.

Examples

  • Jira marked Done but Docs unchanged
  • RFC marked Published but no doc update
  • High Jira churn with stale documentation

These are warnings, not accusations.


4. Governance Process Signals

Rule
If it’s not approved via RFC, it does not exist in the Manual.

Examples

  • Doc changes without an RFC
  • RFC approved but not deployed
  • RFC rejected but execution continues

Severity Model

Hecate uses a graduated severity model to avoid alarm fatigue.

LevelMeaningNature
P0Governance brokenHard violation
P1High risk of wasted workImmediate warning
P2Growing entropySoft warning
P3Hygiene / qualityAdvisory signal
P4Observational insightInformational

Only P0–P2 are considered violations.
P3–P4 are system health signals.


How Hecate Surfaces Issues

Hecate never blocks workflows.

Primary Channels

  • Inline trust notices in Ask ZARA answers
  • System dashboards (e.g. /system/violations)
  • Cross-spec governance views

Optional Channels (Severity-based)

  • Slack notifications
  • Email summaries
  • Jira “Validation” issues (optional, explicit)

Example Hecate Signal

⚠️ Possible source-of-truth violation

The ZAYAZ Manual states that API contracts are immutable once published,
but Jira issue ZYZ-281 describes a breaking change.

According to the Documentation & Delivery Playbook,
Docs take precedence.

Hecate does not fix — it flags.


What Hecate Must Never Do

🚫 Modify Docs
🚫 Approve changes
🚫 Override human decisions
🚫 Invent governance rules
🚫 Treat Jira or Confluence as authoritative over Docs

Hecate protects the system — it does not control it.


Relationship to Ask ZARA

Ask ZARA may:

  • Reference Hecate signals
  • Adjust confidence indicators
  • Surface governance context

Ask ZARA must never:

  • Suppress answers because of violations
  • Rewrite content to “fix” violations

Design Philosophy

Most AI systems answer questions.

Hecate ensures the questions remain answerable.

This transforms Ask ZARA from:

  • A search assistant

Into:

  • A governance-aware system
  • A drift detector
  • An institutional memory guardian

North Star

Truth degrades silently.
Hecate exists to make drift visible.


Hecate Audit Rules v1

#Rule (type)What it detectsSeverityDeterministic checkInputsSuggested routing
1missing-jira-key
JiraTaskUnlinked(unlinked)
 exists but has no jiraKey
P0Parse MDX → find <JiraNeed …/>→ if jiraKey missing/blankDocs MDXDashboard + Slack/Email
2jira-issue-not-foundjiraKey exists in MDX but not found in progress.json(or Jira API)P0Validate key pattern + lookup in progress.json issues (optional: Jira /issue/{key})Docs MDX + progress.json(+ Jira API)Dashboard + Slack/Email
3jira-missing-doc-backlinkJira issue exists but has no remote link back to SpecsP1Jira issue remotelinks contain no URL starting with DOCS_BASE_URLJira API (remotelink)Dashboard + Slack/Email (to governance owner)
4epic-declared-in-docs-but-not-foundDocs frontmatter declares jira.epic, but progress index has no matching epic entryP0Docs specId has epicKey, but progress.epics[specId] missing or epicKey mismatchDocs frontmatter + progress.jsonDashboard + Slack/Email
5epic-has-no-childrenDoc has jira.epic but epic has 0 childrenP1progress.epics[specId].counts.total === 0Docs frontmatter + progress.jsonDashboard (Slack if >24h / “age” threshold)
6jira-not-linked-to-doc-epicA doc’s jiraKey exists but is under a different epic/spec in the progress indexP1jiraIssueByKey[jiraKey].specId !== doc.specId OR epicKey mismatchDocs MDX + progress.jsonDashboard + Slack/Email (PM + governance owner)
7done-but-doc-staleEpic has recent activity / done work but docs appear staleP2if epic.updatedMax > doc.last_updated + staleDaysprogress.json+ Docs frontmatterDashboard (digest optional)
8rfc-published-but-docs-unchangedHubSpot RFC is Published for a page_url but doc unchanged since RFC updatedP2(raise later if needed)Compare hubspot.updatedAt(stage=Published)vs doc.last_updatedHubSpot metadata export + Docs frontmatterDashboard + Slack/Email (owner)

Notes on severity (why P0/P1/P2)

  • P0 = traceability is broken at the leaf level (the thing you think is being executed can’t even be reliably located).
  • P1 = execution is disconnected from authority (Jira exists but isn’t anchored to Docs properly, or specs/IDs don’t line up).
  • P2 = system drift / staleness (not necessarily wrong, but risky and should be surfaced).

Violation object shape (with Canonical violation types v1)

This format is designed to:

  • work for dashboards + sorting + filtering
  • be “attachable” to Ask ZARA answers
  • survive growth (Confluence, richer refs) without breaking

/workspaces/zayaz-docs/docusaurus/src/shared/hecate-types.ts:

// src/shared/hecate-types.ts

export type Severity = "P0" | "P1" | "P2" | "P3" | "P4";

export type ViolationType =
| "missing-jira-key"
| "jira-issue-not-found"
| "jira-missing-doc-backlink"
| "jira-not-linked-to-doc-epic"
| "epic-declared-in-docs-but-not-found"
| "epic-has-no-children"
| "spec-has-epic-but-epic-empty"
| "done-but-doc-stale"
| "orphan-jira-specid"
| "rfc-published-but-docs-unchanged";

export type Violation = {
id: string; // stable hash
severity: Severity;
type: ViolationType;

title: string;
message: string;
ruleRef?: string;

scope: "need" | "section" | "page" | "spec" | "system";

specId?: string;
doc?: {
id?: string;
path?: string;
sourceFile?: string;
lastUpdated?: string;
};
section?: {
anchor?: string;
heading?: string;
needId?: string;
};

jira?: {
key?: string;
epicKey?: string;
url?: string;
updated?: string;
};

rfc?: {
pageUrl?: string;
ticketId?: string;
stage?: string;
updated?: string;
};

evidence?: Array<{
source: "docs" | "jira" | "hubspot" | "confluence";
note: string;
}>;

suggestedFix?: {
kind: "run-script" | "edit-doc" | "update-jira" | "review-rfc";
label: string;
command?: string;
link?: string;
};

detectedAt: string;
};

Severity mapping

ViolationTypeSeverity
missing-jira-keyP0
jira-issue-not-foundP0
epic-declared-in-docs-but-not-foundP0
jira-not-linked-to-doc-epicP1
epic-has-no-childrenP1
jira-missing-doc-backlinkP2
done-but-doc-staleP2
rfc-published-but-docs-unchangedP3

Rule definitions with title/message templates + suggestedFix

1. missing-jira-key (P0)

When: <JiraNeed /> exists but no jiraKey.

  • scope: need (or section if you don’t want per-need granularity)
  • title: Unlinked JiraNeed
  • message template:
    • A tag exists but has no jiraKey. Execution cannot be traced to Jira.
      JiraTaskUnlinked(unlinked)
  • evidence:
    • source=docs: Found without jiraKey in section {anchor}
      JiraTaskUnlinked(unlinked)
  • suggestedFix:
    • run-script: npm run sync:jira-needs
    • edit-doc: “Add jiraKey to tag”
{
"type": "missing-jira-key",
"severity": "P0",
"title": "Unlinked JiraNeed",
"message": "A <JiraNeed/> tag exists but has no jiraKey. Execution cannot be traced to Jira."
}

2. jira-issue-not-found (P0)

When: MDX contains jiraKey, but it’s not present in your Jira index (progress.json or dedicated Jira ETL).

  • scope: need
  • title: Jira issue not found
  • message:
    • The docs reference Jira key {jiraKey}, but it was not found in the Jira index.
  • evidence:
    • docs: jiraKey={jiraKey} present in MDX
    • jira: key not found in progress.json
  • suggestedFix:
    • run-script: npm run jira:progress-index (and/or Jira ETL)
    • update-jira: verify key exists / permissions

When: Jira issue exists but has no remote link back to Docs (DOCS_BASE_URL).

  • scope: need
  • title: Jira issue missing Docs link
  • message:
    • Jira issue {jiraKey} has no web link back to the ZAYAZ Manual. Traceability is incomplete.
  • evidence:
    • jira: No remotelink matching ${DOCS_BASE_URL}
  • suggestedFix:
    • run-script: npm run jira:backfill-links (or sync:jira-needs for new)
    • update-jira: add remote link manually

4. jira-missing-spec-id (P1)

When: Jira issue exists but Spec ID custom field is empty.

  • scope: need
  • title: Jira issue missing Spec ID
  • message:
    • Jira issue {jiraKey} is missing Spec ID. It cannot be reliably tied to a spec.
  • suggestedFix:
    • update-jira: set Spec ID field
    • run-script: (optional) re-sync/patch script if you automate it later

5. spec-has-epic-but-epic-empty (P1)

When: doc has jira.epic, but epic has 0 children.

  • scope: spec
  • title: Epic has no child issues
  • message:
    • Spec {specId} links to epic {epicKey}, but no child issues were found.
  • evidence:
    • progress: counts.total = 0
  • suggestedFix:
    • update-jira: add/link child issues to epic
    • run-script: npm run jira:progress-index (after fixing)

6. done-but-doc-stale (P2)

When: Jira activity is newer than doc last_updated by threshold (e.g. 7 days), OR epic has done work but doc hasn’t moved.

  • scope: spec (or page)
  • title: Documentation may be stale
  • message:
    • Jira activity for {specId} is newer than the doc update timestamp. Consider promoting stabilized outcomes to Docs.
  • evidence:
    • docs: last_updated={...}
    • jira: updatedMax={...}
  • suggestedFix:
    • edit-doc: update page + bump last_updated
    • (optional) create Jira “Validation” task later

7. orphan-jira-specid (P1)

When: Jira issue has Spec ID that does not exist in docs index.

  • scope: need (or system if you group)
  • title: Orphaned Jira Spec ID
  • message:
    • Jira issue {jiraKey} references Spec ID {specId}, but no matching doc id was found.
  • suggestedFix:
    • edit-doc: add/create doc with that id, or correct Spec ID in Jira
    • update-jira: fix Spec ID

8. rfc-published-but-docs-unchanged (P2)

When: HubSpot RFC ticket is Published (or equivalent stage), but doc last_updated is older than RFC updated time.

  • scope: page
  • title: RFC published but docs not updated
  • message:
    • An RFC for this page is marked Published in HubSpot, but the manual has not been updated since.
  • suggestedFix:
    • review-rfc: open HubSpot ticket
    • edit-doc: implement approved change

Architecture

  • hecate-types.ts = law
  • knowledge-audit.ts = enforcement
  • ZARA = messenger
/workspaces/zayaz-docs

├─ docusaurus/
│ └─ src/
│ └─ shared/
│ ├─ jira-types.ts
│ ├─ hecate-types.ts
│ └─ trust-types.ts

├─ scripts/
│ └─ audit/
│ └─ knowledge-audit.ts ← imports hecate-types

└─ docusaurus/static/
└─ system/
└─ violations.json ← generated

How imports should look

From Docusaurus / React / Ask ZARA

import type { Violation, Severity } from "@site/src/shared/hecate-types";

(Docusaurus aliases @site → docusaurus root)

From audit scripts (Node)

import type { Violation } from "../../docusaurus/src/shared/hecate-types";

(relative path from scripts/audit/knowledge-audit.ts)

Explicit rule

If a type is used by both build scripts and the site, it lives in docusaurus/src/shared/.



GitHub RepoRequest for Change (RFC)