Docs/Reference

Reference

Writes are judged by the whole file they leave

Every gate on a write, an edit, a patch or a notebook edit judges the file as the write leaves it, not the text the write carries. Tama rebuilds that file once, through the replay in check_numeric_literals_payload::path_texts, and hands each gate the whole result:

Every gate on a write, an edit, a patch or a notebook edit judges the file as the write leaves it, not the text the write carries. Tama rebuilds that file once, through the replay in check_numeric_literals_payload::path_texts, and hands each gate the whole result:

  • a whole-file write: the content it writes;
  • a string edit (old_string/new_string, several edits in one call): the file on disk with each edit applied in order;
  • a hashline section: the file on disk with each anchored operation applied, an uncommitted change another session made to the file included;
  • an apply_patch envelope: each file it adds, updates or moves, as its hunks leave it;
  • a notebook cell edit: the whole notebook with the cell replaced, inserted or deleted.

So a violation the file already holds is refused on the next write to that file, whoever wrote it, and text the write removes is not judged as written. A write that removes the violation passes. No gate counts out what the file held before the write, check-numeric-literals included.

A write that leaves several files, a patch envelope or a hashline edit of several sections, has each file judged on its own under its own path by pre-write-edit, block-internal-names and block-one-off-commands: a refusal names the file that holds the violation and the line in that file, and a file in a vendored or generated tree (node_modules, .git/, .next, …) is judged as one whichever file the write names first. A write that only takes text away and adds none is not judged by pre-write-edit. The journey is each_file_a_patch_leaves_is_judged_under_its_own_path in tests/pre-write-edit/held_lines.rs.

block-oversized-files counts the lines of that same rebuilt file, every file a write leaves, so a hashline split that cuts lines and inserts module declarations is counted after its cut, whatever fragment the editor also sends. A write whose file cannot be rebuilt is refused with the cause. The journey is tests/tool-payload/targets.rs.

#Structural rewrites are refused

A structural rewrite written to the harness's xd://ast_edit device carries only its patterns and the files they apply to; the harness's ast-grep engine stages the rewrite and a later write to xd://resolve applies it, so neither call carries the files as they will read. Every gate that rebuilds a write refuses it, naming the targets:

pre-write-edit: BLOCKED: the file this write leaves cannot be rebuilt to judge it: cannot rebuild the files the xd://ast_edit rewrite of /repo/held.js leaves: …; make the change with edit or write, whose resulting file is rebuilt and judged

Make the change with edit or write; the journey is tests/pre-write-edit/held_lines.rs.

#What a refusal says

A refusal names the file and the line in the whole file where each violation stands, as line N: <the line>, numbered from one as an editor numbers lines. The number is the line's place in the file the write leaves, not its place in the patch or the cell. Examples:

BLOCKED: legacy activation bypass detected in /repo/stage.sh: …
line 1: python -m …

block-direct-lsi-api: BLOCKED: … target: /repo/fill.py
  matched: project registry write/read endpoint (line 1: requests.post(…))

block-unapproved-tests: BLOCKED: /repo/src/lib.rs (test markers at line 5: #[test]) is test code the operator has not approved. …

A write the replay cannot rebuild is refused, never judged by the fragment it carries:

… the file this write leaves cannot be rebuilt to judge it: <cause>

The cause names the file and what failed: the file does not exist, an old_string was not found, a patch hunk (the hunk expecting `…`) does not match the file, a notebook cell is not there. Fix the write so it applies to the file as it is; there is no setting that lets an unrebuildable write through.

#The gates

GateWhat it names
pre-write-editevery content rule, and the second-program check, on the rebuilt file
block-fallbacks, block-silent-waits, block-identity-literals, block-keyword-literals, block-internal-namesthe construct and its line
check-numeric-literalseach literal the file holds and the line it stands on in the file the write leaves
check-legacy-activation-bypasseach marker and every line holding it, per file
block-direct-lsi-api, block-overleaf-apieach forbidden call and the line of every match, per file
check-raw-api-callsthe raw site call and its line
block-openai-api-keythe credential reference and the lines holding it
block-credential-copieseach copy of a credential store, the store and the statement, per file (credential stores are never copied)
check-reward-hackingfor a hook file below ~/.shared-hooks, each dropped protection or narrowed trigger regex, and the lines of each guard or bypass the write introduces
check-humanized-actionsthe model reads each in-scope file whole, every line prefixed with its number in the file, and names the lines in its sentence
block-unapproved-teststhe file, and the line of each test marker it holds

pre-write-edit's funding API rule refuses a client for LSI, PARP or NCBR (a CDP session, a session fetch, a collection or scalar save, a saved-values or field-list route) wherever the file holds it, and an LSI endpoint path only when the same file also sends a request of its own (fetch(, a .request client call, a request context, XMLHttpRequest). A file that names the path only to recognise the answer the page received after a UI action, as a trajectory waiting on its own save does, is admitted. The journey cargo test --manifest-path rust/Cargo.toml -p tama-cli --test content_addresses writes both forms through the built hook.

Its time-limit rule refuses the calls that end work early and the limit word wherever the running part of a file spells it: a code file without its comments and without the names its function definitions give (read from the file's syntax tree, so a test named for a limit's absence passes while every call of it is still judged), an HTML page's script elements, event-handler attribute values (onload=, onclick=, every on…) and javascript: URLs, an MDX page's paragraphs JavaScript reads as statements (its import and export block), {expressions} and JSX tags, its fenced code blocks and inline code left out as shown rather than run, and every other configuration or data file whole; a Markdown, reStructuredText or plain-text page runs nothing and is not judged, so a page can state that a request has no limit. A code file whose syntax cannot be read, or an MDX page the JavaScript grammar cannot be loaded or yields no tree for, is refused with the cause, and tama violations find --time-limits reports it as an error of the scan. The word for a due date names a stored date as often as a limit: a paper's submission date, a grant's due day, a sentence saying a wait has none. That word is read as a limit only on a line that also bounds a clock (the current instant with a span added, a monotonic clock, a span of time), so a field holding a date or prose about one is admitted. The journey cargo test --manifest-path rust/Cargo.toml -p tama-cli --test pre_write_edit_time_limits writes a stored date, the library off switches, a finite interval, a bounded clock, a function named for a limit's absence and a call of it, a prose page, an HTML page with and without a limiting script, an HTML handler attribute and a javascript: link that set one, and MDX pages whose export or expression sets one or whose prose and fenced example only name one, through the built hook.

#Where it comes from

Source: rust/crates/tama-hook-tools/src/ports/check_numeric_literals_payload/ (the replay, line_at and lines_holding) and each gate's own module. The journey cargo test --manifest-path rust/Cargo.toml -p tama-cli --test hooks_whole_file runs the built tama hook on real files: a patch beside a bypass the file already holds is refused naming line 1:, a patch the file does not hold is refused with the hunk it expected, and an edit of a hook file that introduces an always-false guard is refused naming line 3:. The suites lsi_api_edits, openai_api_key_writes, unapproved_tests_whole_file and numeric_literals_operations (the patch and notebook replay) assert the same per gate.