Files
hips/HIPs/hip-1116-content.md
zeekayandHanzo Dev 7a9dcac628 What each runtime implements of the Hanzo corpus
An audit read the code and found the proposal that specifies it. Go reaches
all 122 capability proposals and 64 of the 121 other Standards Track ones;
Rust has 35, mostly the operator and the CLI; C++ has three, because the
complete original C++ in the estate is a ZAP handler, a bot nothing specifies,
and authored kernels inside forked CUDA and Metal crates.

    | | shipped | partial | none | not assessed |
    | Go   | 146 | 33 | 1 |  80 |
    | C++  |   1 |  2 | 0 | 257 |
    | Rust |  10 | 25 | 1 | 224 |

The large "not assessed" columns are the point rather than a gap. The model and
training specs are Python, the frontend and design-system proposals are
TypeScript, and recording `none` against those would read as a search that
came up empty when the honest statement is that the runtime was never the
question. Governance, Meta and Process are not graded at all.

Six proposals are Final with nothing found in Go and are left unwritten rather
than demoted: 0065, 0089, 0098, 0103, 0521 and 0902. HIP-0521 answers itself,
its own section reading "Not yet implemented". Three of the others name a
canonical Go file in consensus/protocol/auth that nobody wrote, in a package
where the four neighbouring proposals' files all exist with tests beside them.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-05 19:18:13 -07:00

5.0 KiB

hip, title, author, type, category, capability, status, implementation-go, created, requires
hip title author type category capability status implementation-go created requires
1116 Content — The Marketing Loop Hanzo AI Standards Track Interface content Final shipped 2026-08-20 HIP-0026, HIP-0139

HIP-1116: Content — The Marketing Loop

Abstract

/v1/content is the marketing content loop: draft with the model and the studio, move an item through one lifecycle, publish it to the brand's connected channels, and read the queue board across doctypes. It is implemented in hanzoai/cloud apps/content as a stateless orchestrator: the framework module marketing holds the documents, this capability adds only what a generic document engine cannot be — the state machine, the generation edge, the distribution edge (apps/content/content.go:21-41).

Motivation

CRUD, tenancy, permissions and install are the framework's generic surface; duplicating them here would be a second document engine to keep honest. What the generic engine cannot know is that a marketing item has exactly one legal lifecycle, that a draft can be generated, and that "published" means external side effects happened — those three are this capability.

Specification

The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY are to be interpreted as in RFC 2119.

§1 It owns no store

Documents live in the framework module marketing; this subsystem opens no store of its own (apps/content/content.go:40-41). Its state is the swappable edges — generator, distributor, storefront (apps/content/content.go:47-52).

§2 The lifecycle is enforced at the storage boundary

For every publishable doctype, before_save hooks enforce two rules no matter who writes — the /v1/content endpoints, a raw framework PUT, the console's generic renderer, or an automations flow step (apps/content/hooks.go:13-26):

  1. status-edge legality — the one state machine in lifecycle.go;
  2. server-owned fields (external_ids, published_at) may only be written by a trusted in-process op, never by a client.

Both are pure gates: a refused write is 422, and distribution stays in the orchestrator, never in the engine.

§3 The addresses, and the one implementation

GET /v1/content/lifecycle, GET /v1/content/board, GET /v1/content/channels, POST /v1/content/generate, POST /v1/content/publish, and POST /v1/content/{doctype}/{name}/transition — all typed (apps/content/typed_wire_test.go). Every exported op is called both by the handler and by the automations connector, so a human console, a flow, an MCP tool call and a headless bot drive the same single implementation (apps/content/content.go:36-39). Publish is idempotent per channel and answers in_progress having posted nothing when it loses the per-item lease to a live publisher (apps/content/zipdoc_gen.go:71).

§4 Tenancy and money

Every handler resolves its tenant through principal.Org (HIP-0026) and scopes strictly to it (apps/content/content.go:34-35). The capability is metered (plugin/content/main.go:21), and the meter is split on who can attribute the work: text drafting rides the platform AI plane — identity travels on the ChatRequest, so the one inference meter bills the tokens (apps/content/generate.go:27-31) — while studio renders are GPU work the AI plane never sees, so content is their sole meter: Bill.Gate before the render (fail-closed 402) and the debit recorded after (apps/content/studio_render.go:121-123,172). The metered-apps registry carries content for exactly that render fee.

§5 Events, telemetry, stage, upstreams

It publishes no events on the platform bus; a publish's external side effects are posts to the org's own connected channels through the distributor edge. It emits nothing to observability beyond the request span — inference telemetry belongs to the AI plane that serves it. Its stage is beta: a vertical application. It derives from no upstream; the document engine is our own framework module.

Rationale

Enforcing the lifecycle in before_save hooks rather than in the handlers is the load-bearing choice: the framework surface is generic and open, so a rule enforced only in this package's handlers is a rule any other writer skips. At the storage boundary there is no other writer. The cost is that the hooks must stay pure — side effects in a gate would fire on every writer too — which is why distribution lives in the orchestrator.

Security Considerations

The wrong implementation lets a client write external_ids or published_at directly — forging the record that something was published, or aiming a re-publish at someone else's external post ids. The server-owned-fields gate exists for that. The render meter is the second exposure: GPU work billed to nobody is free compute, so the gate runs before the render and fails closed on a frozen or broke org. Tenancy rides the validated principal on every path, including the connector-driven ones.

References

  • HIP-0026 — Identity and Access Management
  • HIP-0139 — Capability

Released under CC0 1.0 Universal Public Domain Dedication.