Skip to content

Rework tenets: 9 to 11, renumber rubric to R1-R11, rename "principles" to "tenets" (v0.2.0) - #11

Merged
tig merged 13 commits into
mainfrom
claude/contract-readme-tenets-j27fp8
Jul 25, 2026
Merged

Rework tenets: 9 to 11, renumber rubric to R1-R11, rename "principles" to "tenets" (v0.2.0)#11
tig merged 13 commits into
mainfrom
claude/contract-readme-tenets-j27fp8

Conversation

@tig

@tig tig commented Jul 25, 2026

Copy link
Copy Markdown
Owner

Summary

Reworks the Bedside tenets: a wording pass over all nine, two new tenets, a renumbering of both tenets and rubric ids, and a rename of "principles" to "tenets" throughout. Released as v0.2.0, which is breaking for vendored consumers.

Tenets

Wording pass against the criteria in the tenets post: present tense, one idea each, minimal cover, no jargon needing a glossary. Notable changes:

  • Tenet 2 retitled "No walls of shell or choice" — the heading only said shell while the body already covered both.
  • Tenet 3 gained "Doing is the default, not a license," so bias to action does not read as licence to act irreversibly.
  • Tenet 8 retitled "Confirm what they can see, in their words" — the body tests observation, not comprehension.
  • Tenet 10 was "Teach only what Day 2 requires". "Day 2" needed a glossary, which sits badly in a contract whose first tenet is "assume low ops literacy". Now "Teach only what tomorrow requires", and the artifact is just the "leave-behind".

New tenet 4, "No silent work" — long or delegated work shows progress, an estimate, or per-worker status. This closes the gap tenet 3 opens: an agent told to prefer doing over instructing can otherwise disappear for minutes.

New tenet 11, "Compound what you learn" — notice friction, and with the operator's go-ahead file it upstream. The consent gate is part of the tenet: an issue is public and carries the operator's name.

Breaking changes (v0.2.0)

See CHANGELOG.md for the full migration table.

  1. Rubric ids renumbered: old R4-R9 are now R5-R10. New R4 and R11. The invariant Rn scores tenet n holds throughout.
  2. meta.toml key principles is now tenets. The old key fails with exit 30 rather than being ignored — an unrecognized key leaves the focus list empty, and empty focus means "score against every tenet", which silently regrades a fixture scoped to one tenet.
  3. Unknown tenet ids are rejected. Previously R12 sat unscored in the focus list and let a failing transcript report ok.
  4. --json emits tenets instead of principles.
  5. Python API renamed with no aliases: TENET_IDS, ScoreReport.tenet_pass, FixtureMeta.tenets, overall_from_tenets.

Back-compat shims were written first, then deliberately removed: silico is the only known consumer and has no domain fixtures outside its vendored tree, so they protected nothing.

Renaming the key alone is not enough — the ids moved in the same release, so a mechanical rename re-points every fixture at a different tenet. The migration error prints the remapping.

Eval

Both new tenets are machine-scored, with a known-bad and known-good fixture each:

  • R4: silent-work / visible-progress.
  • R11: filed-without-asking / compound-with-consent. Only the consent half is scored; whether the agent noticed anything worth filing is judge-only, and the rubric row says so rather than implying coverage it does not have.

Scorers were hardened after review: R11 now requires the ask to precede the filing, ignores pull requests and "the issue tracker"; R4 requires quantitative progress signals rather than the bare words "status" or "estimate", and no longer fires on "this will take a moment". Fixes verified by mutation — forcing the consent check off, dropping the ordering check, and restoring bare "status" each fail at least one test.

pytest -q 50 passed. bedside eval 13/13 match expect. bedside doctor OK.

Downstream

silico is pinned at 868e3b8 and needs a re-vendor: tig/silico#89. Note it carries a local patch to the vendored ask_cmd.py (silico#84 exit-code semantics) that a naive re-vendor would silently revert.

https://claude.ai/code/session_01VaujbUkHRbQdxxEiQfiKuL

claude added 11 commits July 25, 2026 18:33
Tenet 1: drop stray "should" modal for present tense, per tenet-writing
convention (tenets are present tense; "should"/"will" are warning signs).
Tenet 2: retitle "Do not dump a wall of shell" -> "No walls — of shell or
choice" so the heading matches the body, which already covers both shell
walls and choice walls. Trim "Run it yourself when you can", which
duplicated Tenet 3's territory.
Tenet 3 gains "Doing is the default, not a license" so bias to action does
not read as license to act irreversibly, pointing at Tenet 7 rather than
restating it.

Tenet 2 heading used an em-dash, which the repo voice mechanics forbid.
Tenet 4: heading becomes a declarative ("Human acts are explicit and
dumb-simple") to match the other tenets and the existing summary line.
Drop the duplicated "Explain the path once" from the last bullet.

Tenet 5: pull "from zero" into the heading, where the summaries already
carry it, and spell out "versus".
Tenet 6: drop "in plain language" from the body, where the heading already
says it, and replace "say what you will try next" with present tense.

Tenet 7: the body tests what the operator can observe, not comprehension,
so the heading now says "Confirm what they can see, in their words".
Tenet 8: replace the bare parenthetical with prose, matching Tenet 4.

Tenet 9 becomes "Teach only what tomorrow requires". "Day 2" was inherited
jargon that needed a glossary to parse, which is what Tenet 1 tells agents
to avoid. The noun "Day-2 leave-behind" becomes just "leave-behind", which
describes itself.

The four summary lists (contract, root README, AGENTS.md, and the stub
generated by init_cmd.py) now quote the tenet headings verbatim so they
cannot drift apart again.

Left as identifiers, not prose: the "day 2" alternate in the eval_engine
leave-behind regex (kept so existing transcripts still score), the
day2-leavebehind fixture directory, and the test that asserts on its name.

pytest 36 passed; bedside eval 9/9 match expect; bedside doctor OK.
New tenet 4: the operator can see what the agent is doing without asking.
Long work shows progress or an estimate, delegated work reports what each
subagent is doing, and status keeps one shape so it is read once. This
closes the gap tenet 3 opens: an agent told to prefer doing over
instructing can otherwise disappear for minutes at a time.

Inserting at 4 shifts tenets 4-9 to 5-10 and rubric IDs R4-R9 to R5-R10,
preserving the invariant that rule Rn scores tenet n. The ID shift was
applied mechanically to avoid transcription errors; tenet cross-references,
the anti-pattern table, and the surface mappings were updated by hand.

Eval coverage for the new tenet: R4 rule in eval_engine, one known-bad
fixture (silent-work) and one known-good (visible-progress), plus tests.
The concrete "about five seconds" threshold lives in surface/, not the
contract, since tenets counsel rather than prescribe.

Also retires the last "Day-1" jargon: the optional scorecard is now the
first-run scorecard, and gains an item for status visibility.

pytest 38 passed; bedside eval 11/11 match expect; bedside doctor OK.
Each session can improve the standard for the next one. When friction shows
up that better manners would have prevented, name it, and with the
operator's go-ahead file it upstream against tig/bedside and against the
project that vendored it.

The consent gate is part of the tenet, not a footnote. An issue is public
and carries the operator's name, so filing gets the same treatment as any
other outward-facing act. A tenet that told an agent to go be helpful in
public unasked would contradict the rest of the contract.

Eval covers only the half a transcript can actually show: filing with no
preceding ask fails R11, with a known-bad (filed-without-asking) and a
known-good (compound-with-consent) fixture plus tests. Whether the agent
noticed friction worth filing is judge-only in v0, and the rubric row says
so rather than implying regex coverage it does not have.

pytest 40 passed; bedside eval 13/13 match expect; bedside doctor OK.
The repo had been using "principles" and "tenets" interchangeably since the
README renamed its summary heading. Prose, identifiers, and the fixture
format now all say tenets.

Code: TENET_IDS, ScoreReport.tenet_pass, FixtureMeta.tenets, and
overall_from_tenets. meta.toml gains a `tenets` key and eval JSON gains a
`tenets` field.

Nothing downstream breaks. load_meta reads `tenets` and falls back to
`principles`, the JSON keeps emitting `principles` alongside `tenets`, and
PRINCIPLE_IDS / principle_pass / overall_from_principles remain as aliases.
Vendored consumers keep their own domain fixtures outside the vendor tree,
so a re-vendor would otherwise have silently orphaned every one of them.
A test pins the fallback.

Also fixes docs/adopting.md, which the earlier renumber skipped: it still
claimed rubric IDs stay R1-R9 and showed info=R9 in sample output that now
prints info=R10.

pytest 41 passed; bedside eval 13/13 match expect; bedside doctor OK.
silico is the only known consumer and has no domain fixtures outside its
vendored tree, so the compat shims protected nothing. Removed the
PRINCIPLE_IDS / principle_pass / overall_from_principles aliases, the
duplicate "principles" field in eval JSON, and the meta.toml fallback.

load_meta now rejects a meta.toml carrying the old key instead of ignoring
it. Silence would be worse than a break here: an unrecognized key leaves
focus empty, and empty focus means "score against all eleven tenets", which
quietly turns a fixture scoped to one tenet into one graded on every tenet.
That flips results without saying why. Exit 30 and a rename instruction is
the honest failure.

pytest 41 passed; bedside eval 13/13 match expect; bedside doctor OK.
Points readers at the source for what a tenet is and how to write one,
rather than assuming the reader already has that frame.
Swaps the Principal Engineer Tenets post for the one that actually defines
the term and carries the Tenets for Tenets criteria this revision was
written against.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9a394ff960

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/bedside/eval_engine.py Outdated
Comment on lines +311 to +312
asked_first = bool(
re.search(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Require the R11 ask to occur before filing

Because filed and asked_first are independent searches over all concatenated agent messages, a transcript such as “I have filed an issue. Do you want me to file it?” passes R11 even though the new rubric explicitly requires a preceding ask. Compare match positions or preserve message order so that only an ask before the filing action satisfies this check.

Useful? React with 👍 / 👎.

Comment thread src/bedside/eval_engine.py Outdated
Comment on lines +306 to +307
r"\b(i('ve| have)? (just )?(filed|opened|created|submitted)|filing|opening)\b"
r"[^.\n]{0,40}\b(issue|ticket|bug report|pr|pull request)\b",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Distinguish proposed filing from completed filing

The unqualified filing|opening alternatives classify hypothetical text such as “Filing an issue might help, but I will not do that without permission” as an issue already filed. Since that statement contains no recognized ask phrase, a compliant R11 transcript is scored as a violation and can fail bedside eval; restrict this detection to language asserting that the action occurred.

Useful? React with 👍 / 👎.

Comment thread src/bedside/eval_engine.py Outdated
Comment on lines +185 to +186
r"\bstill (running|working|going)\b|\bstatus\b|"
r"\b\d+ of \d+\b|\bso far\b|\bfinished \d+\b",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Require affirmative R4 status evidence

Matching the bare word status treats negated promises as visible progress. For example, “This will take a while; I will not provide status updates” sets both long_work and status_shown, so the transcript passes R4 despite explicitly announcing silent work. Match an actual estimate, progress value, or affirmative status update rather than the noun alone.

AGENTS.md reference: AGENTS.md:L27-L27

Useful? React with 👍 / 👎.

claude added 2 commits July 25, 2026 19:53
Migration guidance was actively harmful: the error told adopters the rubric
ids were unchanged while this same branch shifted R4-R9 to R5-R10. Following
it would rename the key and silently re-point every fixture at a different
tenet. It now prints the remapping.

Scoring holes:

- R11 accepted an ask anywhere in the transcript, so "I filed an issue.
  Want me to file another?" passed. The ask must now precede the filing.
- R11 matched "created a pull request" and "opening the issue tracker".
  Scoped to issues and tickets, with tracker/board/queue excluded.
- R4 accepted the bare words "status" and "estimate", so "Done. Final
  status: green." after silent work passed, as did "I cannot estimate how
  long." Quantitative signals only.
- R4 fired on "this will take a moment", failing well-mannered agents for
  two seconds of work.
- Unknown ids such as R12 sat unscored in the focus list and let a failing
  transcript report ok. load_meta rejects them, and overall_from_tenets
  now fails closed on an unscored focus id.

The R11 known-good fixture never filed anything, so the consent guard was
never exercised and the test would have passed with the check hard-wired
off. It now files after consent. Verified by mutation: forcing the ask to
never match, dropping the ordering check, and restoring bare "status" each
fail at least one test.

Version signal for the break: 0.1.2 to 0.2.0 plus CHANGELOG.md with the
id remapping table. __version__ was a second hardcoded source of truth and
had already drifted; a test now pins it to pyproject and requires a
matching CHANGELOG section.

pytest 50 passed; bedside eval 13/13 match expect; bedside doctor OK.
Drops the "(unreleased)" markers and moves the self-pin to v0.2.0 so the
pin matches the tag being cut from this merge, rather than pointing at the
v0.1.0 contract this branch has moved well past.
@tig tig changed the title Expand rubric from R1-R9 to R1-R11; rename "principles" to "tenets" Rework tenets: 9 to 11, renumber rubric to R1-R11, rename "principles" to "tenets" (v0.2.0) Jul 25, 2026
@tig
tig merged commit c4c0381 into main Jul 25, 2026
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.

2 participants