docs(positioning): add "el-sujeto-no-se-alquila" narrative (es/en)
This commit is contained in:
parent
27a8fb23a2
commit
e53474a236
25 changed files with 537 additions and 48 deletions
|
|
@ -14,7 +14,7 @@ css_class: "category-adr"
|
|||
---
|
||||
<h2>Context</h2>
|
||||
|
||||
<p>Consumer projects have project-type-specific CLI needs that ontoref's generic command set cannot satisfy. A PersonalOntology project has CFP pipelines, career schemas, and opportunity tracking that no other repo_kind needs. A DevWorkspace project has workspace cards, cluster state dimensions, and production-readiness gates. These capabilities lived as local scripts (scripts/jpl.nu) — invisible to ontoref's help system, absent from describe capabilities, and not portable to other PersonalOntology projects. The problem had two layers: (1) how to conditionally load domain-specific Nu commands without breaking the existing dispatcher, and (2) how to make domain commands discoverable (help, describe capabilities) and aliasable (ore prov, personal state). Nu's module system (`use`, `source`, `overlay use`) is compile-time: paths must be known at parse time and `overlay use` creates an isolated namespace that cannot extend `def main` in the existing dispatcher. Runtime loading of arbitrary Nu modules is architecturally impossible in the current Nu model.</p>
|
||||
<p>Consumer projects have project-type-specific CLI needs that ontoref's generic command set cannot satisfy. A PersonalOntology project has CFP pipelines, career schemas, and opportunity tracking that no other repo_kind needs. A DevWorkspace project has workspace cards, cluster state dimensions, and production-readiness gates. These capabilities lived as local scripts (scripts/jpl.nu) — invisible to ontoref's help system, absent from describe capabilities, and not portable to other PersonalOntology projects. The problem had two layers: (1) how to conditionally load domain-specific Nu commands without breaking the existing dispatcher, and (2) how to make domain commands discoverable (help, describe capabilities) and aliasable (ontoref prov, personal state). Nu's module system (`use`, `source`, `overlay use`) is compile-time: paths must be known at parse time and `overlay use` creates an isolated namespace that cannot extend `def main` in the existing dispatcher. Runtime loading of arbitrary Nu modules is architecturally impossible in the current Nu model.</p>
|
||||
|
||||
<h2>Decision</h2>
|
||||
|
||||
|
|
@ -26,7 +26,7 @@ css_class: "category-adr"
|
|||
|
||||
<h2>Alternatives considered</h2>
|
||||
|
||||
<ul><li><strong>Nu overlay use for runtime domain loading</strong> — <em>rejected:</em> overlay use creates an isolated namespace — commands defined in an overlayed module cannot be called by name in the parent scope. It is also parse-time in module context. Confirmed broken: nu -c 'use FILE *; command args' causes infinite recursion when called from def main.</li><li><strong>Add domain commands directly to reflection/bin/ontoref.nu</strong> — <em>rejected:</em> Would require hardcoding every domain's commands in the main dispatcher, or using dynamic path strings in `use` which Nu forbids. Also violates the no-enforcement axiom — the main dispatcher should not know about PersonalOntology specifics.</li><li><strong>Project-local scripts/ (scripts/jpl.nu approach)</strong> — <em>rejected:</em> Invisible to ore help and ore describe capabilities. Not portable across PersonalOntology projects. Namespace requires prefix (jpl cfp vs cfp). Dispatch requires knowing the script path.</li></ul>
|
||||
<ul><li><strong>Nu overlay use for runtime domain loading</strong> — <em>rejected:</em> overlay use creates an isolated namespace — commands defined in an overlayed module cannot be called by name in the parent scope. It is also parse-time in module context. Confirmed broken: nu -c 'use FILE *; command args' causes infinite recursion when called from def main.</li><li><strong>Add domain commands directly to reflection/bin/ontoref.nu</strong> — <em>rejected:</em> Would require hardcoding every domain's commands in the main dispatcher, or using dynamic path strings in `use` which Nu forbids. Also violates the no-enforcement axiom — the main dispatcher should not know about PersonalOntology specifics.</li><li><strong>Project-local scripts/ (scripts/jpl.nu approach)</strong> — <em>rejected:</em> Invisible to ontoref help and ontoref describe capabilities. Not portable across PersonalOntology projects. Namespace requires prefix (jpl cfp vs cfp). Dispatch requires knowing the script path.</li></ul>
|
||||
|
||||
<h2>Related ADRs</h2>
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ css_class: "category-adr"
|
|||
|
||||
<h2>Constraints</h2>
|
||||
|
||||
<ul><li><strong>Hard</strong> The credentials required to pull the src-vault OCI artifact from ZOT must be stored outside the vault itself — each src-vault has its own access credentials, held in the actor's local .kage, not inside any vault it protects</li><li><strong>Hard</strong> RegistryEntry must not use credential_env — only credential_sops or credential_oidc are valid credential reference fields</li><li><strong>Hard</strong> Every *.sops.yaml credential file must include at minimum the admin and the bound_actor recipients for its access class</li><li><strong>Hard</strong> Any domain or mode that pushes or pulls from a registry must declare uses_registry referencing the RegistryEntry id in manifest.ncl</li><li><strong>Soft</strong> All sops operations on registry credential files must go through ore secrets — direct sops invocations bypass lock state and audit log</li><li><strong>Hard</strong> Every oras invocation must use DOCKER_CONFIG pointing to a tmpdir containing only the credential for the target registry endpoint — no ambient ~/.docker/config.json</li><li><strong>Hard</strong> vault_key must never be written to disk in plaintext — it is decrypted from access.sops.yaml into RESTIC_PASSWORD or KOPIA_PASSWORD for the duration of the operation only</li><li><strong>Soft</strong> All vault snapshot operations must use vault-backend.nu — direct restic or kopia invocations are not permitted in recipes or modules</li><li><strong>Hard</strong> Every push of src-vault/<project>:latest to ZOT must produce a cosign signature; every pull must verify the signature before the artifact is trusted</li></ul>
|
||||
<ul><li><strong>Hard</strong> The credentials required to pull the src-vault OCI artifact from ZOT must be stored outside the vault itself — each src-vault has its own access credentials, held in the actor's local .kage, not inside any vault it protects</li><li><strong>Hard</strong> RegistryEntry must not use credential_env — only credential_sops or credential_oidc are valid credential reference fields</li><li><strong>Hard</strong> Every *.sops.yaml credential file must include at minimum the admin and the bound_actor recipients for its access class</li><li><strong>Hard</strong> Any domain or mode that pushes or pulls from a registry must declare uses_registry referencing the RegistryEntry id in manifest.ncl</li><li><strong>Soft</strong> All sops operations on registry credential files must go through ontoref secrets — direct sops invocations bypass lock state and audit log</li><li><strong>Hard</strong> Every oras invocation must use DOCKER_CONFIG pointing to a tmpdir containing only the credential for the target registry endpoint — no ambient ~/.docker/config.json</li><li><strong>Hard</strong> vault_key must never be written to disk in plaintext — it is decrypted from access.sops.yaml into RESTIC_PASSWORD or KOPIA_PASSWORD for the duration of the operation only</li><li><strong>Soft</strong> All vault snapshot operations must use vault-backend.nu — direct restic or kopia invocations are not permitted in recipes or modules</li><li><strong>Hard</strong> Every push of src-vault/<project>:latest to ZOT must produce a cosign signature; every pull must verify the signature before the artifact is trusted</li></ul>
|
||||
|
||||
<h2>Alternatives considered</h2>
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ css_class: "category-adr"
|
|||
|
||||
<h2>Decision</h2>
|
||||
|
||||
<p>Formalize the three-level hierarchy with four mechanisms: (1) Level identity declaration — each ontoref instance declares level.index (1=base, 2=domain, 3=instance), level.name, and level.parent (name of the level above; absent at level 1) in manifest.ncl. This makes level identity explicit and queryable. (2) Per-mode resolution strategy — each reflection mode declares a strategy field using one of four values: 'Override (implementation is complete at this level, traversal stops), 'Delegate (no implementation here, traverse to parent), 'Merge (accumulate fields bottom-up across all levels; lower level wins on conflicts), 'Compose (declare explicit partial inheritance via an extends field naming specific steps or fields to inherit from the parent). Strategy is required at level 2+; absent at level 1 (base is always Override by definition). Implicit absence at level 2+ is treated as 'Delegate with a Soft validation warning. (3) FSM-bound strategy transitions — when a mode's strategy is expected to change as the project matures, declare a state dimension in state.ncl whose current_state tracks the strategy value. The transition from 'Delegate to 'Override (or any other pair) is then an observable FSM event: tracked in state.ncl, visible in ore describe state, and triggerable by the same transition conditions as any other dimension. Strategy changes are architectural events, not silent refactors. (4) Observable traversal via ore mode resolve — the command 'ore mode resolve <id>' reports which level answered the operation, the strategy applied, the source file, and the reason (declared strategy or FSM state). No mode resolution is ever silent.</p>
|
||||
<p>Formalize the three-level hierarchy with four mechanisms: (1) Level identity declaration — each ontoref instance declares level.index (1=base, 2=domain, 3=instance), level.name, and level.parent (name of the level above; absent at level 1) in manifest.ncl. This makes level identity explicit and queryable. (2) Per-mode resolution strategy — each reflection mode declares a strategy field using one of four values: 'Override (implementation is complete at this level, traversal stops), 'Delegate (no implementation here, traverse to parent), 'Merge (accumulate fields bottom-up across all levels; lower level wins on conflicts), 'Compose (declare explicit partial inheritance via an extends field naming specific steps or fields to inherit from the parent). Strategy is required at level 2+; absent at level 1 (base is always Override by definition). Implicit absence at level 2+ is treated as 'Delegate with a Soft validation warning. (3) FSM-bound strategy transitions — when a mode's strategy is expected to change as the project matures, declare a state dimension in state.ncl whose current_state tracks the strategy value. The transition from 'Delegate to 'Override (or any other pair) is then an observable FSM event: tracked in state.ncl, visible in ontoref describe state, and triggerable by the same transition conditions as any other dimension. Strategy changes are architectural events, not silent refactors. (4) Observable traversal via ontoref mode resolve — the command 'ontoref mode resolve <id>' reports which level answered the operation, the strategy applied, the source file, and the reason (declared strategy or FSM state). No mode resolution is ever silent.</p>
|
||||
|
||||
<h2>Constraints</h2>
|
||||
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ implementation is tracked as backlog item bl-014.</p>
|
|||
|
||||
<h2>Alternatives considered</h2>
|
||||
|
||||
<ul><li><strong>Leave the gap as implicit Rust source TODOs</strong> — <em>rejected:</em> Implicit TODOs are not queryable. ADR-031 on+re duality requires protocol gaps to live on the ontology axis. Cost of this ADR is small; cost of every consumer rediscovering the gap grows linearly with the consumer count.</li><li><strong>Implement substrate effects directly in ADR-033 §FULL EFFECTS instead of splitting</strong> — <em>rejected:</em> ADR-033 §FULL EFFECTS was a self-contained PR-sized scope: tier_transition module + tests + CLI surface + watcher + holder + handler. Including substrate would have ballooned the scope across multiple substrate crates and pushed the ship date indefinitely. Splitting lets ADR-033 ship its value (working ore tier set + guard + tests) immediately.</li><li><strong>Persist the oplog via stratumiops stratum-db</strong> — <em>rejected:</em> An earlier draft of this ADR assumed stratum-db for oplog persistence. The implemented `ontoref-oplog` is redb-backed and self-contained in the workspace, enforcing signature + parent-existence + monotonic-HLC checks on every append. Using stratum-db would reintroduce an external path dependency for tier-2, contradicting ADR-001's minimal-adoption posture and ADR-029's offline-first default. redb keeps the witness chain dependency-free.</li></ul>
|
||||
<ul><li><strong>Leave the gap as implicit Rust source TODOs</strong> — <em>rejected:</em> Implicit TODOs are not queryable. ADR-031 on+re duality requires protocol gaps to live on the ontology axis. Cost of this ADR is small; cost of every consumer rediscovering the gap grows linearly with the consumer count.</li><li><strong>Implement substrate effects directly in ADR-033 §FULL EFFECTS instead of splitting</strong> — <em>rejected:</em> ADR-033 §FULL EFFECTS was a self-contained PR-sized scope: tier_transition module + tests + CLI surface + watcher + holder + handler. Including substrate would have ballooned the scope across multiple substrate crates and pushed the ship date indefinitely. Splitting lets ADR-033 ship its value (working ontoref tier set + guard + tests) immediately.</li><li><strong>Persist the oplog via stratumiops stratum-db</strong> — <em>rejected:</em> An earlier draft of this ADR assumed stratum-db for oplog persistence. The implemented `ontoref-oplog` is redb-backed and self-contained in the workspace, enforcing signature + parent-existence + monotonic-HLC checks on every append. Using stratum-db would reintroduce an external path dependency for tier-2, contradicting ADR-001's minimal-adoption posture and ADR-029's offline-first default. redb keeps the witness chain dependency-free.</li></ul>
|
||||
|
||||
<h2>Related ADRs</h2>
|
||||
|
||||
|
|
|
|||
|
|
@ -77,14 +77,14 @@ reflection schema `reflection/schemas/interaction.ncl` (migration 0028).</p>
|
|||
rather than redeclaring parallel vocabularies that would drift. The
|
||||
runtime validator parses enum members FROM the schema files at runtime, so
|
||||
the allowlist can never diverge from the contract.</p>
|
||||
<p>5. Two emission paths, both supported. `ore interaction record` validates a
|
||||
<p>5. Two emission paths, both supported. `ontoref interaction record` validates a
|
||||
record structurally before appending (the forced path; malformed records
|
||||
are rejected). Direct JSONL append by the agent is also permitted (the
|
||||
free path), audited post-hoc by `ore interaction validate` (pre-commit /
|
||||
free path), audited post-hoc by `ontoref interaction validate` (pre-commit /
|
||||
CI gate). The `--no-validate` flag bridges the two on the same command.</p>
|
||||
<p>6. Decisions materialise the adr? criteria as data. `Decision` carries
|
||||
`alternatives_rejected`, `reversible`, `adr_candidate`, and
|
||||
`tensions_engaged` (core.ncl node ids). `ore interaction decisions
|
||||
`tensions_engaged` (core.ncl node ids). `ontoref interaction decisions
|
||||
--adr-candidates` surfaces ADR candidates across sessions in one query,
|
||||
feeding the ADR lifecycle from observed decisions rather than recollection.</p>
|
||||
<p>The layer is opt-in per ADR-029: a project that never emits interaction JSONL
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ schema/catalog additions to consumers.</p>
|
|||
build kind, the build/distribution catalog entries, and the generator that
|
||||
emits .woodpecker/release.yml + install/install.sh + justfiles/release.just
|
||||
all live in the NCL workflow model. Distribution is therefore self-describing
|
||||
and queryable via `ore workflow`, like every other build/CI artifact.</p>
|
||||
and queryable via `ontoref workflow`, like every other build/CI artifact.</p>
|
||||
<p>2. Build-once; the image is assembled FROM the binary, never recompiled. The
|
||||
musl binary is cross-compiled once per arch (`cross`). Both the install
|
||||
bundle AND the runnable image consume that same binary. The image is
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ css_class: "category-adr"
|
|||
<p>Projects accumulate many just recipes (and loose scripts). ontoref already
|
||||
INVENTORIES recipes — describe.nu::scan-just-recipes runs `just --list` and
|
||||
categorizes each recipe by a name-prefix heuristic (categorize-recipe), and
|
||||
`ore describe tools` lists them. But the inventory is shallow: it knows a
|
||||
`ontoref describe tools` lists them. But the inventory is shallow: it knows a
|
||||
recipe's name, its trailing `#` comment, and a guessed bucket. It cannot answer
|
||||
"which is the canonical way to run all checks", "show me the deploy tasks", or
|
||||
"what does build-standalone do and why" — because the recipe carries no declared
|
||||
|
|
@ -26,16 +26,16 @@ INTENT and no real categorization, only a prefix guess.</p>
|
|||
<p>- Recipes (justfiles) are the MECHANISM layer — the concrete command. Single
|
||||
source of truth for HOW.
|
||||
- Modes (reflection/modes/*.ncl) are the PROCEDURE layer — multi-step gated
|
||||
DAGs with actors/steps/depends_on, executed by `ore run`.</p>
|
||||
DAGs with actors/steps/depends_on, executed by `ontoref run`.</p>
|
||||
<p>What is missing is not a third store ("devtask" is a target-side abstraction,
|
||||
not ontoref vocabulary). What is missing is for a recipe to SELF-DESCRIBE — to
|
||||
declare its intent and categorization in place — exactly as Rust handlers do
|
||||
with #[onto_api(method, path, description, tags)]: the annotation sits next to
|
||||
the code, a proc-macro parses it, and inventory aggregates a zero-cost catalog
|
||||
that `ore describe api` / GET /api/catalog / MCP all read. The same shape is
|
||||
that `ontoref describe api` / GET /api/catalog / MCP all read. The same shape is
|
||||
wanted for recipes: an annotation next to the recipe, parsed by ontoref, that
|
||||
makes justfiles queryable.</p>
|
||||
<p>The qa routing fix in the same session (ore qa show/list/search/add) added the
|
||||
<p>The qa routing fix in the same session (ontoref qa show/list/search/add) added the
|
||||
seeding primitive — a tag-categorized, nickel-validated write path. The question
|
||||
this ADR settles is the GRAMMAR and the BOUNDARIES of seeding/enriching the tool
|
||||
surface: how an annotation is written, how it is mutated, and how a project that
|
||||
|
|
@ -67,14 +67,14 @@ grammar, the recommended mode taxonomy, and the new surface to consumers.</p>
|
|||
<p>2. The recipe is the single source of truth. Annotations live IN the justfile,
|
||||
above the recipe — never in a parallel devtasks store. ontoref parses them
|
||||
(scan-just-recipes gains an @onto parser) and DERIVES a catalog, exactly as
|
||||
#[onto_api] derives artifacts/api-catalog-*.ncl. `ore tool export` writes the
|
||||
derived catalog; `ore describe tools --mode <m> --label <l>` reads it.</p>
|
||||
<p>3. Mutation via a transversal verb. `ore + <noun> <args>` upserts and
|
||||
`ore - <noun> <args>` removes, across stores:</p>
|
||||
<p>ore + tool ci-full --mode ci --labels ci,gate --intent "all checks"
|
||||
ore - tool ci-full # removes the @onto line only
|
||||
ore + qa "<q>" "<a>" --tags devtool,ci # the qa add path
|
||||
ore - qa <id></p>
|
||||
#[onto_api] derives artifacts/api-catalog-*.ncl. `ontoref tool export` writes the
|
||||
derived catalog; `ontoref describe tools --mode <m> --label <l>` reads it.</p>
|
||||
<p>3. Mutation via a transversal verb. `ontoref + <noun> <args>` upserts and
|
||||
`ontoref - <noun> <args>` removes, across stores:</p>
|
||||
<p>ontoref + tool ci-full --mode ci --labels ci,gate --intent "all checks"
|
||||
ontoref - tool ci-full # removes the @onto line only
|
||||
ontoref + qa "<q>" "<a>" --tags devtool,ci # the qa add path
|
||||
ontoref - qa <id></p>
|
||||
<p>`+ tool` / `- tool` edit the `@onto` comment ABOVE the named recipe in
|
||||
place, validated against `just --list`; they NEVER touch the recipe body.
|
||||
`+`/`-` are first-level dispatcher tokens taking `<noun> <args>`, so new
|
||||
|
|
@ -84,7 +84,7 @@ grammar, the recommended mode taxonomy, and the new surface to consumers.</p>
|
|||
behavior). Annotation raises a recipe from guessed to declared; it is never
|
||||
required to run a recipe. This is the `formalization-vs-adoption` balance
|
||||
made literal — "optional layers, not mandatory gates".</p>
|
||||
<p>5. Non-destructive compliance/migration. A `compliant` mode (and `ore tool
|
||||
<p>5. Non-destructive compliance/migration. A `compliant` mode (and `ontoref tool
|
||||
migrate`) scans a project's existing justfiles, proposes `@onto` annotations
|
||||
(seeding `mode` from categorize-recipe + name, leaving `intent` for the
|
||||
author), and — opt-in — reorganizes recipes into justfiles/<mode>.just. It
|
||||
|
|
@ -92,7 +92,7 @@ grammar, the recommended mode taxonomy, and the new surface to consumers.</p>
|
|||
deleted or renamed, reorg is opt-in and reversible, and the project's own
|
||||
recipes are first-class (the mechanism annotates them, it does not supplant
|
||||
them with ontoref-blessed ones).</p>
|
||||
<p>6. Drift-checkable round-trip. `ore tool audit` reports orphan annotations
|
||||
<p>6. Drift-checkable round-trip. `ontoref tool audit` reports orphan annotations
|
||||
(an `@onto` whose recipe is gone from `just --list`) and, at compliance
|
||||
level, un-annotated recipes. Mirrors docs-drift: the annotation and the
|
||||
recipe must stay in sync because they are co-located.</p>
|
||||
|
|
@ -102,7 +102,7 @@ annotated recipes are complementary, not competing.</p>
|
|||
|
||||
<h2>Constraints</h2>
|
||||
|
||||
<ul><li><strong>Hard</strong> A recipe in a justfile is the single source of truth for its command. @onto metadata MUST live in a comment co-located with the recipe; there MUST NOT be a parallel store of recipe command strings. Any tool catalog is DERIVED from the annotations and MUST be regenerated, not hand-edited.</li><li><strong>Hard</strong> The annotation MUST be a single comment line `# @onto key=val ...` immediately above the recipe. Recognized keys: `mode` (one token), `labels` (comma-separated), `intent` (double-quoted free text). Unknown keys MUST be ignored, not error. The recipe name and its plain `#` doc comment MUST be left intact.</li><li><strong>Hard</strong> Annotation/entry mutation MUST go through `ore + <noun> <args>` (upsert) and `ore - <noun> <args>` (remove). For noun `tool`, the verb edits/removes ONLY the @onto comment above the named recipe, validated against `just --list`, and MUST NOT modify the recipe body. New stores MUST be added as nouns, not as new top-level verbs.</li><li><strong>Hard</strong> An un-annotated recipe MUST remain valid, runnable, and inventoried by name+category. Annotation MUST NOT be a precondition for running or listing a recipe. Compliance is reported by audit, never enforced as a gate.</li><li><strong>Hard</strong> The compliance/migration mechanism MUST NOT delete or rename any project-owned recipe. It annotates in place and may propose reorganization into justfiles/<mode>.just only as an opt-in, semantics-preserving, reversible step. A project's own recipes are first-class and MUST survive migration unchanged in behavior.</li><li><strong>Soft</strong> `ore tool audit` MUST report orphan annotations (an @onto whose recipe is absent from `just --list`) and, at compliance level, un-annotated recipes. Every @onto MUST reference an existing recipe.</li><li><strong>Soft</strong> The recommended `mode` taxonomy (tools/dev/build/test/ci/deploy/docs/dist/secrets/…) is advisory guidance, not an enforced enum; `labels` are free-form. Validation MUST NOT reject an unrecognized mode or label.</li></ul>
|
||||
<ul><li><strong>Hard</strong> A recipe in a justfile is the single source of truth for its command. @onto metadata MUST live in a comment co-located with the recipe; there MUST NOT be a parallel store of recipe command strings. Any tool catalog is DERIVED from the annotations and MUST be regenerated, not hand-edited.</li><li><strong>Hard</strong> The annotation MUST be a single comment line `# @onto key=val ...` immediately above the recipe. Recognized keys: `mode` (one token), `labels` (comma-separated), `intent` (double-quoted free text). Unknown keys MUST be ignored, not error. The recipe name and its plain `#` doc comment MUST be left intact.</li><li><strong>Hard</strong> Annotation/entry mutation MUST go through `ontoref + <noun> <args>` (upsert) and `ontoref - <noun> <args>` (remove). For noun `tool`, the verb edits/removes ONLY the @onto comment above the named recipe, validated against `just --list`, and MUST NOT modify the recipe body. New stores MUST be added as nouns, not as new top-level verbs.</li><li><strong>Hard</strong> An un-annotated recipe MUST remain valid, runnable, and inventoried by name+category. Annotation MUST NOT be a precondition for running or listing a recipe. Compliance is reported by audit, never enforced as a gate.</li><li><strong>Hard</strong> The compliance/migration mechanism MUST NOT delete or rename any project-owned recipe. It annotates in place and may propose reorganization into justfiles/<mode>.just only as an opt-in, semantics-preserving, reversible step. A project's own recipes are first-class and MUST survive migration unchanged in behavior.</li><li><strong>Soft</strong> `ontoref tool audit` MUST report orphan annotations (an @onto whose recipe is absent from `just --list`) and, at compliance level, un-annotated recipes. Every @onto MUST reference an existing recipe.</li><li><strong>Soft</strong> The recommended `mode` taxonomy (tools/dev/build/test/ci/deploy/docs/dist/secrets/…) is advisory guidance, not an enforced enum; `labels` are free-form. Validation MUST NOT reject an unrecognized mode or label.</li></ul>
|
||||
|
||||
<h2>Alternatives considered</h2>
|
||||
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ truth.</p>
|
|||
with its own in one directory. The DECLARATION (card.ncl) plus the .ontoref/
|
||||
content are the source of truth; the .claude/ symlink is a derived view.</p>
|
||||
<p>5. Propagation rides the update/migration mechanism, not bespoke symlink edits.
|
||||
`ore conventions sync` (and the `update_ontoref` mode) reconcile each declared
|
||||
`ontoref conventions sync` (and the `update_ontoref` mode) reconcile each declared
|
||||
binding against the shared origin: detect version drift (origin moved, e.g.
|
||||
new Rust guideline), report it, and — opt-in — re-link or re-vendor to the
|
||||
declared version. A shared change reaches every binding project through this
|
||||
|
|
@ -114,26 +114,26 @@ truth.</p>
|
|||
means writing it to the origin and re-syncing, so all binding projects can
|
||||
adopt it.</p>
|
||||
<p>7. Optional, audit-not-gate. A project may declare zero conventions and remain
|
||||
valid. `ore conventions audit` reports: bindings whose origin is unreachable,
|
||||
valid. `ontoref conventions audit` reports: bindings whose origin is unreachable,
|
||||
version drift (declared != origin), and resolution-mode mismatches (declared
|
||||
symlink but found vendored, or vice versa). It REPORTS; it does not block —
|
||||
the formalization-vs-adoption resolution.</p>
|
||||
<p>These are MODES/utilities, not new stores: per the user's framing, guidelines/CI/
|
||||
config bindings are implementation-framework utilities (templates, examples,
|
||||
sync). `ore conventions sync|audit|describe` and the `update_ontoref` extension
|
||||
sync). `ontoref conventions sync|audit|describe` and the `update_ontoref` extension
|
||||
are the operational surface; card.ncl carries the declaration.</p>
|
||||
|
||||
<h2>Constraints</h2>
|
||||
|
||||
<ul><li><strong>Hard</strong> A project's convention bindings (guidelines per language, CI reference, config conventions) MUST be declared in .ontoref/card.ncl as a `conventions` block naming source + version. Guideline CONTENT MUST NOT be inlined; the declaration names sources, content resolves from the shared origin.</li><li><strong>Hard</strong> Convention CONTENT MUST live authoritatively under .ontoref/conventions/<lang>/ (protocol-first). .claude/guidelines/<lang>/ MUST be a materialized view (a symlink into .ontoref/conventions/), never the authoritative location. The conventions MUST resolve with no .claude/ present. The card.ncl declaration plus the .ontoref/ content are the source of truth; per-file resolution mode (symlink to origin | vendored | local-own) is recorded, and a project's own guideline is a real file beside the shared ones.</li><li><strong>Hard</strong> Convention propagation/sync MUST be implemented as an extension of the existing migration system (ADR-010) and the update_ontoref mode — e.g. `ore conventions sync` and an update_ontoref step — NOT as a separate symlink-specific propagation path. A shared-origin change reaching consumers MUST be expressible as / accompanied by a migration.</li><li><strong>Hard</strong> The shared origin MUST be authoritative for shared conventions. A project MUST NOT silently fork a bound convention by editing a vendored copy in place. Local refinements are promoted by writing to the origin and bumping the declared version; divergence MUST be reported by audit, not auto-merged.</li><li><strong>Soft</strong> Convention bindings MUST be optional: a project may declare none and remain valid. `ore conventions audit` MUST report unreachable origins, version drift, and resolution-mode mismatches, but MUST NOT block builds or commands.</li><li><strong>Soft</strong> The `ci` convention binding MUST reference a workflow layer id (ADR-038 model), not re-declare CI steps in the conventions surface. `describe conventions` cross-links to the workflow model rather than duplicating it.</li></ul>
|
||||
<ul><li><strong>Hard</strong> A project's convention bindings (guidelines per language, CI reference, config conventions) MUST be declared in .ontoref/card.ncl as a `conventions` block naming source + version. Guideline CONTENT MUST NOT be inlined; the declaration names sources, content resolves from the shared origin.</li><li><strong>Hard</strong> Convention CONTENT MUST live authoritatively under .ontoref/conventions/<lang>/ (protocol-first). .claude/guidelines/<lang>/ MUST be a materialized view (a symlink into .ontoref/conventions/), never the authoritative location. The conventions MUST resolve with no .claude/ present. The card.ncl declaration plus the .ontoref/ content are the source of truth; per-file resolution mode (symlink to origin | vendored | local-own) is recorded, and a project's own guideline is a real file beside the shared ones.</li><li><strong>Hard</strong> Convention propagation/sync MUST be implemented as an extension of the existing migration system (ADR-010) and the update_ontoref mode — e.g. `ontoref conventions sync` and an update_ontoref step — NOT as a separate symlink-specific propagation path. A shared-origin change reaching consumers MUST be expressible as / accompanied by a migration.</li><li><strong>Hard</strong> The shared origin MUST be authoritative for shared conventions. A project MUST NOT silently fork a bound convention by editing a vendored copy in place. Local refinements are promoted by writing to the origin and bumping the declared version; divergence MUST be reported by audit, not auto-merged.</li><li><strong>Soft</strong> Convention bindings MUST be optional: a project may declare none and remain valid. `ontoref conventions audit` MUST report unreachable origins, version drift, and resolution-mode mismatches, but MUST NOT block builds or commands.</li><li><strong>Soft</strong> The `ci` convention binding MUST reference a workflow layer id (ADR-038 model), not re-declare CI steps in the conventions surface. `describe conventions` cross-links to the workflow model rather than duplicating it.</li></ul>
|
||||
|
||||
<h2>Alternatives considered</h2>
|
||||
|
||||
<ul><li><strong>Keep symlinks as the mechanism, add nothing</strong> — <em>rejected:</em> Symlinks are invisible to ontoref, unversioned, and break on clone/CI/container. They cannot answer 'what version' or 'is this in sync', and a shared bump requires manual per-project symlink work. The whole point is to make bindings declared, queryable, and synced.</li><li><strong>Declare conventions in a new .ontoref/catalog/conventions.ncl</strong> — <em>rejected:</em> Fragments 'what the project is bound to' away from the card.ncl beacon and duplicates the read surface that describe guides/config already provide. A catalog suits kind-extensible operation inventories (ADR-034), not the small, identity-level binding declaration. Chosen against, but the catalog remains the right home if bindings later grow rich enough to need their own kind system.</li><li><strong>A bespoke convention-sync tool independent of the migration system</strong> — <em>rejected:</em> Duplicates ADR-010's propagation mechanism and update_ontoref, and stays outside `ore migrate`/`describe`. Convention propagation is the same event shape as protocol propagation; it must reuse that one path.</li><li><strong>Vendor (copy) conventions only, drop symlinks entirely</strong> — <em>rejected:</em> Loses the transparent dev-loop where editing the origin is instantly reflected. Both modes have a place: symlink for local dev, vendored for clone/CI/container. The declaration records which mode applies; forcing one collapses a useful choice.</li><li><strong>Inline guideline content into card.ncl / the project</strong> — <em>rejected:</em> Bloats the beacon, defeats sharing, and guarantees drift from the origin. Bindings must name sources+versions and resolve content from the shared origin, never inline it.</li></ul>
|
||||
<ul><li><strong>Keep symlinks as the mechanism, add nothing</strong> — <em>rejected:</em> Symlinks are invisible to ontoref, unversioned, and break on clone/CI/container. They cannot answer 'what version' or 'is this in sync', and a shared bump requires manual per-project symlink work. The whole point is to make bindings declared, queryable, and synced.</li><li><strong>Declare conventions in a new .ontoref/catalog/conventions.ncl</strong> — <em>rejected:</em> Fragments 'what the project is bound to' away from the card.ncl beacon and duplicates the read surface that describe guides/config already provide. A catalog suits kind-extensible operation inventories (ADR-034), not the small, identity-level binding declaration. Chosen against, but the catalog remains the right home if bindings later grow rich enough to need their own kind system.</li><li><strong>A bespoke convention-sync tool independent of the migration system</strong> — <em>rejected:</em> Duplicates ADR-010's propagation mechanism and update_ontoref, and stays outside `ontoref migrate`/`describe`. Convention propagation is the same event shape as protocol propagation; it must reuse that one path.</li><li><strong>Vendor (copy) conventions only, drop symlinks entirely</strong> — <em>rejected:</em> Loses the transparent dev-loop where editing the origin is instantly reflected. Both modes have a place: symlink for local dev, vendored for clone/CI/container. The declaration records which mode applies; forcing one collapses a useful choice.</li><li><strong>Inline guideline content into card.ncl / the project</strong> — <em>rejected:</em> Bloats the beacon, defeats sharing, and guarantees drift from the origin. Bindings must name sources+versions and resolve content from the shared origin, never inline it.</li></ul>
|
||||
|
||||
<h2>Anti-patterns</h2>
|
||||
|
||||
<ul><li><strong>Treating .claude Symlinks as the Authoritative Content</strong> — Convention content lives authoritatively under .claude/guidelines/* (harness-specific) with no card.ncl declaration and nothing under .ontoref/. The binding is invisible to ontoref, unversioned, harness-coupled, and vanishes on clone/CI/container or when there is no Claude Code.</li><li><strong>A Separate Sync Path Outside the Migration System</strong> — Convention propagation is built as its own tool/script independent of the migration system and update_ontoref, so it is invisible to `ore migrate` and duplicates the protocol's propagation mechanism.</li><li><strong>Editing a Vendored Convention In Place</strong> — A project edits its vendored copy of a shared guideline directly, forking the shared origin silently. Other binding projects never see the change and the origin fractures.</li><li><strong>Failing Builds on Convention Drift</strong> — `ore conventions audit` (or a hook) blocks commands/builds when a binding is drifted or undeclared, turning an optional layer into a mandatory gate.</li><li><strong>Re-Declaring CI in the Conventions Surface</strong> — CI steps are copied into card.ncl's conventions block instead of referencing the workflow layer, creating a second drifting CI source.</li></ul>
|
||||
<ul><li><strong>Treating .claude Symlinks as the Authoritative Content</strong> — Convention content lives authoritatively under .claude/guidelines/* (harness-specific) with no card.ncl declaration and nothing under .ontoref/. The binding is invisible to ontoref, unversioned, harness-coupled, and vanishes on clone/CI/container or when there is no Claude Code.</li><li><strong>A Separate Sync Path Outside the Migration System</strong> — Convention propagation is built as its own tool/script independent of the migration system and update_ontoref, so it is invisible to `ontoref migrate` and duplicates the protocol's propagation mechanism.</li><li><strong>Editing a Vendored Convention In Place</strong> — A project edits its vendored copy of a shared guideline directly, forking the shared origin silently. Other binding projects never see the change and the origin fractures.</li><li><strong>Failing Builds on Convention Drift</strong> — `ontoref conventions audit` (or a hook) blocks commands/builds when a binding is drifted or undeclared, turning an optional layer into a mandatory gate.</li><li><strong>Re-Declaring CI in the Conventions Surface</strong> — CI steps are copied into card.ncl's conventions block instead of referencing the workflow layer, creating a second drifting CI source.</li></ul>
|
||||
|
||||
<h2>Related ADRs</h2>
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ first-class typed kind, bound by a Proof seam:</p>
|
|||
<p>The crossings are explicit: `ValueProp` is the WHAT×WHOM seam (gains
|
||||
`differentiator_ids`); `Campaign` and `Proof` bind HOW and VALIDATION.</p>
|
||||
<p>The marketing surface is governed by the same mechanism it sells. Five coherence
|
||||
rules run in `ore positioning audit` (local-first, daemon-independent):</p>
|
||||
rules run in `ontoref positioning audit` (local-first, daemon-independent):</p>
|
||||
<p>1. AnchorDrift — a differentiator/proof evidence_adr must be Accepted.
|
||||
2. UnprovenValidatedAudience — an Audience marked 'Validated needs >=1 Proof.
|
||||
3. Live value-prop — must converge four elements (differentiator +
|
||||
|
|
@ -69,7 +69,7 @@ Validated/Live claims must cite Accepted ADRs — mirroring the
|
|||
|
||||
<h2>Constraints</h2>
|
||||
|
||||
<ul><li><strong>Hard</strong> The positioning schema MUST keep WHAT (Differentiator), FOR WHOM (Audience) and HOW (DifusionMechanism) as separate typed kinds. Cross-axis binding MUST happen only through the seam kinds (ValueProp for what×whom; Campaign and Proof). Collapsing an axis back into another kind is forbidden.</li><li><strong>Hard</strong> Proof MUST reference the other three axes (converges.differentiator_ids, audience_ids, mechanism_ids each non-empty) and MUST NOT be referenced by any other kind. The make_proof contract (`_proof_converges_all`) enforces the triple convergence.</li><li><strong>Hard</strong> Every Differentiator MUST cite >=1 ontology node and >=1 evidence ADR, and name >=1 competitor category it beats (`vs`). The make_differentiator contracts (`_diff_requires_anchor`, `_diff_requires_vs`) enforce this.</li><li><strong>Hard</strong> `ore positioning audit` MUST run the five coherence rules over the positioning layer and gate CI by value-prop status: hard ADR-drift on Validated/Live value-props and any coherence violation fail; Draft drift and coverage gaps are informational.</li><li><strong>Soft</strong> A value-prop with status 'Live MUST bind >=1 differentiator (the WHAT axis); the `_live_requires_differentiator` contract enforces the local half, and the audit enforces the rest (a difundiendo mechanism and a proven differentiator).</li></ul>
|
||||
<ul><li><strong>Hard</strong> The positioning schema MUST keep WHAT (Differentiator), FOR WHOM (Audience) and HOW (DifusionMechanism) as separate typed kinds. Cross-axis binding MUST happen only through the seam kinds (ValueProp for what×whom; Campaign and Proof). Collapsing an axis back into another kind is forbidden.</li><li><strong>Hard</strong> Proof MUST reference the other three axes (converges.differentiator_ids, audience_ids, mechanism_ids each non-empty) and MUST NOT be referenced by any other kind. The make_proof contract (`_proof_converges_all`) enforces the triple convergence.</li><li><strong>Hard</strong> Every Differentiator MUST cite >=1 ontology node and >=1 evidence ADR, and name >=1 competitor category it beats (`vs`). The make_differentiator contracts (`_diff_requires_anchor`, `_diff_requires_vs`) enforce this.</li><li><strong>Hard</strong> `ontoref positioning audit` MUST run the five coherence rules over the positioning layer and gate CI by value-prop status: hard ADR-drift on Validated/Live value-props and any coherence violation fail; Draft drift and coverage gaps are informational.</li><li><strong>Soft</strong> A value-prop with status 'Live MUST bind >=1 differentiator (the WHAT axis); the `_live_requires_differentiator` contract enforces the local half, and the audit enforces the rest (a difundiendo mechanism and a proven differentiator).</li></ul>
|
||||
|
||||
<h2>Alternatives considered</h2>
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ css_class: "category-adr"
|
|||
|
||||
<h2>Decision</h2>
|
||||
|
||||
<p>Generalize ADR-018's absolute triad into a relative parent chain and add a co-tenancy declaration, both opt-in and backward-compatible, via four mechanisms. (1) RELATIVE LEVEL CHAIN — level identity is the parent chain, not an absolute index. A manifest declares level.parent (a name reference, exactly as ADR-018) and an optional level.role label; level.index becomes a DERIVED depth (walk parents to a base) that is no longer capped at 3 and no longer authoritative. The names base/domain/instance are reinterpreted as ROLES in a sliding window of three relative to an observation point, not global coordinates. Existing index 1/2/3 declarations remain valid as the depth<=3 case; deeper chains simply keep walking. The terminal node of one chain may itself be the parent-root of another (instance-as-host is a well-formed shape, not an error). (2) DOMAIN CO-TENANCY — a repo may declare manifest.ncl::hosts, an array of { chain (name reference to a foreign domain artifact), mount (where in this repo the hosted chain's Layer-3 wiring lives), digest (optional witness pin) }. The foreign chain is resolved by name through catalog discovery (ADR-030) and verified by witness (ADR-028), NEVER cloned. The host carries only Layer-3 wiring for the hosted chain (ADR-020), tagged layer-3-boundary. (3) MUTATION SOVEREIGNTY UNDER CO-TENANCY — a host's runtime MUST NOT mutate the authoritative state of any hosted chain. Hosting is placement plus wiring; each chain's authoritative state mutates only through its own declared operations with its own witness (ADR-024). Co-tenancy is co-residency of wiring, not transfer of state ownership. (4) OBSERVABLE CROSS-CHAIN RESOLUTION — ore mode resolve extends to report the full traversal PATH (every level visited, not a single hop) and the CHAIN SCOPE (which chain answered) when multiple chains are co-resident; ore describe state disambiguates FSM dimensions by chain scope. No cross-chain resolution is silent.</p>
|
||||
<p>Generalize ADR-018's absolute triad into a relative parent chain and add a co-tenancy declaration, both opt-in and backward-compatible, via four mechanisms. (1) RELATIVE LEVEL CHAIN — level identity is the parent chain, not an absolute index. A manifest declares level.parent (a name reference, exactly as ADR-018) and an optional level.role label; level.index becomes a DERIVED depth (walk parents to a base) that is no longer capped at 3 and no longer authoritative. The names base/domain/instance are reinterpreted as ROLES in a sliding window of three relative to an observation point, not global coordinates. Existing index 1/2/3 declarations remain valid as the depth<=3 case; deeper chains simply keep walking. The terminal node of one chain may itself be the parent-root of another (instance-as-host is a well-formed shape, not an error). (2) DOMAIN CO-TENANCY — a repo may declare manifest.ncl::hosts, an array of { chain (name reference to a foreign domain artifact), mount (where in this repo the hosted chain's Layer-3 wiring lives), digest (optional witness pin) }. The foreign chain is resolved by name through catalog discovery (ADR-030) and verified by witness (ADR-028), NEVER cloned. The host carries only Layer-3 wiring for the hosted chain (ADR-020), tagged layer-3-boundary. (3) MUTATION SOVEREIGNTY UNDER CO-TENANCY — a host's runtime MUST NOT mutate the authoritative state of any hosted chain. Hosting is placement plus wiring; each chain's authoritative state mutates only through its own declared operations with its own witness (ADR-024). Co-tenancy is co-residency of wiring, not transfer of state ownership. (4) OBSERVABLE CROSS-CHAIN RESOLUTION — ontoref mode resolve extends to report the full traversal PATH (every level visited, not a single hop) and the CHAIN SCOPE (which chain answered) when multiple chains are co-resident; ontoref describe state disambiguates FSM dimensions by chain scope. No cross-chain resolution is silent.</p>
|
||||
|
||||
<h2>Constraints</h2>
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ css_class: "category-adr"
|
|||
|
||||
<p>ADR-035 established positioning as a queryable protocol surface and ADR-043
|
||||
modelled it as four elements (WHAT / FOR WHOM / HOW bound by the Proof seam),
|
||||
governed by the five coherence rules of `ore positioning audit` — the first of
|
||||
governed by the five coherence rules of `ontoref positioning audit` — the first of
|
||||
which, AnchorDrift, requires that every `evidence_adr` cited by a Differentiator
|
||||
or Proof resolves to an Accepted ADR. Both ADRs were authored when the
|
||||
positioning surface had exactly one occupant: ontoref itself. In a single-project
|
||||
|
|
@ -34,7 +34,7 @@ only in rustelo's ADR catalogue, not ontoref's.</p>
|
|||
<p>Working the placement through surfaced the load-bearing fact: a rustelo
|
||||
Differentiator authored inside ontoref's `.ontoref/positioning/` would FAIL
|
||||
AnchorDrift, because ontoref does not own those ADRs. Authored inside rustelo's
|
||||
own `.ontoref/positioning/`, the same subject passes — verified: `ore positioning
|
||||
own `.ontoref/positioning/`, the same subject passes — verified: `ontoref positioning
|
||||
audit` run from rustelo reports `adr-drift: none`. The audit already resolves
|
||||
`evidence_adrs` against the AUTHORING project's ADR set; the framework simply
|
||||
never named where that places a subject. This is the same authority-upstream /
|
||||
|
|
@ -68,7 +68,7 @@ the rustelo publishing-contract.</p>
|
|||
|
||||
<h2>Constraints</h2>
|
||||
|
||||
<ul><li><strong>Hard</strong> A positioning subject that cites `evidence_adrs` MUST be authored in the `.ontoref/positioning/` of the project whose ADR catalogue Accepts those ADRs. `ore positioning audit`, run from that project, MUST report no AnchorDrift for the subject. Placing such a subject in a project that does not Accept its evidence ADRs is a drift finding, not a stylistic choice.</li><li><strong>Soft</strong> A project MUST reference a peer's positioning subject only by ROLE — a prose mention or an id in its OWN authored record — and MUST NOT re-author the peer's typed subject in its own tree. Cross-references between subjects are by id (competitor_ids, differentiator_ids), never by copied record.</li><li><strong>Soft</strong> The sovereignty rule MUST stay additive and opt-in: a project with no `positioning/` directory, or one that references no peer subject, MUST validate unchanged and pay zero adoption cost. The rule adds no kind, folder, or required field to ADR-043's surface.</li></ul>
|
||||
<ul><li><strong>Hard</strong> A positioning subject that cites `evidence_adrs` MUST be authored in the `.ontoref/positioning/` of the project whose ADR catalogue Accepts those ADRs. `ontoref positioning audit`, run from that project, MUST report no AnchorDrift for the subject. Placing such a subject in a project that does not Accept its evidence ADRs is a drift finding, not a stylistic choice.</li><li><strong>Soft</strong> A project MUST reference a peer's positioning subject only by ROLE — a prose mention or an id in its OWN authored record — and MUST NOT re-author the peer's typed subject in its own tree. Cross-references between subjects are by id (competitor_ids, differentiator_ids), never by copied record.</li><li><strong>Soft</strong> The sovereignty rule MUST stay additive and opt-in: a project with no `positioning/` directory, or one that references no peer subject, MUST validate unchanged and pay zero adoption cost. The rule adds no kind, folder, or required field to ADR-043's surface.</li></ul>
|
||||
|
||||
<h2>Alternatives considered</h2>
|
||||
|
||||
|
|
@ -76,7 +76,7 @@ the rustelo publishing-contract.</p>
|
|||
|
||||
<h2>Anti-patterns</h2>
|
||||
|
||||
<ul><li><strong>Authoring a Peer's Positioning Subject in the Host's Tree</strong> — A contributor places project B's Differentiator/ValueProp inside project A's `.ontoref/positioning/` to 'own the story in one place'. Its evidence_adrs are Accepted in B, not A, so `ore positioning audit` from A reports AnchorDrift — the subject is homeless, not centralised.</li><li><strong>Duplicating a Subject Across Projects and Syncing by Hand</strong> — The same Differentiator is copied into both the sovereign project and a peer to keep each surface 'complete'. The copies drift, and the peer copy must either strip its anchor (unanchored, rejected) or cite un-Acceptable ADRs (AnchorDrift). Two records, no single sovereign truth — the exact drift AnchorDrift exists to prevent.</li><li><strong>Reaching Into a Peer's ADR Catalogue to Anchor a Local Subject</strong> — To author a peer's subject locally, a contributor adds a resolver so evidence_adrs can cite a peer project's Accepted ADRs. This dissolves ADR sovereignty — the host now anchors claims on decisions it did not make and cannot govern — the opposite of ADR-028's consume-by-reference-cannot-mutate model.</li></ul>
|
||||
<ul><li><strong>Authoring a Peer's Positioning Subject in the Host's Tree</strong> — A contributor places project B's Differentiator/ValueProp inside project A's `.ontoref/positioning/` to 'own the story in one place'. Its evidence_adrs are Accepted in B, not A, so `ontoref positioning audit` from A reports AnchorDrift — the subject is homeless, not centralised.</li><li><strong>Duplicating a Subject Across Projects and Syncing by Hand</strong> — The same Differentiator is copied into both the sovereign project and a peer to keep each surface 'complete'. The copies drift, and the peer copy must either strip its anchor (unanchored, rejected) or cite un-Acceptable ADRs (AnchorDrift). Two records, no single sovereign truth — the exact drift AnchorDrift exists to prevent.</li><li><strong>Reaching Into a Peer's ADR Catalogue to Anchor a Local Subject</strong> — To author a peer's subject locally, a contributor adds a resolver so evidence_adrs can cite a peer project's Accepted ADRs. This dissolves ADR sovereignty — the host now anchors claims on decisions it did not make and cannot govern — the opposite of ADR-028's consume-by-reference-cannot-mutate model.</li></ul>
|
||||
|
||||
<h2>Related ADRs</h2>
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ UNWITNESSED. So a check can go green over a shrinking fraction of reality and it
|
|||
perfectly valid. It does not fail. It does not warn. It looks where it always looked, finds nothing
|
||||
wrong there, and signs.</p>
|
||||
<p>AND THE COVERAGE EXPIRES PRECISELY WHEN YOU IMPROVE THE MECHANISM. That is the finding, and it is
|
||||
not a metaphor. In one session, on one witness (`ore rustelo routes`), THREE TIMES:</p>
|
||||
not a metaphor. In one session, on one witness (`ontoref rustelo routes`), THREE TIMES:</p>
|
||||
<p>· the SITE gained ownership of its templates (adr-070's overlay). The witness read only the
|
||||
framework's `crates/pages_htmx/templates/` and reported a site-owned page as broken.
|
||||
· the CONSUMER gained ownership of its routes (`merge_site_routes`). The witness read only the
|
||||
|
|
|
|||
101
site/site/content/adr/en/accepted/adr-074.md
Normal file
101
site/site/content/adr/en/accepted/adr-074.md
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
---
|
||||
id: "adr-074"
|
||||
title: "Context-provision is governed — ontoref is the single source of truth about the protocol; carriers invoke it live and hold no protocol content, pointers, or verifiers of their own"
|
||||
slug: "074"
|
||||
subtitle: "Accepted"
|
||||
excerpt: "A session — a person or an agent — arrives needing to know how the protocol works: how a project"
|
||||
author: "ontoref"
|
||||
date: "2026-07-18"
|
||||
published: true
|
||||
featured: false
|
||||
category: "accepted"
|
||||
tags: ["adr-074", "adr", "accepted"]
|
||||
css_class: "category-adr"
|
||||
---
|
||||
<h2>Context</h2>
|
||||
|
||||
<p>A session — a person or an agent — arrives needing to know how the protocol works: how a project
|
||||
self-governs its relation to a domain, what vocabulary is mandatory, how bonds are declared and
|
||||
retyped. The convenient move, and the one this session nearly took, is to answer where the session
|
||||
already looks: write the how-to into the project's CLAUDE.md, propagate a bond-vocabulary block into
|
||||
every consumer's CLAUDE.md, plant a topic-specific line into a SessionStart hook under `~/.claude/`,
|
||||
add a verifier next to it. Four turns of the same reflex: put the truth where the reader is standing.</p>
|
||||
<p>That reflex is drift by construction, and the ontology already names why. `dev-internal-overlay`
|
||||
classes `.claude/` as dev-internal OPERATIONAL CONFIG — a carrier, not a home for governed content.
|
||||
`ontoref-three-layer-model` states the rule generically: protocol truth is Layer 1 / protocol-qa,
|
||||
and "this entry exists so adopters discover the layering from protocol documentation, not by
|
||||
re-deriving it across three projects"; Layer 3 (per-caller, per-machine wiring) is OUTPUT of a
|
||||
relationship, "never in this project's repo", referenced by "explicit pointers, never copy-paste".
|
||||
ADR-028 already forbids the clone: the ontology is addressable independently and a consumer verifies
|
||||
BY WITNESS, NOT BY COPY.</p>
|
||||
<p>The sharp form of the requirement, as stated in-session: we do not want channels, pointers,
|
||||
declarations, or verifiers SCATTERED across the universe and its constellations on one particular
|
||||
machine's disk. ontoref is the one that governs, and is responsible for the truth about questions
|
||||
like these AS SUCH. The failure is not that carriers exist — an agent does read CLAUDE.md first, and
|
||||
that is legitimate reach. The failure is content, pointers, and verifiers ACCRETING in those carriers
|
||||
as a second authority that no witness keeps in sync with the governed surface. Two copies, no witness,
|
||||
guaranteed divergence the first time one is edited and the other is not.</p>
|
||||
<p>There is already a correct shape in production and it was almost overlooked: the generic on+re
|
||||
conduits (the SessionStart orient hook, the UserPromptSubmit routing that answers "esto ya está
|
||||
gobernado — `ontoref qa show <id>`"). They carry NO protocol content. They ASK ontoref, at read-time,
|
||||
which governed entry houses the current topic, and surface a live pointer INTO the governed surface.
|
||||
The content stays in ontoref; the routing is decided by ontoref; the carrier is a thin, generic,
|
||||
topic-agnostic conduit. That is the pattern this ADR ratifies and generalizes — and it is the pattern
|
||||
whose alternative (topic-specific truth accreting per carrier, per machine) it forbids.</p>
|
||||
|
||||
<h2>Decision</h2>
|
||||
|
||||
<p>CONTEXT-PROVISION ABOUT THE PROTOCOL IS GOVERNED. ontoref's own surface — the ontology, reflection
|
||||
(qa, modes, disciplines, substrate views), adrs, the CLI/daemon/MCP that serve them — is the SINGLE
|
||||
SOURCE OF TRUTH and the SINGLE RESPONSIBLE AUTHORITY for how the protocol works. The answer to a
|
||||
"how does X work in the protocol" question is a QUERY answered by ontoref, reached by asking ontoref
|
||||
at one addressable locus, not a copy read from wherever the asker happened to be standing.</p>
|
||||
<p>Three rules follow, and they are the contract:</p>
|
||||
<p>1. TRUTH LIVES ONLY IN THE GOVERNED SURFACE. Protocol knowledge is authored once, in ontology or
|
||||
reflection, where ontoref can type it, validate it, witness it and version it. A qa entry, a
|
||||
discipline, a schema, an ADR — these are homes. A carrier is not.</p>
|
||||
<p>2. CARRIERS INVOKE; THEY DO NOT REPLICATE. An external carrier (a project or global CLAUDE.md,
|
||||
MEMORY.md, a SessionStart/UserPromptSubmit hook, an agent memory index) may hold at most a THIN,
|
||||
GENERIC, TOPIC-AGNOSTIC invocation that resolves against ontoref at read-time — the shape the
|
||||
orient/routing hooks already have. It holds NO protocol content, NO topic-specific pointer table,
|
||||
NO per-topic declaration. Routing is ontoref's job (the hook asks ontoref which entry is
|
||||
relevant), never a hand-maintained map in the carrier.</p>
|
||||
<p>3. THE GOVERNOR VERIFIES; VERIFIERS ARE NOT SCATTERED. If a check is needed that a carrier has not
|
||||
accreted duplicated truth, that check is ONE command inside ontoref auditing its own carriers —
|
||||
the governor doing its job — never a validator planted per-machine, per-repo, next to each
|
||||
carrier as its own little authority. Centralized-in-ontoref is the cure; scattered-across-disk
|
||||
is the disease, and a scattered verifier is the disease wearing the cure's clothes.</p>
|
||||
<p>Corollary for the bond work that surfaced this (adr-073): the bond how-to lives as ONE governed qa
|
||||
entry (`bond-carrier-layout-howto` in `reflection/qa.ncl`) and as the `bonding` discipline/substrate
|
||||
view that references it — NOT as a bond section propagated into consumer CLAUDE.md files, NOT as a
|
||||
bond-specific hook line, NOT as a per-repo bond verifier. The existing bond vocabulary block in the
|
||||
producer-level CLAUDE.md is legacy duplication under this ADR and is to be thinned to the generic
|
||||
"ask ontoref" conduit, not extended.</p>
|
||||
<p>SCOPE — TRUTH, NOT INSTRUMENTS. This ADR governs protocol TRUTH: definitions, directives,
|
||||
vocabulary, how-the-protocol-works knowledge. OPERATIONAL INSTRUMENTS — fill-in-the-blanks forms,
|
||||
materializable templates, prompt scaffolds, mode step-sequences (reflection/forms/,
|
||||
reflection/templates/, reflection/modes/) — are NOT carriers of truth: filling one produces a
|
||||
disposable work product, not a second authority, and materializing one is not replication. An
|
||||
instrument crosses into this ADR's territory only when it INLINES governed content instead of
|
||||
referencing it. That boundary is watched SOFTLY, from one place — the instrument registry
|
||||
(reflection/instruments.ncl) read by `sync instruments check` — and softly on purpose: an
|
||||
instrument may legitimately NUANCE or EXPLAIN governed content with no intent to stand over the
|
||||
governance; a match is a finding for a human to judge, never an automatic verdict of drift.</p>
|
||||
<p>This ADR is itself an instance of its own rule: it is authored once, here, in the governed adrs/
|
||||
surface; every carrier that needs it points a session at `ontoref` to read it, and copies nothing.</p>
|
||||
|
||||
<h2>Constraints</h2>
|
||||
|
||||
<ul><li><strong>Hard</strong> The bond context-provision how-to lives in the governed qa surface, not in a carrier.</li><li><strong>Hard</strong> The governed provision channel exists as ontoref infrastructure — the substrate-view/discipline registry through which a session is provisioned by asking ontoref.</li><li><strong>Soft</strong> No protocol content, pointer table, or independent verifier lives in any external carrier (CLAUDE.md, MEMORY.md, hooks) as a second source of truth; carriers hold only a thin generic invocation.</li><li><strong>Soft</strong> Session instruments (forms, templates, prompt scaffolds) reference governed entries instead of inlining governed content; the instrument registry exists and the governor audits it from one place, softly.</li></ul>
|
||||
|
||||
<h2>Alternatives considered</h2>
|
||||
|
||||
<ul><li><strong>Propagate the content into every consumer's CLAUDE.md (and a hook line, and a memory entry) so a session has it inline without asking.</strong> — <em>rejected:</em> This is the reflex the ADR exists to stop. It duplicates governed truth into N per-machine carriers with no witness; the first edit that misses one copy is silent drift. dev-internal-overlay classes CLAUDE.md as a carrier, and three-layer-model forbids re-deriving protocol truth across projects.</li><li><strong>Keep content in the governed surface but maintain a per-carrier POINTER TABLE (topic -> entry id) in each CLAUDE.md/hook.</strong> — <em>rejected:</em> A pointer table is governed content in disguise — it encodes what-houses-what and drifts as the surface changes. Routing belongs to ontoref (the orient/routing hooks already decide relevance live); a hand-maintained map fragments that authority across carriers.</li><li><strong>Enforce no-duplication with a verifier installed alongside each carrier, per repo and per machine.</strong> — <em>rejected:</em> That is the scattered-verifier the requirement names explicitly: each deputy carries its own model of the truth, per disk, competing with the governor. One audit inside ontoref keeps the authority singular; scattering it recreates the fragmentation it was meant to prevent.</li><li><strong>Abolish content-bearing carriers entirely — forbid CLAUDE.md/hooks from surfacing protocol knowledge at all.</strong> — <em>rejected:</em> Collapses formalization-vs-adoption toward formalization: carriers are how the protocol reaches a session before any command runs. The synthesis keeps the conduit and empties its payload, rather than removing the reach.</li></ul>
|
||||
|
||||
<h2>Anti-patterns</h2>
|
||||
|
||||
<ul><li><strong>Answering Where the Reader Stands</strong> — Governed protocol knowledge is copied into a carrier the reader already looks at — a project or global CLAUDE.md section, a MEMORY.md entry, a hook body — so a session finds it inline without asking. The copy has no witness binding it to the governed surface; the first edit to one side that the other misses is silent, undetectable divergence, and the carrier now confidently serves a stale truth.</li><li><strong>Deputies With Their Own Badge</strong> — To stop carriers drifting, a verifier is installed next to each carrier — per repo, per machine — each encoding its own model of what the truth should be. The remedy fragments the very authority it was meant to protect: now there are many little verifiers scattered across disks, each a candidate second source of truth, none of them the governor. Enforcement itself becomes the thing that drifts.</li><li><strong>Trusting the Photocopy</strong> — A session treats a carrier's inline copy as authoritative and never asks ontoref, so it cannot tell whether what it read is current. Drift becomes invisible not because it is absent but because nothing ever compares the copy to the source. The carrier was meant to point at the governor; instead it stands in for it.</li></ul>
|
||||
|
||||
<h2>Related ADRs</h2>
|
||||
|
||||
<p><a href="/adr/073">ADR-073</a> · <a href="/adr/028">ADR-028</a> · <a href="/adr/046">ADR-046</a> · <a href="/adr/062">ADR-062</a> · <a href="/adr/018">ADR-018</a></p>
|
||||
12
site/site/content/adr/en/accepted/adr-074.ncl
Normal file
12
site/site/content/adr/en/accepted/adr-074.ncl
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
id = "adr-074",
|
||||
title = "Context-provision is governed — ontoref is the single source of truth about the protocol; carriers invoke it live and hold no protocol content, pointers, or verifiers of their own",
|
||||
slug = "074",
|
||||
excerpt = "",
|
||||
tags = ["adr", "accepted"],
|
||||
page_route = "/adr/074",
|
||||
graph = {
|
||||
implements = [],
|
||||
related_to = ["adr-073", "adr-028", "adr-046", "adr-062", "adr-018"],
|
||||
},
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
# AUTO-GENERATED — do not edit manually
|
||||
# Scope: blog/en
|
||||
# Updated: 2026-07-17T05:56:25Z
|
||||
# Updated: 2026-07-19T04:50:00Z
|
||||
# Regen: nu scripts/content/generate-ncl-index.nu
|
||||
|
||||
std.array.flatten [
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# AUTO-GENERATED — do not edit manually
|
||||
# Scope: blog/en/engineering
|
||||
# Updated: 2026-07-17T05:56:25Z
|
||||
# Updated: 2026-07-19T04:50:00Z
|
||||
# Regen: nu scripts/content/generate-ncl-index.nu
|
||||
|
||||
[
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
# AUTO-GENERATED — do not edit manually
|
||||
# Scope: blog/en/ontoref
|
||||
# Updated: 2026-07-17T05:56:25Z
|
||||
# Updated: 2026-07-19T04:50:00Z
|
||||
# Regen: nu scripts/content/generate-ncl-index.nu
|
||||
|
||||
[
|
||||
import "./a-harness-without-a-subject.ncl",
|
||||
import "./a-rule-without-a-trigger-is-a-sign.ncl",
|
||||
import "./ai-knowledge-tool-who-keeps-it-alive.ncl",
|
||||
import "./context-declared-not-filled.ncl",
|
||||
|
|
|
|||
165
site/site/content/blog/en/ontoref/a-harness-without-a-subject.md
Normal file
165
site/site/content/blog/en/ontoref/a-harness-without-a-subject.md
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
---
|
||||
# Post metadata
|
||||
id: "a-harness-without-a-subject"
|
||||
title: "A harness without a subject: what harness engineering doesn't name yet"
|
||||
slug: "a-harness-without-a-subject"
|
||||
subtitle: "The AI harness is the word of the year: the five layers that wrap a model so it can do real work. But a minimal harness is a hundred lines, every vendor now ships one, and the advantage is moving one layer down — to the subject the harness consults."
|
||||
excerpt: "Harness engineering just named itself as a discipline: documentation as code, architectural constraints, layered verification, periodic consistency audits. All four pillars exist — in flat markdown, held up by manual discipline. This post concedes the whole argument (“the model is commodity, the harness is the advantage”) and adds the next step: the harness governs the verb — how a change is made — and names no subject to check it against. A verb without a subject cannot drift, because drift is precisely a subject diverging from its own declared self."
|
||||
|
||||
# Publication info
|
||||
author: "Jesús Pérez"
|
||||
date: "2026-07-19"
|
||||
published: true
|
||||
featured: true
|
||||
|
||||
# Categorization
|
||||
category: "ontoref"
|
||||
tags: ["ontoref", "harness", "harness-engineering", "agents", "drift", "developer"]
|
||||
|
||||
# Display
|
||||
sort_order: 9
|
||||
|
||||
# Image (card thumbnail + in-post featured)
|
||||
thumbnail: "/images/ontoref-harness-without-a-subject.webp"
|
||||
image_url: "/images/ontoref-harness-without-a-subject.webp"
|
||||
og_image: "/images/og/ontoref-harness-without-a-subject.png"
|
||||
---
|
||||
|
||||
<picture>
|
||||
<source srcset="/images/ontoref-harness-without-a-subject.avif" type="image/avif">
|
||||
<source srcset="/images/ontoref-harness-without-a-subject.webp" type="image/webp">
|
||||
<img src="/images/ontoref-harness-without-a-subject.webp" alt="A harness without a subject: what harness engineering doesn't name yet" width="1536" height="1024" loading="lazy">
|
||||
</picture>
|
||||
|
||||
There is a term going around — the *AI harness* — doing for 2026 what *prompt
|
||||
engineering* did for 2022 and *context engineering* for 2025: naming the place
|
||||
where the outcome is actually decided. The definition settling in
|
||||
([webreactiva's summary](https://www.webreactiva.com/blog/ai-harness) is a good
|
||||
one) is clean: the harness is **everything that wraps the model so it can do
|
||||
real work** — tools, system prompt, context management, permissions, and
|
||||
verification loops. The model is the engine; the harness is the whole vehicle.
|
||||
And the numbers behind the thesis are serious: the same model going from 52.8%
|
||||
to 66.5% on a benchmark with only the harness changed; another jumping from
|
||||
6.7% to 68.3% by changing nothing but the edit format; LangChain measuring
|
||||
10–20 point jumps on tau2-bench just by adding model-specific harness profiles
|
||||
([DataCamp's survey](https://www.datacamp.com/blog/agent-harness) collects
|
||||
them and states the now-canonical equation: **agent = model + harness**).
|
||||
Hence the slogan: *the model is commodity, the harness is the competitive
|
||||
advantage*.
|
||||
|
||||
Conceded. All of it. The harness matters more than the model, and anyone who
|
||||
has run a real agent doesn't need to be told twice.
|
||||
|
||||
Now the step the slogan doesn't take.
|
||||
|
||||
## The harness is becoming commodity too
|
||||
|
||||
The argument carries this inside itself: a minimal harness — read file, list
|
||||
files, edit file — fits in **under a hundred lines**. Every vendor now ships
|
||||
one, and the open-source ones come by the dozen. When the piece that was the
|
||||
advantage can be reproduced in an afternoon, the advantage doesn't vanish: **it
|
||||
moves one layer down**. The question stops being "which harness runs your
|
||||
agent?" and becomes "what does your harness find when it asks *what is this
|
||||
project, and what has it decided?*"
|
||||
|
||||
For most teams, the honest answer is: a pile of markdown. And that is not a
|
||||
caricature — it is the component's own definition: when the harness literature
|
||||
enumerates its "memory and state", what it lists is files, logs, and
|
||||
summaries. State without a type, prose without a contract.
|
||||
|
||||
## Four verbs, no subject
|
||||
|
||||
Look at the full vocabulary of the agent era: you **orchestrate** workflows,
|
||||
wrap them in **guardrails**, run them inside a **harness**, **harvest** their
|
||||
output back into memory. Four verbs, one grammar — and all four govern the
|
||||
**act**. Not one names a **subject**: a thing the project has declared itself
|
||||
to be, that could be checked for still being true.
|
||||
|
||||
That omission is not a gap in the vocabulary; it is its function. A verb
|
||||
without a subject **cannot drift**, because drift is precisely that: a subject
|
||||
diverging from its own declared self over time. What you cannot name, you
|
||||
cannot measure. That is why the ecosystem can ship ever-better harnesses and
|
||||
still have no answer to the one question that matters at agent speed: *is what
|
||||
you declared six weeks ago still true?* The question is not expressible in the
|
||||
grammar it chose.
|
||||
|
||||
The harness is a **spatial** instrument: it contains the act in the moment it
|
||||
happens — this context, these permissions, this verification, now. Drift is
|
||||
**temporal**: the slow separation between what a system says it is and what it
|
||||
has become, measured in commits and sessions, not in tokens. You cannot build
|
||||
a fence against time.
|
||||
|
||||
## The four pillars, typed
|
||||
|
||||
What makes *harness engineering* interesting as a named discipline — Mitchell
|
||||
Hashimoto named it in February 2026 — is that its four pillars map the problem
|
||||
exactly. It's just that each pillar is practiced today in its informal form:
|
||||
flat markdown held up by manual discipline. Each has a typed form, and the
|
||||
difference between the two is whether coherence is **hoped for** or
|
||||
**checked**:
|
||||
|
||||
| Harness engineering pillar | Informal form | Typed form in <a href="/about" class="brand-site">ontoref</a> |
|
||||
|---|---|---|
|
||||
| Documentation as code | `AGENTS.md` — prose the agent reads | An ontology queryable as data: `describe` answers *what is this, what can I do, what is the impact of touching X* |
|
||||
| Architectural constraints | Conventions stated in text | Hard/Soft constraints on every ADR, evaluated by `validate-adrs`: a violation **fails CI** |
|
||||
| Layered verification | Hooks and human review | Structural gates + a signed witness: every act that mutates the model emits a witness; every mutation is the deposit of a witnessed act |
|
||||
| Garbage collection | Periodic consistency audits | Drift as a first-class value: an observer compares declaration against artifact and **proposes** the fix — never applies it silently |
|
||||
|
||||
The fourth row is the most revealing. "Collecting garbage" every so often is
|
||||
admitting the system drifts and resigning yourself to sweeping up. Treating
|
||||
drift as an observable value — something a process detects, names, and turns
|
||||
into a reviewable mutation proposal — is refusing to let the gap between map
|
||||
and territory stay invisible while it grows.
|
||||
|
||||
## Your harness doesn't compete with this — it consults it
|
||||
|
||||
Here is the division of roles, stated without ambiguity: **<a href="/about" class="brand-site">ontoref</a> is not a
|
||||
harness and does not pretend to be one**. It doesn't own the tool loop, it
|
||||
executes nothing on the model's behalf, it will not orchestrate your agents
|
||||
better. It is the layer the harness finds when it asks: the **subject** — a
|
||||
typed model of the project: its decisions with their constraints, its state
|
||||
with its transition conditions, its tensions held rather than collapsed — that
|
||||
any harness can query as data and check every change against.
|
||||
|
||||
The recent taxonomy distinguishes three layers — framework (LangChain,
|
||||
CrewAI), runtime (LangGraph, Temporal), and harness (Deep Agents, the agent
|
||||
SDKs) — and <a href="/about" class="brand-site">ontoref</a> sits in none of the three: it is what all three consult.
|
||||
There is also a hard reason it must live outside, and the literature itself
|
||||
supplies it when it admits its open tension: results become **tightly coupled
|
||||
to the specific harness profile**, and switching harness or model is costly.
|
||||
If the project's knowledge lives inside that profile, changing vehicles means
|
||||
losing it — you are hostage to your harness. A subject declared outside any
|
||||
harness is portable across all of them: accountable to its model, hostage to
|
||||
none.
|
||||
|
||||
The relation is invocation, not replication: the harness (Claude Code, or any
|
||||
other) carries a live pointer to the governed surface; it never copies the
|
||||
content, because a copy is the first drift. And the protocol eats its own
|
||||
cooking: <a href="/about" class="brand-site">ontoref</a> describes itself with its own protocol — its ontology, its
|
||||
ADRs, and its reflection layer are <a href="/about" class="brand-site">ontoref</a> consuming ontoref. The subject it
|
||||
asks you to declare is the one it maintains for itself, and it fails its own CI
|
||||
when that stops being true.
|
||||
|
||||
## The honest boundary
|
||||
|
||||
Keep your harness. Improve it: the five layers are real and so are the
|
||||
numbers. But when the freshly named discipline tells you the advantage lives
|
||||
in the environment rather than the model, ask it the next question: *and what
|
||||
does your environment check the project against, to know it is still what it
|
||||
declared itself to be?* If the answer is a prose file nobody can query as data
|
||||
or validate as a contract, you have an excellent vehicle headed to a
|
||||
destination you never declared. At agent speed, a system with no declared
|
||||
subject drifts faster than any human can watch.
|
||||
|
||||
The answer to that question is already stated — it is the set of phrases
|
||||
<a href="/about" class="brand-site">ontoref</a> uses to define itself, rotating on [its own front page](/):
|
||||
|
||||
> [What you leave stated, someone will be able to verify.](/)
|
||||
|
||||
> [Knowing what you are is cheap. Knowing you still are is not — that must be
|
||||
> verified.](/)
|
||||
|
||||
> [A project with no verifiable reason for being isn't alive: it's being
|
||||
> remembered.](/)
|
||||
|
||||
What you only leave inside the harness, no one will be able to verify.
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
# Generated from a-harness-without-a-subject.md
|
||||
# Schema: ../../../../../../../../../../jesusperezlorenzo/.local/share/rustelo/nickel/content/metadata/post_metadata.ncl
|
||||
# Regenerate: nu scripts/content/md-to-ncl.nu --force
|
||||
|
||||
let schema = import "../../../../../../../../../../jesusperezlorenzo/.local/share/rustelo/nickel/content/metadata/post_metadata.ncl" in
|
||||
|
||||
schema.make_post {
|
||||
id = "a-harness-without-a-subject",
|
||||
title = "A harness without a subject: what harness engineering doesn't name yet",
|
||||
slug = "a-harness-without-a-subject",
|
||||
subtitle = "The AI harness is the word of the year: the five layers that wrap a model so it can do real work. But a minimal harness is a hundred lines, every vendor now ships one, and the advantage is moving one layer down — to the subject the harness consults.",
|
||||
excerpt = "Harness engineering just named itself as a discipline: documentation as code, architectural constraints, layered verification, periodic consistency audits. All four pillars exist — in flat markdown, held up by manual discipline. This post concedes the whole argument (“the model is commodity, the harness is the advantage”) and adds the next step: the harness governs the verb — how a change is made — and names no subject to check it against. A verb without a subject cannot drift, because drift is precisely a subject diverging from its own declared self.",
|
||||
date = "2026-07-19",
|
||||
featured = true,
|
||||
category = "ontoref",
|
||||
tags = ["ontoref", "harness", "harness-engineering", "agents", "drift", "developer"],
|
||||
sort_order = 9,
|
||||
image_url = "/images/ontoref-harness-without-a-subject.webp",
|
||||
graph = {
|
||||
implements = ["witness-as-axis-seam", "drift-observation", "describe-query-layer", "self-describing"],
|
||||
related_to = ["trust-is-an-output-not-an-input", "context-declared-not-filled"],
|
||||
},
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
# AUTO-GENERATED — do not edit manually
|
||||
# Scope: blog/es
|
||||
# Updated: 2026-07-17T05:56:25Z
|
||||
# Updated: 2026-07-19T04:50:00Z
|
||||
# Regen: nu scripts/content/generate-ncl-index.nu
|
||||
|
||||
std.array.flatten [
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# AUTO-GENERATED — do not edit manually
|
||||
# Scope: blog/es/engineering
|
||||
# Updated: 2026-07-17T05:56:25Z
|
||||
# Updated: 2026-07-19T04:50:00Z
|
||||
# Regen: nu scripts/content/generate-ncl-index.nu
|
||||
|
||||
[
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
# AUTO-GENERATED — do not edit manually
|
||||
# Scope: blog/es/ontoref
|
||||
# Updated: 2026-07-17T05:56:25Z
|
||||
# Updated: 2026-07-19T04:50:00Z
|
||||
# Regen: nu scripts/content/generate-ncl-index.nu
|
||||
|
||||
[
|
||||
import "./a-harness-without-a-subject.ncl",
|
||||
import "./a-rule-without-a-trigger-is-a-sign.ncl",
|
||||
import "./ai-knowledge-tool-who-keeps-it-alive.ncl",
|
||||
import "./context-declared-not-filled.ncl",
|
||||
|
|
|
|||
163
site/site/content/blog/es/ontoref/a-harness-without-a-subject.md
Normal file
163
site/site/content/blog/es/ontoref/a-harness-without-a-subject.md
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
---
|
||||
# Post metadata
|
||||
id: "a-harness-without-a-subject"
|
||||
title: "Un arnés sin sujeto: lo que el «harness engineering» aún no nombra"
|
||||
slug: "un-arnes-sin-sujeto"
|
||||
subtitle: "El arnés («harness») es la palabra del año: las cinco capas que envuelven al modelo para que haga trabajo real. Pero un arnés mínimo son cien líneas, cada proveedor ya envía el suyo, y la ventaja se está desplazando una capa hacia abajo: hacia el sujeto que el arnés consulta."
|
||||
excerpt: "El «harness engineering» acaba de nombrarse como disciplina: documentación como código, restricciones arquitectónicas, verificación por capas, auditorías periódicas. Los cuatro pilares existen — en markdown plano, sostenidos por disciplina manual. Este post concede el argumento entero («el modelo es commodity, el arnés es la ventaja») y le añade el paso siguiente: el arnés gobierna el verbo — cómo se hace un cambio — y no nombra ningún sujeto contra el que comprobarlo. Un verbo sin sujeto no puede derivar, porque la deriva es exactamente un sujeto divergiendo de su propio yo declarado."
|
||||
|
||||
# Publication info
|
||||
author: "Jesús Pérez"
|
||||
date: "2026-07-19"
|
||||
published: true
|
||||
featured: true
|
||||
|
||||
# Categorization
|
||||
category: "ontoref"
|
||||
tags: ["ontoref", "harness", "harness-engineering", "agentes", "drift", "developer"]
|
||||
|
||||
# Display
|
||||
sort_order: 9
|
||||
|
||||
# Image (card thumbnail + in-post featured)
|
||||
thumbnail: "/images/ontoref-harness-without-a-subject-es.webp"
|
||||
image_url: "/images/ontoref-harness-without-a-subject-es.webp"
|
||||
og_image: "/images/og/ontoref-harness-without-a-subject-es.png"
|
||||
---
|
||||
|
||||
<picture>
|
||||
<source srcset="/images/ontoref-harness-without-a-subject-es.avif" type="image/avif">
|
||||
<source srcset="/images/ontoref-harness-without-a-subject-es.webp" type="image/webp">
|
||||
<img src="/images/ontoref-harness-without-a-subject-es.webp" alt="Un arnés sin sujeto: lo que el «harness engineering» aún no nombra" width="1536" height="1024" loading="lazy">
|
||||
</picture>
|
||||
|
||||
Circula un término — «AI harness», el arnés — que está haciendo por 2026 lo que
|
||||
*prompt engineering* hizo por 2022 y *context engineering* por 2025: darle nombre
|
||||
a donde se decide de verdad el resultado. La definición que se está asentando
|
||||
([webreactiva la resume bien](https://www.webreactiva.com/blog/ai-harness)) es
|
||||
limpia: el arnés es **todo lo que envuelve al modelo para que haga trabajo real**
|
||||
— herramientas, system prompt, gestión de contexto, permisos y bucles de
|
||||
verificación. El modelo es el motor; el arnés, el vehículo completo. Y los números
|
||||
que acompañan la tesis son serios: el mismo modelo pasando de 52,8 % a 66,5 % en
|
||||
un benchmark cambiando solo el arnés; otro saltando de 6,7 % a 68,3 % cambiando
|
||||
únicamente el formato de edición; LangChain midiendo saltos de 10–20 puntos en
|
||||
tau2-bench con solo añadir perfiles de arnés específicos por modelo
|
||||
([el repaso de DataCamp](https://www.datacamp.com/es/blog/agent-harness) los
|
||||
recoge y deja la ecuación en canon: **agente = modelo + arnés**). De ahí la
|
||||
consigna: *el modelo es commodity, el arnés es la ventaja competitiva*.
|
||||
|
||||
Concedido. Entero. El arnés importa más que el modelo, y quien lo haya
|
||||
comprobado con un agente real no necesita que se lo repitan.
|
||||
|
||||
Ahora el paso que la consigna no da.
|
||||
|
||||
## El arnés también se está volviendo commodity
|
||||
|
||||
El propio argumento lo trae dentro: un arnés mínimo — leer fichero, listar,
|
||||
editar — cabe en **menos de cien líneas**. Cada proveedor envía hoy el suyo, y
|
||||
los de código abierto se cuentan por docenas. Cuando la pieza que era ventaja se
|
||||
puede reproducir en una tarde, la ventaja no desaparece: **se desplaza una capa
|
||||
hacia abajo**. La pregunta deja de ser «¿qué arnés ejecuta a tu agente?» y pasa a
|
||||
ser «¿qué encuentra tu arnés cuando pregunta *qué es este proyecto y qué ha
|
||||
decidido*?».
|
||||
|
||||
Para la mayoría de los equipos, la respuesta honesta es: un montón de markdown.
|
||||
Y no es una caricatura — es la definición del propio componente: cuando la
|
||||
literatura del arnés enumera su «memoria y estado», lo que lista es ficheros,
|
||||
logs y resúmenes. Estado sin tipo, prosa sin contrato.
|
||||
|
||||
## Cuatro verbos, ningún sujeto
|
||||
|
||||
Mira el vocabulario completo de la era de agentes: **orquestas** flujos, los
|
||||
envuelves en **guardarraíles**, los ejecutas dentro de un **arnés**, **cosechas**
|
||||
su salida de vuelta a memoria. Cuatro verbos, una gramática — y los cuatro
|
||||
gobiernan el **acto**. Ninguno nombra un **sujeto**: algo que el proyecto haya
|
||||
declarado ser, y que pueda comprobarse que sigue siendo cierto.
|
||||
|
||||
Esa omisión no es un hueco del vocabulario; es su función. Un verbo sin sujeto
|
||||
**no puede derivar**, porque la deriva es exactamente eso: un sujeto divergiendo
|
||||
de su propio yo declarado a lo largo del tiempo. Lo que no puedes nombrar, no lo
|
||||
puedes medir. Por eso el ecosistema puede enviar arneses cada vez mejores y
|
||||
seguir sin respuesta para la única pregunta que importa a velocidad de agente:
|
||||
*¿sigue siendo verdad lo que declaraste hace seis semanas?* La pregunta no es
|
||||
expresable en la gramática elegida.
|
||||
|
||||
El arnés es un instrumento **espacial**: contiene el acto en el momento en que
|
||||
ocurre — este contexto, estos permisos, esta verificación, ahora. La deriva es
|
||||
**temporal**: la separación lenta entre lo que un sistema dice ser y aquello en
|
||||
lo que se ha convertido, medida en commits y sesiones, no en tokens. No se puede
|
||||
levantar una valla contra el tiempo.
|
||||
|
||||
## Los cuatro pilares, tipados
|
||||
|
||||
Lo interesante del «harness engineering» como disciplina nombrada — Mitchell
|
||||
Hashimoto le puso nombre en febrero de 2026 — es que sus cuatro pilares son un
|
||||
mapa exacto del problema. Solo que cada pilar se practica hoy en su forma
|
||||
informal: markdown plano sostenido por disciplina manual. Cada uno tiene una
|
||||
forma tipada, y la diferencia entre ambas es si la coherencia **se espera** o
|
||||
**se comprueba**:
|
||||
|
||||
| Pilar del «harness engineering» | Forma informal | Forma tipada en <a href="/about" class="brand-site">ontoref</a> |
|
||||
|---|---|---|
|
||||
| Documentación como código | `AGENTS.md` — prosa que el agente lee | Ontología consultable como datos: `describe` responde *qué es esto, qué puedo hacer, qué impacto tiene tocar X* |
|
||||
| Restricciones arquitectónicas | Convenciones enunciadas en texto | Restricciones Hard/Soft de cada ADR, evaluadas por `validate-adrs`: una violación **rompe CI** |
|
||||
| Verificación por capas | Hooks y revisión humana | Gates estructurales + testigo firmado: cada acto que muta el modelo emite un testigo; cada mutación es el depósito de un acto testificado |
|
||||
| Garbage collection | Auditorías periódicas de consistencia | La deriva como valor de primera clase: un observador compara declaración contra artefacto y **propone** la corrección — nunca la aplica en silencio |
|
||||
|
||||
La cuarta fila es la más reveladora. «Recolectar basura» cada cierto tiempo es
|
||||
admitir que el sistema deriva y resignarse a barrerlo. Tratar la deriva como un
|
||||
valor observable — algo que un proceso detecta, nombra y convierte en propuesta
|
||||
de mutación revisable — es negarse a que la separación entre mapa y territorio
|
||||
sea invisible mientras crece.
|
||||
|
||||
## Tu arnés no compite con esto: lo consulta
|
||||
|
||||
Aquí está el reparto de papeles, y conviene decirlo sin ambigüedad: **<a href="/about" class="brand-site">ontoref</a> no
|
||||
es un arnés y no pretende serlo**. No posee el bucle de herramientas, no ejecuta
|
||||
nada por el modelo, no orquestará mejor a tus agentes. Es la capa que el arnés
|
||||
encuentra cuando pregunta: el **sujeto** — un modelo tipado del proyecto: sus
|
||||
decisiones con sus restricciones, su estado con sus condiciones de transición, sus
|
||||
tensiones sin colapsar — que cualquier arnés puede consultar como datos y contra
|
||||
el que cada cambio puede comprobarse.
|
||||
|
||||
La taxonomía reciente distingue tres capas — «framework» (LangChain, CrewAI),
|
||||
«runtime» (LangGraph, Temporal) y arnés (Deep Agents, los SDK de agentes) — y
|
||||
<a href="/about" class="brand-site">ontoref</a> no está en ninguna de las tres: es lo que las tres consultan. Hay además
|
||||
una razón de peso para que viva fuera, y la aporta la propia literatura cuando
|
||||
admite su tensión abierta: los resultados quedan **acoplados al perfil concreto
|
||||
del arnés**, y cambiar de arnés o de modelo sale caro. Si el conocimiento del
|
||||
proyecto vive dentro de ese perfil, cambiar de vehículo es perderlo — eres rehén
|
||||
de tu arnés. Un sujeto declarado fuera de cualquier arnés es portable entre
|
||||
todos ellos: responsable ante su modelo, rehén de ninguno.
|
||||
|
||||
La relación es de invocación, no de réplica: el arnés (Claude Code, el que sea)
|
||||
lleva un puntero vivo a la superficie gobernada; no copia su contenido, porque
|
||||
una copia es la primera deriva. Y el protocolo se aplica a sí mismo el cuento:
|
||||
el propio <a href="/about" class="brand-site">ontoref</a> se describe con su propio protocolo — su ontología, sus ADRs y
|
||||
su capa de reflexión son <a href="/about" class="brand-site">ontoref</a> consumiendo ontoref. El sujeto que te pide
|
||||
declarar es el que él mismo mantiene, y falla su propia CI cuando deja de ser
|
||||
cierto.
|
||||
|
||||
## La frontera honesta
|
||||
|
||||
Quédate con tu arnés. Mejóralo: las cinco capas son reales y los números también.
|
||||
Pero cuando la disciplina que acaba de nombrarse te diga que la ventaja está en
|
||||
el entorno y no en el modelo, hazle la pregunta siguiente: *¿y contra qué
|
||||
comprueba tu entorno que el proyecto sigue siendo el que declaró ser?* Si la
|
||||
respuesta es un fichero de prosa que nadie puede consultar como datos ni validar
|
||||
como contrato, tienes un vehículo excelente hacia un destino que nunca
|
||||
declaraste. A velocidad de agente, un sistema sin sujeto declarado deriva más
|
||||
rápido de lo que ningún humano puede vigilar.
|
||||
|
||||
La respuesta a esa pregunta ya está dicha — son las frases con las que <a href="/about" class="brand-site">ontoref</a>
|
||||
se define a sí mismo, rotando en [su propia portada](/):
|
||||
|
||||
> [Lo que dejas dicho, alguien podrá comprobarlo.](/)
|
||||
|
||||
> [Saber lo que eres es barato. Saber que sigues siéndolo, no — eso hay que
|
||||
> comprobarlo.](/)
|
||||
|
||||
> [Un proyecto sin razón de ser verificable no está vivo: está siendo
|
||||
> recordado.](/)
|
||||
|
||||
Lo que solo dejas dentro del arnés, nadie podrá comprobarlo.
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
# Generated from a-harness-without-a-subject.md
|
||||
# Schema: ../../../../../../../../../../jesusperezlorenzo/.local/share/rustelo/nickel/content/metadata/post_metadata.ncl
|
||||
# Regenerate: nu scripts/content/md-to-ncl.nu --force
|
||||
|
||||
let schema = import "../../../../../../../../../../jesusperezlorenzo/.local/share/rustelo/nickel/content/metadata/post_metadata.ncl" in
|
||||
|
||||
schema.make_post {
|
||||
id = "a-harness-without-a-subject",
|
||||
title = "Un arnés sin sujeto: lo que el «harness engineering» aún no nombra",
|
||||
slug = "un-arnes-sin-sujeto",
|
||||
subtitle = "El arnés («harness») es la palabra del año: las cinco capas que envuelven al modelo para que haga trabajo real. Pero un arnés mínimo son cien líneas, cada proveedor ya envía el suyo, y la ventaja se está desplazando una capa hacia abajo: hacia el sujeto que el arnés consulta.",
|
||||
excerpt = "El «harness engineering» acaba de nombrarse como disciplina: documentación como código, restricciones arquitectónicas, verificación por capas, auditorías periódicas. Los cuatro pilares existen — en markdown plano, sostenidos por disciplina manual. Este post concede el argumento entero («el modelo es commodity, el arnés es la ventaja») y le añade el paso siguiente: el arnés gobierna el verbo — cómo se hace un cambio — y no nombra ningún sujeto contra el que comprobarlo. Un verbo sin sujeto no puede derivar, porque la deriva es exactamente un sujeto divergiendo de su propio yo declarado.",
|
||||
date = "2026-07-19",
|
||||
featured = true,
|
||||
category = "ontoref",
|
||||
tags = ["ontoref", "harness", "harness-engineering", "agentes", "drift", "developer"],
|
||||
sort_order = 9,
|
||||
image_url = "/images/ontoref-harness-without-a-subject-es.webp",
|
||||
graph = {
|
||||
implements = ["witness-as-axis-seam", "drift-observation", "describe-query-layer", "self-describing"],
|
||||
related_to = ["trust-is-an-output-not-an-input", "context-declared-not-filled"],
|
||||
},
|
||||
}
|
||||
|
|
@ -37,13 +37,13 @@
|
|||
|
||||
<rect x="290" y="176" width="210" height="50" rx="7" fill="#1b2330" stroke="#1c2530"/>
|
||||
<text x="302" y="194" class="t" font-size="10.5" fill="#c0ccd8">adrs/</text>
|
||||
<text x="302" y="208" class="s" font-size="9.5" fill="#8090a4"><tspan class="t" fill="#e8a838">73</tspan> records · <tspan class="t" fill="#e8a838">69</tspan> accepted</text>
|
||||
<text x="302" y="208" class="s" font-size="9.5" fill="#8090a4"><tspan class="t" fill="#e8a838">74</tspan> records · <tspan class="t" fill="#e8a838">70</tspan> accepted</text>
|
||||
<text x="302" y="220" class="s" font-size="9.5" fill="#8090a4">typed constraints · warrant · ondaod</text>
|
||||
|
||||
<rect x="512" y="176" width="186" height="50" rx="7" fill="#1b2330" stroke="#1c2530"/>
|
||||
<text x="524" y="194" class="t" font-size="10.5" fill="#c0ccd8">reflection/schemas/</text>
|
||||
<text x="524" y="208" class="s" font-size="9.5" fill="#8090a4"><tspan class="t" fill="#e8a838">32</tspan> schemas · <tspan class="t" fill="#e8a838">8</tspan> forms</text>
|
||||
<text x="524" y="220" class="s" font-size="9.5" fill="#8090a4"><tspan class="t" fill="#e8a838">47</tspan> migrations</text>
|
||||
<text x="524" y="208" class="s" font-size="9.5" fill="#8090a4"><tspan class="t" fill="#e8a838">35</tspan> schemas · <tspan class="t" fill="#e8a838">11</tspan> forms</text>
|
||||
<text x="524" y="220" class="s" font-size="9.5" fill="#8090a4"><tspan class="t" fill="#e8a838">48</tspan> migrations</text>
|
||||
|
||||
<rect x="710" y="176" width="206" height="50" rx="7" fill="#1b2330" stroke="#1c2530"/>
|
||||
<text x="722" y="194" class="t" font-size="10.5" fill="#c0ccd8">positioning/</text>
|
||||
|
|
@ -70,7 +70,7 @@
|
|||
|
||||
<rect x="430" y="286" width="486" height="46" rx="7" fill="#1b2330" stroke="#1c2530"/>
|
||||
<text x="442" y="305" class="t" font-size="10.5" fill="#c0ccd8">reflection/modules/ · <tspan fill="#e8a838">38</tspan> Nushell modules</text>
|
||||
<text x="442" y="320" class="s" font-size="9" fill="#8090a4"><tspan class="t" fill="#e8a838">29</tspan> DAG modes · describe · adr · validate · backlog · sync · graph · view · qa · …</text>
|
||||
<text x="442" y="320" class="s" font-size="9" fill="#8090a4"><tspan class="t" fill="#e8a838">30</tspan> DAG modes · describe · adr · validate · backlog · sync · graph · view · qa · …</text>
|
||||
|
||||
<!-- ── BAND 3 · CRATES ───────────────────────────────────────────── -->
|
||||
<rect x="30" y="362" width="900" height="100" rx="9" fill="#161c24" stroke="#2a3644"/>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Loading…
Add table
Reference in a new issue