Skip to content

Instructions charge no retention tier and are bounded by their own cap (#446) - #450

Merged
tonite31 merged 7 commits into
mainfrom
fix/446-instruction-cap
Sep 4, 2026
Merged

Instructions charge no retention tier and are bounded by their own cap (#446)#450
tonite31 merged 7 commits into
mainfrom
fix/446-instruction-cap

Conversation

@tonite31

@tonite31 tonite31 commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Closes #446.

self instruction add was refused once the project's full tier reached
its 1,000-token cap — a cap that exists so self context fits its
3,000-token budget, a budget no instruction is in. instruction render
prints every instruction whole however far the store stands over the caps,
and views.ts keeps a full-exposure one out of the context projection
entirely. A record nothing ever elides was competing for the room set aside
for the records that are, and the --demote remedy pointed at goals and
conventions to free it.

The case table is amended first, in its own commit, and the code follows it.

Decisions

  1. An instruction charges no retention tier at any exposure. The
    predicate is the shipped one, labels.includes("instruction") && source === undefined. @superself/fold does not change and FOLD_VERSION stays
    at 1: tierCharacters keeps counting everything, and the CLI subtracts
    the instructions where it reads a cap's usage — so state add, state place, state confirm and every cap refusal report the tier without
    them.
  2. Instructions have a cap of their own. StoreConfig.instructionTokens,
    beside fullTokens / indexTokens, default 2,000, counted per render
    target (project / workspace) exactly as tierOf splits the tiers, over
    instruction-labelled records at any exposure. retentionCaps returns it
    as a third field.
  3. instruction add refuses only against the instruction cap, and never
    names --demote, a goal, an objective or a convention: instructions hold <n> of the <cap>-token <scope> instruction cap and this text adds <m> more — retire or supersede one with a shorter text, or raise instructionTokens in config.json<estimate note>. A --supersedes predecessor is credited
    before the comparison, so the remedy the refusal advertises works.
  4. --demote leaves instruction add — an unknown option the parser
    refuses. It shipped yesterday and is unreleased. A raw state add --label instruction --demote <id> is refused by name toward the room that does
    exist.
  5. state confirm of a proposed instruction checks the instruction cap,
    in requireTierRoom's wording family: confirming this would put the <scope> instructions over their cap (<n> of <cap> tokens held)<estimate note> — retire or supersede one …. state place on an instruction is
    refused by no cap at all: no tier holds it, and the instruction cap counts
    it at any exposure.
  6. A raw state add --label instruction is exempt from the tiers and
    checked against the instruction cap through the same predicate — the label
    is the mechanism, so the raw verb follows it, as Instruction records: rules and tool notes every session receives whole, outside the context render budget #440's table settled for
    the render.
  7. The listing's share line reads instructions hold <n> tokens — <n> of the <cap>-token <scope> instruction cap (<pct>%)<estimate note>, one line
    per occupied target, note on the last line only.
  8. self help placement states that instructions charge no retention
    tier and that instruction add is bounded by instructionTokens (default
    2,000) instead.

Cells

docs/maintainers/case-tables/440-instructions.md, amendment list
"review round: #446", 161 designed cells (the branch is rebased onto main,
which gained #445's G17).

  • Restated: A23, A24, A25, A28, B5–B9, B18, B19, C23, D12, E9, E18, F14,
    G1, G4.
  • New: A36 (the cap refusal), A37 (--demote unknown), A38 (the tier
    count excludes the instruction), A39 (raising the cap admits the add), A40
    (the raw verb lands at a full tier's cap), A41 (the raw verb judged by the
    instruction cap; a preset label beside it is not), A42 (--demote on a raw
    instruction add), B21 (one share per target), B22 (neither tier's refusal
    counts an instruction, at full or at index), E20 (promotion with both caps
    at their limits), E21 (every placement lands, naming no demotion), F16 (the
    confirm refusal), F17 (raising the cap lands the confirm).
  • Decisions added: §D-14 (no tier, its own cap), §D-15 (the two
    refusals), §D-16 (--demote and the placement gate). The "cap exemption"
    line under "what this table does not cover" is retired and replaced by what
    still is not covered: what a demoted instruction costs the context budget,
    and gating a --scope move against the instruction cap.

Gates

Run to completion locally: pnpm --filter superself typecheck, pnpm --filter superself build, node test/structure.mjs (function ceiling 30,
dead exports 0), and node --test on instruction.test.mjs (65),
instruction-context.test.mjs (31), instruction-place.test.mjs (21),
instruction-render.test.mjs (27), docs, guide, golden, skill,
place, preset-caps, context, state, structure, handoff, and the
eleven other suites that assert cap wording (agent-consent, derivation,
render-gate-documents, skill-context, scope-move, runbook,
workspace-scope, confirm-owner, tokens, workspace-direction,
search-live) — all green. The golden fixture is regenerated; its only
change is the root usage listing's instruction add line.

A self-adversarial pass reverted each half of the change in turn: dropping
the tier subtraction fails ten cells (A23, A28, A38, A41, B18, B22, D12, E9,
E18, F14) and dropping the instruction-cap gate fails fourteen (A23–A25, A28,
A36, A38–A42, C23, F14, F16, F17). Two restated cells that passed under both
rules — A25 and A41 — were strengthened until they did not.

CI runs the whole suite; it is the referee.

🤖 Generated with Claude Code


Review round 1

One blocking finding, five should, three optional; all nine applied.

1 (blocking) — the credit side. A tier that charges an instruction nothing
was still crediting one back. holdsSeat read a retention tier through
occupiesTier alone, so a full-exposure instruction held a seat the tier's own
usage never charges it for: with a 50-token record, a 23-token instruction and
fullTokens: 60, the 30-token state add that a bare add is refused went
through with --demote <instruction-id>, the tier read 80 of 60 afterwards,
and the instruction had left the manual. --supersedes <instruction-id> bought
the same room through vacatedTokens. Three edits: the tier branch of
holdsSeat excludes an instruction, requireDemotionsEnough sums what a
demotion frees through holdsSeat rather than through raw characters, and
requireDemotableSeat refuses an instruction target by name — before its scope
and exposure clauses, because a project-scoped full instruction passes both and
frees nothing: --demote <id> is an instruction — it charges no retention tier, so demoting it frees no room; name a goal, decision, convention or index record with --demote. New cells A43 (the --demote refusal) and A44 (the
--supersedes credit gone: the refusal states the tier's own 50 of 60).

2 (should) — share line vs cap. shareLines counted the rendered set while
the cap counts every exposure, so a store holding one demoted instruction
printed a share smaller than the number its own cap refusal states, and a store
whose instructions were all demoted printed "no instructions recorded" over a
manual it was still being refused adds against. The share counts through
chargesInstructionCap — the predicate the cap itself is summed with — and
prints wherever the cap is charged. §D-6 and the comment at instruction.ts
are amended; new cell B23 holds both halves.

3 (should) — two stale "does not cover" bullets. The legacy-label bullet
said such records "still charge the same tier"; they charge instructionTokens
now, and a store that used the label freely may already stand over the 2,000
default — reproduced at 2240 of 2000, rendering whole and refusing instruction
adds alone. The bullet describing --demote <id> as the remedy for an add past
the full tier described the retired rule and cited A23/A25 as refusals they no
longer are; deleted.

4 (should) — F17's row. It claimed a --supersedes predecessor is credited
at confirm time. The confirm judges the unit's own net movement and credits no
such link (a 24-token successor superseding a 23-token live instruction is
refused at 23 of 30), and the cell never asserted it. The clause is deleted
and the credit is stated in §D-15, on the add path, where it is true. No code
change.

5 (should) — docs/reference/cli.md. The caps bullet gains
instructionTokens (default 2,000, per render target) with its own remedy
sentence, and the --demote <id> clause is scoped to the two retention tiers.

6 (should) — labelsAreInstruction. It tested membership with in, which
walks Object.prototype, so --label constructor — or toString, or
__proto__ — read as a preset source at the gate while sourceOf folded the
record with source === undefined: one record, two answers about which cap it
charges. Object.hasOwn is the test now, the local SOURCE_LABELS and its
build-time Record<EntitySource, true> guard both kept. New cell A45.

7, 8, 9 (optional). B19 asserts the cap its two share lines name, so it
can no longer pass against the pre-#446 build. remembered is inlined into
usageReader, its one caller. A24, E21 and F16 read
events().length across their refusals, as A36 and A42 do.

Table: groups A 45 and B 23, 165 designed cells, and the "review round:
#446" list gains a round-1 sub-list naming each cell and why.

Gates, each to completion on the dev VM: typecheck, build,
node test/structure.mjs (ceiling 30, dead exports 0), and node --test on
instruction (69), instruction-render (27), instruction-place (21),
instruction-context (31), place (16), preset-caps (29), context (15),
docs (13), guide (14), golden (3), skill (44), state (8) — all green.

Self-adversarial pass: reverting the holdsSeat tier exclusion alone fails
A44; reverting the requireDemotableSeat clause alone fails A43 (the
two halves of the blocking finding guard one cell each, rather than 1(a)
guarding both); reverting the share-line predicate fails B23. All three
restored, all cells green again.


Review round 2

No blocking finding, three should, three optional; all six applied.

1 (should) — --demote <proposed instruction> misdirected. The proposed
clause in requireDemotable fired before requireDemotableSeat's instruction
clause, so naming a proposed instruction with --demote took --demote <id> is still proposed — it holds no place in the full tier until confirmed, a
remedy that only led to A43's refusal once the caller confirmed it. The
instruction clause is hoisted into requireDemotable, above the proposed and
!isLive clauses: kind is judged before lifecycle, and it now precedes every
clause but the one naming the record being placed. §D-16 and A43's row are
amended to say so; new cell A46 drives --demote <a proposed instruction>
on a full add at the cap and asserts the instruction wording, nothing
recorded.

2 (should) — cli.md's instructionTokens bullet was unpinned. Nothing
in docs.test.mjs checked the bullet named the cap, its 2,000 default, "per
render target", or a remedy matching the built refusal (INSTRUCTION_REMEDY
in state.ts). New cell G18 pins all four. While there, the bullet's
--demote sentence was imprecise: it read both paths as "refused by name,"
but instruction add declares no such flag at all — the parser refuses it as
unknown option '--demote' — and only a raw state add --label instruction --demote <id> is refused by name. The bullet now says both, and G18 is added
to a new "round 2" sub-list beside the round-1 one.

3 (should) — B12 delegated a proof B23 didn't carry. B12's row credited
B23 with proving the token total holds a demoted instruction and excludes a
proposal, a superseded and a retracted one, but B23 seeded only the full and
the demoted instruction. B23 now also seeds one proposed, one superseded (via
its predecessor) and one retracted instruction, and asserts the share equals
confirmed + demoted alone and equals the next refusal's held number — the
same 51 either way. B12's row is amended to point at B23 truthfully.

4 (optional) — the --artifact orphan. Pre-existing and not moved:
state add --label instruction --artifact <path> past the instruction cap
still registers the artifact and then refuses the record, because
resolveArtifactRef runs before the cap gate in entityAdd. The comment
above the call was wrong about the ordering ("after every other check"); it
now says the cap gate follows it. Added to the case table's "does not cover"
list with one sentence.

5 (optional) — an all-demoted listing printed only the share line. When
every charged instruction is demoted, sections is empty and listRows
printed nothing beside the share — a reader could read the bare number as
"nothing is recorded." instructionList now adds one line beside the share
in that case: every instruction is demoted — self context carries them as index lines; instruction render prints none. listRows is also guarded so
Math.max(...[]) is never evaluated on the empty path. §D-6 and B23 (which
already seeded an all-demoted store) are amended to assert it.

6 (optional) — one rule spelled twice. holdsSeat's tier branch excludes
an instruction with !isInstruction, and heldCharacters subtracts
instructionTierCharacters — the same rule, kept twice because one runs
before a demotion's credit is summed and the other after the fold's own sum.
A comment on instructionTierCharacters now names holdsSeat as its
complement. New cell A47 pins them equal with two instructions and two
ordinary records seeded (not one of each), driven through a tier refusal's
numbers as A28 and A38 are: the held count is the sum of entityCharacters
over the two ordinary records alone.

Bookkeeping. A24's and E21's rows are reworded to carry the
events().length claim the round-1 sub-list credited them with — A24's own
outcome is a landing, so the claim now names F16, the confirm that actually
refuses. A44's row is reworded the same way.

Table: groups A 47 (A46, A47 new) and G 18 (G18 new), 168 designed cells,
and a new "round 2" sub-list names A46, A47, G18, B23, B12, A24 and E21 with
one sentence each.

Gates, each to completion on the dev VM: typecheck, build,
node test/structure.mjs (ceiling 30, dead exports 0), and node --test on
instruction (71, +2), instruction-context (31), instruction-place (21),
instruction-render (27), place (16), preset-caps (29), docs (14, +1),
guide (14), golden (3), skill (44) — all green.

Self-adversarial pass: reverting the requireDemotable hoist (moving the
instruction clause back into requireDemotableSeat, after the proposed and
!isLive clauses) fails A46 alone; every other cell in the file still
passes. Restored, and the suite is green again.

inflike-rayim and others added 4 commits September 4, 2026 14:10
…and has a cap of its own

instruction is recorded at full exposure and charges `fullTokens`, the cap
that exists so `self context` fits its 3,000-token budget — a budget no
instruction is in. A ~190-token procedure was refused three times at
930/1000, the `--demote` remedy pointed at goals and conventions, and
`--demote` refused workspace-scoped records.

The table is the contract, so the decision is made here before any code.
Three rulings: §D-14, an instruction charges no retention tier at any
exposure and is bounded by `StoreConfig.instructionTokens` (default 2,000)
counted per render target; §D-15, the two refusals that cap raises, neither
of which names `--demote`, a goal, an objective or a convention; §D-16,
`--demote` leaves `instruction add` and a placement of an instruction is
refused by no cap.

Restated against them: A23, A24, A25, A28, B5–B9, B18, B19, C23, D12, E9,
E18, F14, G1, G4. New: A36–A42, B21, B22, E20, E21, F16, F17 — 161 designed
cells. The "cap exemption" line under "what this table does not cover" is
retired and replaced by the two things that are still not covered: what a
demoted instruction costs the context budget, and gating a `--scope` move
against the instruction cap.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: rayim <rayim@inflike.com>
…ts own

The retention tiers exist so `self context` fits its 3,000-token budget. An
instruction is in no part of that projection — `views.ts` keeps a
full-exposure one out and `instruction render` prints every one of them whole
however far the store stands over the caps — and yet it was recorded at full
exposure and charged `fullTokens` like a goal. A record nothing ever elides
was competing for the room set aside for records that are, and the `--demote`
remedy pointed at goals and conventions to free it (#446).

`@superself/fold` does not change and `FOLD_VERSION` stays at 1:
`tierCharacters` keeps counting every full-exposure record, and the CLI
subtracts the instructions where it reads a cap's usage, so `state add`,
`state place`, `state confirm` and every cap refusal report a tier without
them. The predicate is the shipped one, read off the folded entity where
there is one and off the composed payload's labels where there is not — the
label is the mechanism, so a raw `state add --label instruction` follows the
rule exactly as the render already does.

In its place: `StoreConfig.instructionTokens`, default 2,000, counted per
render target over instruction-labelled records at any exposure. `CappedTier`
carries it as a third kind so one path still reads, compares and refuses
every cap. `--demote` leaves `instruction add`, whose refusal now names the
room that exists — a shorter successor, or a larger cap — and never a goal,
an objective or a convention. A placement of an instruction is refused by no
cap at all.

Cells: A23, A24, A25, A28, B5–B9, B18, B19, C23, D12, E9, E18, F14, G4
restated; A36–A42, B21, B22, E20, E21, F16, F17 new.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: rayim <rayim@inflike.com>
…ction add`

`docs.test.mjs`'s G1 holds the cli.md row byte-identical to the contract's
own syntax line, so the flag leaving the verb leaves both. The golden fixture
is regenerated: the one line that moved is the root usage listing's.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: rayim <rayim@inflike.com>
…y replace

The self-adversarial pass over #446's cells found A25 and A41 passing under
the old rule as well as the new one. A25 asserted that the add names no
demotion, in a store whose full tier was nowhere near its cap — so it proved
nothing about the tier. It now fills the tier to `fullTokens` with the goal
and the convention the old refusal advertised demoting: the state #446
reported, and the add lands. A41 asserted that a `--label convention` add
lands, which every cap admits; it now seeds a full tier the convention
overflows, so the two caps are told apart by the one label that decides them.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: rayim <rayim@inflike.com>
@tonite31
tonite31 force-pushed the fix/446-instruction-cap branch from d9f7ae6 to 33ed86d Compare September 4, 2026 14:12
inflike-rayim and others added 3 commits September 4, 2026 14:47
…e cap holds

Three defects the first review round of #446 found, all on the credit side of
the ruling this branch makes: a tier that charges an instruction nothing was
still crediting one back.

`holdsSeat` read a retention tier through `occupiesTier` alone, so a
full-exposure instruction held a seat the tier's own usage never charges it
for. `--demote <instruction-id>` on an ordinary full add therefore bought room
nothing was paying for — with a 50-token record, a 23-token instruction and
`fullTokens: 60` the 30-token add a bare `state add` was refused went through,
the tier read 80 of 60 afterwards, and the instruction left the manual for
nothing — and `--supersedes <instruction-id>` did the same through
`vacatedTokens`. The tier branch now excludes an instruction,
`requireDemotionsEnough` sums what a demotion frees through `holdsSeat` rather
than through raw characters, and `requireDemotableSeat` refuses an instruction
target by name, before its scope and exposure clauses: a project-scoped full
instruction passes both and frees nothing.

`shareLines` counted the rendered set while the cap counts every exposure, so a
store holding one demoted instruction printed a share smaller than the number
its own cap refusal states, and a store whose instructions were all demoted
printed "no instructions recorded" over a manual it was still being refused
adds against. The share counts through `chargesInstructionCap` — the predicate
the cap itself is summed with — and prints wherever the cap is charged.

`labelsAreInstruction` tested membership with `in`, which walks
`Object.prototype`, so `--label constructor` read as a preset source at the gate
while `sourceOf` folded the record with `source === undefined`: one record, two
answers about which cap it charges. `Object.hasOwn` is the test now.

Beside them: `remembered` is inlined into its one caller, B19 asserts the cap
its share lines name so it can no longer pass against the pre-#446 build, and
A24, E21 and F16 read the log across their refusals as A36 and A42 do.

New cells A43, A44, A45 and B23; A24, B19, E21 and F16 amended.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: rayim <rayim@inflike.com>
…d cap

The design half of review round 1 of #446.

§D-14 gains the rule the code was missing: the subtraction runs both ways, so a
tier that charges an instruction nothing can be credited nothing for one either.
§D-15 scopes the `--supersedes` credit to the add path, where it is true — the
confirm judges the unit's own net movement and credits no such link — and F17's
row loses the clause that claimed it at confirm time, which that cell never
asserted. §D-16 gains the wording `--demote` refuses an instruction target with.
§D-6 says the share is counted through the cap's own predicate and prints
wherever the cap is charged.

Two "does not cover" bullets were stale. The legacy-label bullet said such
records "still charge the same tier"; they charge `instructionTokens` now, and
a store that used the label freely may already stand over the 2,000 default —
reproduced at 2240 of 2000, rendering whole and refusing instruction adds
alone. The bullet describing `--demote <id>` as the remedy for an instruction
add past the full tier described a rule this branch retired, and cited A23 and
A25 as refusals they no longer are; it is deleted.

`docs/reference/cli.md` gains `instructionTokens` beside the two retention
caps, with its own remedy sentence, and the `--demote <id>` clause is scoped to
the tiers it frees room in.

Group counts: A 45, B 23, 165 designed cells.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: rayim <rayim@inflike.com>
Round 2 of #450's review: --demote naming a proposed instruction now takes
the instruction refusal instead of the proposed one, holdsSeat and
heldCharacters are pinned equal with more than one record of each kind,
cli.md's instructionTokens bullet is pinned against the built refusal and
tells the parser and by-name --demote paths apart, B23 seeds every lifecycle
state B12 claims it does, and a listing whose instructions are all demoted
says so beside the share instead of printing only the number.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: rayim <rayim@inflike.com>
@tonite31
tonite31 merged commit 5e4afce into main Sep 4, 2026
5 checks passed
@tonite31
tonite31 deleted the fix/446-instruction-cap branch September 4, 2026 15:30
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.

Instructions are refused at the full-tier cap although they never enter the context budget

2 participants