| A rule applies only when every populated dimension matchesC09 | five dimensions — file_patterns, operations, code_patterns, languages, project_attributes; a rule with at least one populated dimension applies iff each populated one is satisfied by the change; a rule with none matches nothing | shipped |
| Globs, overlaps and substrings — nothing fuzzierC68 | file_patterns are path globs (**/, a bare **, *, ?; \ and / both read as /); operations, languages and project_attributes need one value in common; code_patterns are substrings of task_context — all case-insensitive; 32 entries per dimension, 200 characters each, 8,000 serialized | shipped |
| Only active rules are candidates; the answer says how much it did not showC69the dashboard replay allows a limit up to 200 | the project’s active rules, most-retrieved first (at most 1,000), matched in memory; returned = matches up to limit, plus candidate_count and suppressed_count; limit defaults to 50 and must be 1–100 over REST and MCP — out of range is refused, not clamped | shipped |
| Every returned rule counts the retrievalC10a telemetry touch — deliberately not audited, like pings and usage reports | retrieval_count + 1 and last_retrieved_at stamped in one bulk UPDATE, reflected in the response; the counter ranks the next call’s candidates | shipped |
| A person can replay the exact retrievalC11a replay is a retrieval: it bumps retrieval_count like an agent’s call would | /applicable-rules runs the same QueryApplicableRulesAsync an agent’s call runs, with the same three counts | shipped |
| A rule derives only from an enforced lessonC12the gate is structural, the human is convention — any write_session_state credential can enforce a lesson; mis-filed lessons and rules can be hard-deleted | derive_rule reads the lesson under an update lock inside the insert transaction and refuses one that is not enforced; enforced itself needs a written prevention mechanism (a database constraint); lesson and rule status move forward only | shipped |
| What a derive copiesC72 | the lesson’s prevention mechanism becomes the body, its applicability tags seed project_attributes, slug and title default to the lesson’s, source_lesson_id links back, the project is inherited; a slug already used in the project is a conflict | shipped |
| active → archived, never back; id, slug and source lesson fixed at insertC71 | tg_build_rules_status_monotonic rejects any UPDATE that lowers status_rank or touches workspace_id, rule_id, rule_slug, source_lesson_id; there is no un-archive surface — archive is the only status write, and an archive of an archived rule is a no-op that writes no audit row | shipped |
| Update replaces the trigger surface only when told toC71 | update_rule edits title, body and triggers under an update lock; the surface is replaced as a whole and only with replace_triggers (MCP) or a present triggers object (REST); an update that changes nothing writes no audit row | shipped |
| Enrichment is optional and off by defaultC70until it runs, a rule matches on the triggers a person wrote or a derive seeded — with none, it matches nothing | every rule lands pending; the enrichment sweep ships disabled and the LLM client is inert until your own Anthropic key is configured — without a provider enrich_rule answers deferred and the row is untouched; a usable answer becomes enriched, an unusable one parks the rule failed with the reason, and only reenrich_rule (failed → pending) requeues it | default-off |
| 8 events on the audit chainC73 | build_rule.created, build_rule.derived, build_rule.updated, build_rule.archived, build_rule.reenrich_requested, build_rule.enriched, build_rule.enrichment_failed, build_rule.deleted — each written into the workspace’s tamper-evident SHA-256 chain in the same transaction as the row; no-op updates and archives write none | shipped |
| Writes need one scope; reads need only authenticationC74 | the seven writes require write_session_state (operational tier) over REST and MCP alike; the three reads — list, get, the retrieval — require an authenticated caller in the workspace | shipped |
| REST and MCP return the same bytesC05 | one serializer for the rule aggregate — rule, summary, list page, applicable wrapper with its counts — pinned by byte-parity tests covering all ten operations | shipped |