TileFoundry Spec Rules¶
Principles¶
The spec is the single source of truth for TileFoundry public contracts. If a
different implementation of the same public construct would need to know a fact,
that fact belongs in docs/spec/*.md, not in code comments or plan files.
Runtime ops use one public entry per op/family. Target runtime headers may split the implementation into internal helpers, traits, or impl classes, but generated code calls the public entry and does not select implementation tiers.
Code may carry local-mechanics comments. It does not mechanically backlink every op definition to the spec. Add a short spec backlink only when a code path exists solely because a specific spec rule requires it.
Unified Entry Format¶
A spec entry shows the construct in its source defining form, with every
identifier spelled and cased exactly as in the source: a Python class
(including every HIR / TIR Op) appears as its class Name(Base): definition, a
Python function as its def name(...) -> R: signature, and a C++ construct as
its struct / class / enum / template declaration. A class MUST NOT be shown as
a call-form signature. Each entry is followed by a - constraints: list, where
every normative MUST / SHALL / SHOULD sentence lives.
The interface is concise, never a copy of the implementation: no decorators,
no registration machinery, no ParamDef plumbing, no method or function
bodies (a method appears as its ...-terminated signature). An Op's inputs
and attributes appear as annotated fields, one per line, using the source
field names; attribute defaults are kept (they are interface).
Documentation inside a block follows the industry style of its language, so it is mechanically checkable:
- Python — Google docstring style (validated by ruff's pydocstyle rules,
convention = "google"). The class or function docstring opens with a one-line summary (for a value-producing Op, state what it produces; for an effect-form Op, sayeffect form). Field roles go in anAttributes:section (name: input|attribute; role.), function parameters inArgs:, results inReturns:. Declaration lines carry no trailing role comments. - C++ — Doxygen (
/** @brief ... @tparam ... @param ... @return ... */above each declaration; aggregate members MAY use trailing///<).
A fenced block that exists to pin an ambiguous contract corner (usage, not an
interface) starts with a # example / // example marker line and is exempt
from the format checks. Example code never repeats an implementation. One
block may group a family of related signatures.
Consensus ops may be grouped when one external reference defines their
behavior. Custom TileFoundry ops and public runtime entries need their own
entry. A decorator-based mechanism appears only in the section that owns it —
the custom-op machinery (@register_op / ParamDef) in
core-ir §2.3, the visitor registries (@register_*) in
visitor-registry; anywhere else a decorator may
only appear inside an # example-marked block.
Constraints¶
Spec text is English and records the current contract only. It must not mention plan files, milestones, task IDs, PR numbers, commit hashes, chat message IDs, agent names, version stamps, test plans, or future/TODO sections.
A construct has one owning section. Other specs link to that section instead of restating its definition. Keep examples only when they pin down an otherwise ambiguous contract corner.
Referring To A Section¶
Every reference to a spec section is a markdown link:
[<doc> §<number>](<path>#<github-anchor>)
path is relative inside docs/spec (./runtime.md), repository-root
everywhere else (docs/spec/runtime.md). The anchor MUST name the section the
display text numbers, never a heading nested under it. A bare §2.3 records
which section was true once; the link breaks when the heading moves, which is
the point.
scripts/spec_refs_lint.py enforces this over docs/spec/*.md, src/,
tests/ and include/; a § inside a fenced block is example text.
tilefoundry.utils.spec_ref.spec_ref_render renders one as
spec runtime §1.1.2 for a refusal message.
Append a section; do not renumber one. A number is an address that code,
sibling specs and the spec command all reach a section by. Duplicates are
worse than gaps: two 3.1 headings make both unreachable by
tilefoundry spec <topic> 3.1. Gaps and out-of-order numbering are the accepted
cost — docs/spec/runtime.md numbers 2.10 before 2.9. This part is habit:
the lint catches a renamed heading, not a renumbered one.
Entropy And Close Tracking¶
scripts/spec_entropy_lint.py guards Python code comments/docstrings from
re-growing long contract prose. scripts/spec_rules_lint.py checks
mechanically-forbidden spec tokens. These tools are review gates, not a
spec-code validator.
Review-led spec work tracks every source comment to one final state:
implemented, verified no-op, or resolved by decision.