import type { TreeKind } from './effective-tree'; /** * The K dimension as a CLASSIFICATION carries — one concrete tree, never the `pw` union. * * `p` and `w` are the same PROJECT and every rule-scoped guard treats them alike; the doc writes the * pair as `pw` in the row's MATCHER (below), which is a different vocabulary on purpose. */ export type L1Kind = 'f' | 'm' | 'o' | 'p' | 'w'; /** The K value a ROW matches on. `pw` matches both `p` and `w`; `-` is the wildcard. */ export type L1KindMatch = 'f' | 'm' | 'o' | 'w' | 'pw' | '-'; /** R and G are yes/no, written `y`/`n` in the doc, with `-` for "does not matter". */ export type L1Flag = 'y' | 'n' | '-'; /** * V is the same one boolean wearing the doc's own letters: `n` the webpieces versions do NOT agree * between this worktree and the main tree, `y` they do. * * This dimension used to be A (`c` coordinator / `s` subagent). It was replaced rather than removed * because agent identity was measured untrustworthy as a proxy for "which tree am I in" — a * worktree-isolated agent auto-reaped at a turn boundary silently resumes on the primary clone. A * version read off the PATH being acted on cannot lie in that way. */ export type L1VersionSync = 'y' | 'n' | '-'; /** What L1 does with a row. The labels are the doc's own action codebook (see GUARD_MATRIX.md). */ export type L1ActionKind = 'exempt' | 'down' | 'block'; /** * WHICH structural block a blocking row dispatches to. This is the field that makes the array * load-bearing rather than decorative: runner.l1LocationBlock looks the row up and switches on it, * so deleting a row from the array removes the block. */ export type L1BlockId = 'trinary-version-skew' | 'force-to-root' | 'missing-directory'; /** * The row number for L1's PRE-STAGE — `misplacedCdBlock`, which decides from command TEXT before a * tree has been resolved, and therefore cannot be classified over the five dimensions rows 1-6 use * (asking L1_ROWS to classify it would need the very resolution its answer determines). * * ZERO rather than a seventh row, deliberately. It has to appear in the table — an L1 block the * generated doc did not describe is precisely the drift the table exists to prevent, and it was * carrying a `KNOWN GAP` comment saying so. But numbering it 7 would assert it sits in the same * first-match scan as the others, which is the one thing that is not true about it. Row 0 says * "decided before the scan" in the number itself. `renderL1Doc()` PRINTS this row above the six, so * `row=0` in the L1 log joins to a line the reader can actually find. */ export declare const L1_PRESTAGE_ROW = "0"; /** * One point in the five-dimensional space L1 classifies over. Data-only → a class, per CLAUDE.md. * * The dimensions are exactly the doc's legend: K (tree kind of the resolved target), V (webpieces versions in sync or * subagent), R (provably read-only inspection), G (invokes git/gh), P (root or subdirectory). */ export declare class L1Classification { readonly kind: L1Kind; readonly versionsSkewed: boolean; readonly readOnly: boolean; readonly git: boolean; readonly atRoot: boolean; constructor(kind: L1Kind, versionsSkewed: boolean, readOnly: boolean, git: boolean, atRoot: boolean); /** * The classification the RUNNER enforces on, built from the resolved tree and the caller. * * `'outside'` maps to `p`, and that is not a typo. TreeKind `'outside'` is produced by * effective-tree.ts (git has no answer for the directory) and consumed NOWHERE, so a command in no git repo is * judged against the governed repo exactly as if it stood in it. Row 2 (`o` → L2) describes what * SHOULD happen and is deliberately unreachable from here until the "Not done" fix in * guards/L1-location.md lands — exempting `o` alone opens a `cd /tmp &&` bypass of every L2 guard, * so the two ship together or neither does. Mapping it to `p` here is what preserves today's * behaviour (a `git` command from /tmp is still force-to-root blocked); it is not an endorsement. */ static forEnforcement(treeKind: TreeKind, versionsSkewed: boolean, readOnly: boolean, git: boolean, atRoot: boolean): L1Classification; } /** The `act` cell of a row: the doc's literal label, plus the machine-readable kind behind it. */ export declare class L1Action { readonly label: string; readonly kind: L1ActionKind; constructor(label: string, kind: L1ActionKind); } export declare const ACT_EXEMPT: L1Action; export declare const ACT_DOWN: L1Action; export declare const ACT_BLOCK: L1Action; /** * The CURE a blocking row prescribes. * * `runnable` is the axis that matters to the tests: a cure that is a command must, once applied, * actually stop the row from matching (cure reachability). Row 3's cure is an INSTRUCTION — "spawn a * subagent bound to the worktree" — which no allowlist can accept and no reclassification can model, * so it declares `runnable: false` and is asserted only on the deny text. */ export declare class L1Cure { /** How the doc's `why` column spells it. */ readonly summary: string; /** A substring that MUST appear in the deny text the guard emits for this row. */ readonly denyMention: string; readonly runnable: boolean; constructor( /** How the doc's `why` column spells it. */ summary: string, /** A substring that MUST appear in the deny text the guard emits for this row. */ denyMention: string, runnable: boolean); } /** * One row of the "L1 use cases" table: what you SEE, the state it puts you in, the verdict, the fix. * * The four text fields are rendered VERBATIM into the doc. `classification` is the same case expressed * in the matrix's own vocabulary so the tests can run it through the matcher — it is test/enforcement * data, never rendered, which is why a use case that exercises the FILTER or the L0 allowlist (neither * of which is a row) can carry `null` there. */ export declare class L1UseCase { readonly num: number; readonly symptom: string; readonly state: string; readonly verdict: string; readonly fix: string; readonly classification: L1Classification | null; constructor(num: number, symptom: string, state: string, verdict: string, fix: string, classification?: L1Classification | null); } /** One row of L1's decision table. Data-only → a class, per CLAUDE.md. */ export declare class L1Row { readonly num: number; readonly k: L1KindMatch; readonly a: L1VersionSync; readonly r: L1Flag; readonly g: L1Flag; readonly p: 'root' | 'sub' | '-'; readonly action: L1Action; /** The `why` cell, verbatim. */ readonly why: string; readonly cure: L1Cure | null; readonly blockId: L1BlockId | null; readonly useCases: readonly L1UseCase[]; constructor(num: number, k: L1KindMatch, a: L1VersionSync, r: L1Flag, g: L1Flag, p: 'root' | 'sub' | '-', action: L1Action, /** The `why` cell, verbatim. */ why: string, cure: L1Cure | null, blockId: L1BlockId | null, useCases: readonly L1UseCase[]); matches(c: L1Classification): boolean; private kindMatches; } /** * THE seven L1 rows, in first-match-wins order. * * Rows 3, 5 and 7 are the structural blocks and they run as ONE step (runner.l1LocationBlock) so they * can never be reordered by accident. Every other row is a hand-down or an exemption, i.e. "L1 has no * objection" — which is why only those three carry a blockId. * * Row 7 (`m`, the vanished directory) sits LAST only because row numbers are stable across releases — * they are printed in the doc and logged as `row=`, so renumbering rows 1-6 to slot it in front would * silently invalidate every existing reference. Position costs nothing here: `m` is matched by no other * row, so first-match reaches it wherever it sits. */ export declare const L1_ROWS: readonly L1Row[]; /** * The use cases that exercise something that is NOT a row: the excludePaths FILTER (2, 3, 4, 20) and the * L0 allowlist that runs ahead of L1 (15). * * They are use cases of L1 all the same — "exempt" is what emerges when the filter empties the rule * list, and case 15 is the invariant that a cure stays reachable from every tree — so they stay in the * doc's one numbered table. They carry no classification because no row classifies them. */ export declare const L1_UNROWED_USE_CASES: readonly L1UseCase[]; /** Every use case, in the doc's numbering — the order the table is rendered and read in. */ export declare function allL1UseCases(): readonly L1UseCase[]; /** * FIRST MATCH WINS — the one lookup the guard and the tests share. * * Never null: rows 1, 2 and 4/5/6 between them cover every kind, and rows 4/5/6 partition G × P, so a * classification that matched nothing would be a hole in the matrix. The totality test asserts exactly * that, which is why this returns L1Row rather than L1Row | null. */ export declare function firstMatchingL1Row(c: L1Classification): L1Row;