Skip to content

feat: forge discipline, readiness gauging, comprehension probes#1

Merged
nrdxp merged 38 commits into
masterfrom
amend/forge-and-readiness
Jul 8, 2026
Merged

feat: forge discipline, readiness gauging, comprehension probes#1
nrdxp merged 38 commits into
masterfrom
amend/forge-and-readiness

Conversation

@nrdxp

@nrdxp nrdxp commented Jul 8, 2026

Copy link
Copy Markdown
Owner

Summary

Writes back into predicate's doctrine two disciplines refined in the field across recent campaigns: measurable pre-dispatch readiness and forge discipline — plus the role-lens language carrying both into the council seats.

What's here

  • New skills/forge/ — a conditional discipline (no forge → no obligation; forge → full obligation): branch↔PR mapping including stacked PRs, self-contained PR prose (zero process-internal references, SHA-pinned permalinks), review findings + triage recorded on the PR, merge as a consent act, and a five-point forge audit checklist owned by the lead-maintainer seat at merge-consent and campaign CLOSE.
  • Campaign (drafting-time): the Readiness Is Measurable philosophy — four gaugeable numbers (evaluator coverage, comprehension-probe scores, seam-type completeness, red-test/golden-vector inventories) reported with the routing table and approved with it; layer 0 manufactures the campaign's own evaluators before any implementation node; the anti-over-preparation rule (prepare evaluators and seams, never solutions); READINESS_GATE and FORGE_WHEN_PRESENT prime directives.
  • Boundary: the comprehension probe — a zero-context cheap-tier dry run that simulates the IBC's consumer (plan + unanswerable questions + canary traps for known doctrine temptations), positioned as the empirical validator of S1–S7 rather than an eighth condition.
  • Orchestration (run-time): probe step for JIT-authored IBCs against the live tip; a forge-wiring table binding forge acts to driver states (draft PR at DERIVE, accuracy + review-on-record through MERGE/CHECKPOINT, audit at CLOSE); FORGE input parameter.
  • Conditioning deltas: lead-maintainer seat carries the forge audit inside merge-consent; architect seat owns the readiness numbers at dispatch; boundary-worker probes before presenting. Composition suite: 126/126 pass.

Design decisions

  • Forge applicability is conditional by mechanical test (does origin resolve to a forge accepting contributions?), so forge-less projects owe nothing.
  • The forge audit folds into the lead-maintainer seat rather than minting a new council seat: the PR is the merge's public artifact, and the seat that consents to what lands also owns how the landing reads. Delegation to a dedicated reviewer is permitted when the surface is large; the seat retains the verdict.
  • The probe is deliberately not S8: a failing probe always localizes to a violated existing condition — it's measurement, not new law.

Out of scope

  • Core-law (conditioning/core.ncl) editing — deliberately untouched: it is shared with a live campaign, and the identified tightening candidates are proposed separately for the head's ratification rather than landed here.
  • Probe/readiness automation (scripts) — the disciplines are specified in prose; tooling is follow-up.

Verification

  • Predicate's own commit gate (link audit + message constraints) passed on every commit — including once catching and rejecting an over-length header from the author of this PR.
  • conditioning/test_conditioning.sh: 126/126 pass with the persona deltas.

nrdxp added 30 commits June 28, 2026 12:23
Author conditioning/modules/council.ncl, the shared station every
council seat carries, distilled from the architect-council ARCHITECTURE
(0b/2/3/5/5a/5b/6). It mirrors modules/reviewer.ncl's shape: a header
comment plus one plain-String literal, composed between core and a
per-seat lens delta and guarded verbatim by HasModule at wire time.

The module encodes only the class spine: the pact (R/I/U as Nickel
contracts that fail on omission, gating gate-advancement and binding
residue); the deliberation protocol (independent-deposit-first, then
driver-relayed hub-and-spoke correction); and the governance spine
(domain sovereignty plus delegation table, the composer-moderator hub
checked by the auditor, the auditor's load-bearing independence and
head-escalation, the barring lifecycle, Evidence>Authority both ways,
and proportional standing convening).

Thin overlay above core: it adds the council station only and does not
restate the always-on law (the core sentinel is absent). The per-seat
lens deltas and compose wiring are separate nodes.
The persistent council's seats accumulate standing across a campaign, so
the balance of power between them must be machine-enforced, not prose.
Add council.ncl as a first-class peer of dag.ncl: a two-layer intrinsic
contract (Constitution + DecisionLedger) where `nickel export` IS the
gate. A gapped, unilateral, ungrounded, barred, no-consent, or
un-ratified law fails the export with no skippable roundtrip step.

Finalize the corrected decision taxonomy: reconcile-accept and
head-ratified dag-amendment route to the architect, dispatch/convene/
lifecycle to the composer, merge to the maintainer, bar as a 'human
type. Two named must_assent guards make defeater-resistance structural:
merge-consent (maintainer) and head-ratification (human) are required
regardless of the assent class and checked before the generic predicate,
so a later reclassification cannot silently drop a co-signer.
Prove the council contract is non-trivial: a wrong verdict changes an
exit code. test_council.sh runs `nickel export` per committed fixture
under ledger/fixtures/council/ and asserts both the exit code and that
each rejection names its OWN invariant, so no negative control can pass
by an incidental shape error.

Six controls: a complete constitution with a routine owner-only decision
exports clean (proving proportional convening is lawful); gapped,
unilateral, merge-without-consent, barred-seat, and dag-amendment-
without-head each fail for their named reason. Fixtures carry the house
EXPECT polarity annotation so a future recursive sweep classifies them
correctly. Standalone-runnable; not yet wired into an aggregate runner.
The head (human) was a standing seat counted in the 'full machine-
consensus tally, so a 'close decision was satisfied by folding the head
into consensus. nrd ratified two distinct gates instead: the machine
council reaches consensus, THEN the head ratifies on top.

- mark the head structurally (Seat.head) and exclude it from the 'full
  tally, which now sums the four machine seats only;
- require head ratification on 'close via the existing must_assent
  mechanism (must_assent = ["human"]), the same guard that makes 'merge
  require the maintainer and 'dag-amendment require the head.

A 'close with full machine consensus but no head now fails specifically
on head-ratification, not on a generic consensus shortfall. New fixture
close_no_head.ncl proves it; unilateral.ncl is re-pointed to prove the
complementary gate (head present, machine consensus absent ->
anti-unilateral). good.ncl already carried the head, so it stays clean.
Author the three standing-seat persona deltas (architect, lead-
maintainer, process-auditor) as thin Nickel String lenses riding the
N2 council-class module. Each states only its own basin and
decision-domain — boundary/coherence, the hostile merge-consent gate,
and the independent process+residue audit — and references the shared
spine rather than restating it, mirroring the hickey-reviewer shape.

This decorrelates the single architect basin into role-divergent
seats; wiring into compose.ncl and install.sh is deferred to N5.
The council fixtures were Nickel instances that imported and applied
council.ncl inline. The house rule is contracts stay Nickel while data
instances are YAML, so re-render every fixture as a pure-data YAML
instance and validate it externally.

Add council_apply.ncl, a single shape-dispatching apply-contract: a
value carrying `seats` is validated by Constitution, otherwise by
DecisionLedger threaded with the canonical constitution.yaml (the
constructor's argument must be supplied in the apply-file, since
--apply-contract has no parameter mechanism). One apply-file because the
node's file surface names exactly one.

council.ncl is the law and stays byte-unchanged. Its Seat.standing and
DelegationRule.required_assent are bare enum contracts that reject the
plain strings a pure-data YAML instance carries, so the apply-file lifts
those known strings to the tags the contracts expect before the law
runs. Every fixture value is a valid tag, so the lift is lossless and no
invariant is weakened.

Rewrite test_council.sh to validate each YAML fixture via
`nickel export <fixture>.yaml --apply-contract council_apply.ncl`,
preserving all case semantics: the valid ledger and the canonical
constitution export clean; gap/unilateral/merge-no-consent/barred/
dag-amend-no-head/close-no-head each still fail for their own named
invariant keyword. The gate never re-implements an invariant in bash.
The council had a station (the shared module) and a law contract
(council.ncl) but no skill binding a dispatched SEAT to a procedure
— the LAW half of workers : worker-skills :: council-seats : skill
+ persona. Without it, "decision-type X routes to seat Y" had no
discipline to route into.

Author skills/council/SKILL.md as the operating SOP a seat runs:
the deliberation protocol (independent-deposit-first, hub-and-spoke
as the degrade-to-primitive fallback), the pact's gate-blocking
R/I/U obligations, the governance spine (delegation table, composer
checked by an independent auditor, the barring lifecycle), and the
act of recording assent and findings. The skill references the
station and council.ncl rather than restating them.

A seat's deposit and the decision ledger are YAML instances
validated by an externally-applied Nickel contract (deposit.ncl,
council.ncl's DecisionLedger) — contracts are Nickel, data is YAML.
Fidelity and non-restatement confirmed by decorrelated review.
Green deterministic gates are necessary but never sufficient to land a
node: the lead maintainer must affirmatively consent to a merge. That
floor had no machine check — an orchestrator under execution momentum
could merge a 'merge decision the maintainer never assented to, and only
a human would catch it.

council_consent.sh closes the gap. It reduces to council.ncl via
`nickel export <ledger> --apply-contract council_apply.ncl` rather than
re-implementing assent-membership in bash, so the contract stays the one
source of the law; a non-zero export is only read as a consent failure
when it names the `merge-consent:` guard, so an incidental shape error
cannot masquerade as a verdict. Wired into the MERGE state as a
precondition run before `git merge`, mirroring the adherence_audit and
recorder_close_check sibling gates.
The recommendation to prefer `--no-ff` for sequential/distinct-concern
landings was agent-fabricated and never specced. Isolation is verified
by branch reachability (every non-merge first-parent commit traces to a
node/* branch), not by merge shape — adherence_audit.sh already encodes
that merge-shape-agnostic law, so the prose recommending a specific
strategy contradicted the audit it claimed to serve.

This was recorded as a correction but never applied to source. Remove
the `--no-ff` clause from the MERGE row (SKILL.md), the guard_note
parenthetical (state_machine.ncl), and the three demo invocations
(TRANSCRIPT.md), leaving the already-correct any-strategy framing. The
descriptive `--no-ff` comment in adherence_audit.sh is the correct
framing and is left untouched.
The three landed standing-council seats (architect, lead-maintainer,
process-auditor) had a contract, a module, and personas but no path
into the generator, so they could not be dispatched.

Wire the council class into compose.ncl mirroring the reviewer class:
a council import-record plus per-seat fields composed core ++
council_module ++ seat-delta, each guarded by HasCore and HasModule
council_module and pulling no producer (a seat reasons about
architecture, it does not write code). Register COUNCIL_ROLES in
install.sh, fold it into AGENT_ROLES so each seat materializes as a
predicate-<seat>.md agent, and give each a routing description. Mirror
the F6 lockstep and the seat-assertion block in the test suite, with
COUNCIL_ROLES kept byte-identical across both files.
The single output-style slot rendered the architect orchestrator, but
the architect now holds a council SEAT (its judgment) — one identity
competing in two places (finding F3). nrd ratified the composer as the
single output style and the clean rename of the slot token.

Author personas/composer.ncl, the conductor/moderator: the live front
door that scales ceremony, convenes the council proportionally,
sequences deliberation, and integrates decisions — checked by the
process-auditor. It pulls no producer (a moderator is not a
code-writer), so the slot sheds the action procedure. Repoint the
output-style field to it and delete the orphaned architect persona
(now the architect-SEAT).

Clean-rename the slot token architect->composer everywhere it renders
the output style: the compose field, OUTPUT_STYLE_NAME/FILE and the
role default in the generator, the bootstrap delivery call, the
round-trip tests, and the architecture doc's role table. The conceptual
"report to architect" escalation in the doc is left for the narrative
pass (N7), which pluralizes single-architect prose.
F11: decorrelated review found the composer's record-linkage wording
weak in two places against ARCHITECTURE.md 0b/5b. Integration said
only "integrate the result" with no tie to a durable decision, and
the auditor's independence was grounded in convene/control limits but
not in the actual basis: it reads the durable record directly. Tighten
both existing clauses in place so integration produces a recorded
decision in the durable decision-ledger and the auditor's independence
rests on reading that record rather than a composer-curated summary.
F9: the module's bar-ratification line read "the HEAD (or a quorum)
ratifies", contradicting the council.ncl contract it documents. A bar
is a 'human decision-type, and the head-ratification guard requires the
literal "human" in assent (council.ncl:115,120-127) -- a quorum alone
fails. Drop the quorum path so the prose matches the contract; the
line-82 'subset gloss legitimately keeps its own quorum wording.
council.ncl's 'human decision-class makes a bar require literal
human assent; a quorum alone fails the gate (council.ncl:115). The
persona text claimed "the HEAD (or a quorum) ratifies", contradicting
the contract and the already-corrected modules/council.ncl. Align the
wording to "the HEAD ratifies".
The campaign/orchestration narrative described a single architect who
surveyed, judged, drove, and merged. The standing-council model splits
those decisions across seats, so route each to its owner per the
delegation table (constitution.yaml): boundary/plan/reconcile-accept ->
architect seat, drive/dispatch/lifecycle -> composer, merge -> the
lead-maintainer's affirmative consent, and the human-seam poles -> the
HEAD seat. Narrate the accept-not-equal-merge split and rename
ARCHITECT_AS_JUDGE to COUNCIL_AS_JUDGE; the re-run-evaluators and
worker-self-cert-void rules keep their meaning. Capability terms
(architect-tier/-class) and the mechanical executor -- pseudocode
steps, exit-code routing, gate commands, frozen state tables -- and
rules.md citations are left unchanged.
The conditioning output style installs as predicate-composer.md (the
composer is the output-style persona; see install.sh), but the docs
still pointed at the old predicate-architect.md and called it "the
architect law". Update the stale filename and law-name references in
the craft guide, getting-started, and conditioning-layer docs. The
distinct predicate-architecture.md document is left untouched.
The DAG tracker had dag_apply.ncl, paving "author the instance as
pure-data YAML, gate via nickel export --apply-contract". The findings,
context-map, and reconcile-log trackers had only their law contracts and
.ncl test fixtures — no apply-file — so inline-Nickel was their only
paved instance path, the asymmetry that drove trackers to be written in
Nickel instead of data.

Each apply-file imports its law contract (unchanged) and exposes a
custom contract that lifts the bare-enum fields a pure-data YAML carries
as strings to the tags the law expects, then delegates: findings adapts
severity/status, context_map adapts kind, reconcile adapts
verdict/state. The lift is lossless and the intrinsic gate stays intact
(a string status would otherwise make the resolved-requires-evaluator
check silently inert).
The artifact table cited the bare law contracts and only the DAG row
gave the "authored as YAML, validated via --apply-contract" treatment,
so the findings and reconcile rows still implied a Nickel-authored
instance and there was no row for the context map at all.

Give the findings and reconcile rows the DAG row's treatment, add the
missing context-map row, and point every Contract cell at the apply-file
that gates it. Reword the lead so the instances-are-YAML model covers
all four trackers, not just the DAG.
test_council.sh proves council.ncl's invariants in isolation. It does
not prove the law, the merge-consent gate, and the YAML decision-ledger
instances COMPOSE — that the consent gate and the law agree over the
same instances and each catches the failure class it owns.

This smoke composes the landed primitives over the existing fixtures:
good.yaml is the joint PASS witness (consent gate rc 0 AND law rc 0);
merge_no_consent.yaml is caught by the consent gate (merge-consent);
close_no_head.yaml is routed to the law directly (head-ratification),
since the consent gate returns rc 2 for any non-merge-consent failure.
Every verdict reduces to council_consent.sh or the apply-contract — no
invariant is re-implemented in bash.
The reviewer-class campaign built the standing council but shipped no
discoverability reference, so a zero-context maintainer had no durable
entry point to understand the roster, the law, or how to convene it.

Add docs/council.md (Divio reference): the seat roster and lifecycles,
the two-layer council.ncl law (decision taxonomy, assent classes, the
merge-consent and head-ratification guards, the intrinsic gates), the
deposit-and-decision flow, and a minimal convene path via /council.

Every claim links to a committed authority (council.ncl, the canonical
constitution.yaml, the consent gate, the /council skill). The doc does
not link the design-notes ARCHITECTURE.md: it lives only in ephemeral
.scratch, so a permanent doc must ground in durable sources instead.
The architect→composer rename landed in conditioning/ARCHITECTURE.md
but the sibling conditioning-layer.md was missed except one line,
leaving stale references to the deleted personas/architect.ncl. Mirror
the ARCHITECTURE.md target forms onto the persona table, compose.ncl
block, --field call, and the subagent-injection note so both documents
agree on the composer role.
Post-council, the reconcile-time judge that can overrule a grounded
reviewer finding is the architect-seat specifically, not the architect
role at large. Name the seat so the veto authority is unambiguous.
The composer CONDUCTS the campaign: it convenes the seats, sequences
deliberation, and integrates the vote. If it also casts a required
vote in the 'full machine-consensus for a close, it self-certifies
the very work it orchestrated — the un-decorrelation the council
exists to prevent.

Add Seat.conductor (Bool, default false), mirroring how head is
already excluded, and filter machine_ids on
`standing == 'standing && !s.head && !s.conductor`. The 'full tally
is now exactly the independent judging seats (architect, maintainer,
auditor); the composer stays a declared member that conducts the
vote and the head ratifies atop it — both members, neither counted.

Mark the composer seat conductor: true; drop composer from good.yaml's
close assent (no longer required) and add close_missing_seat.yaml
proving a close short one judging seat still fails anti-unilateral —
the exclusion narrows who votes, it does not lower the quorum bar.
Resolve the law-vs-prose contradiction (F15): the constitution
declares the composer a standing seat, yet the prose called it
"NOT a seat". The law now excludes the conductor from the 'full
tally, so the precise statement is that the composer is a council
MEMBER that CONDUCTS the consensus but does not vote in it — it
cannot self-certify the close it orchestrated.

Tighten the persona header and body and the module's delegation
and moderator notes from "the whole council" / "NOT a seat" to
"the hub/conductor, not a consensus-voter". Both files stay thin.
nrdxp added 8 commits June 29, 2026 09:32
Predicate's council law lived only in a test fixture; the production
merge-consent gate validated real decision-ledgers against test
scaffolding (council_apply imported the fixture). Add the constitution
as a first-class CONDITIONING value (conditioning/constitution.ncl, a
Nickel record conforming to council.ncl's Constitution with native enum
tags) and repoint the production apply at it, so consent reduces to
predicate's own law.

Split off council_fixture_apply.ncl (byte-identical but threading the
fixture) and point the two unit-test gates at it, so the law's tests
stay self-contained. Lands atomically: a partial split would red a gate.
The composer CONDUCTS the council but carried no data-derived view of
the law it routes. Fold a constitution->prose render (the seats plus the
decision_type->owner->required_assent delegation table) into the
composer's system prompt as a compose segment, generated from
conditioning/constitution.ncl so editing the law re-renders the prompt.

Pin it with a test_conditioning assertion on the rendered table, and fix
the council SKILL to point at the conditioning constitution rather than
the false "declared in AGENTS.md".
Two documents described the conditioning composition layer:
docs/conditioning-layer.md (human-facing, linked from the
architecture entry point) and conditioning/ARCHITECTURE.md
(normative contract, cited from code comments). Both had
lagged the generator -- conditioning-layer.md by two campaigns
-- and they disagreed with each other: the live compose.ncl is
a three-segment law (core ++ modules ++ delta) over 19 roles in
three classes with a rendered constitution, while the docs still
described a two-segment, seven-role world.

Consolidate into docs/conditioning-layer.md, authored against
the live generator as ground truth: the three-segment law, the
producer/reviewer/council module classes, all 19 roles, the
single-sourced constitution render, and the real delivery
surfaces (output style + 18 agents + GEMINI.md). Delete the
redundant ARCHITECTURE.md, re-point its four code citations to
the surviving doc, and drop its vestigial campaign scaffolding
(per-node slot table, downstream-node checklist, reserved halts).

The generator itself was already correct; this is a docs-only
reconciliation. Verified: all 19 roles export, doc-audit link
gate passes, conditioning sweep 5/5.
The prior commit removed conditioning/ARCHITECTURE.md but, due to
a staging error, did not include the artifacts the consolidation
depends on: the rewritten docs/conditioning-layer.md (authored
against the live generator) and the four code-comment citations
re-pointed away from the deleted file. Without this commit the
deletion stands alone and the surviving doc is stale.

This lands them: docs/conditioning-layer.md now documents the
three-segment law, the producer/reviewer/council modules, all 19
roles, the constitution render, and the real delivery surfaces;
compose.ncl, core.ncl, craft-guide.md, and install.sh point at
the surviving doc instead of ARCHITECTURE.md.

Verified: all 19 roles export, doc-audit link gate passes,
conditioning sweep 5/5.
The forge is the public half of the durable record: branch-to-PR
mapping (stacked PRs included), self-contained PR prose with zero
process-internal references and SHA-pinned permalinks, review findings
and triage recorded on the PR, merge as a consent act through the
lead-maintainer seat, and the forge audit checklist run at
merge-consent and campaign CLOSE. Applicability is conditional by
design: no forge, no obligation.
Campaign (drafting-time): the Readiness Is Measurable philosophy - four
pre-dispatch numbers (evaluator coverage, probe scores, seam-type
completeness, red-test/golden-vector inventories) reported with the
routing table and approved with it; layer 0 manufactures the campaign's
own evaluators before any implementation node; the anti-over-preparation
rule (prepare evaluators and seams, never solutions); READINESS_GATE and
FORGE_WHEN_PRESENT prime directives.

Boundary: the comprehension probe - a zero-context cheap-tier dry run
that simulates the IBC's consumer (plan plus unanswerable questions;
canary traps for known doctrine temptations) as the empirical validator
of S1-S7.

Orchestration (run-time): probe step for JIT-authored IBCs at the layer
boundary; the forge-wiring table binding forge acts to driver states
(draft PR at DERIVE, accuracy plus review-on-record through
MERGE/CHECKPOINT, audit at CLOSE); FORGE input parameter.

Commit-hygiene: merge type cross-references the forge discipline.
Lead-maintainer: merge-consent includes the forge audit - the PR is the
public half of the record the seat maintains; accurate prose, zero
process-internal references, review-on-record. Architect: owns the
readiness numbers at dispatch; unmeasured readiness is a boundary that
does not bound. Boundary-worker: probe before present - the
comprehension probe simulates the IBC's consumer before Approve.
Conditioning e2e suite: 126/126 pass.
@nrdxp nrdxp merged commit e4c218b into master Jul 8, 2026
0 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant