feat(f1): /pos:audit-session — read-only advisory skill comparing policy.yaml vs .claude/logs/#25
Conversation
…it-session Fase 0 kickoff + Fase 1 RED-first per CLAUDE.md regla #3 and .claude/rules/tests.md. Plan ratificado por usuario: decisiones A1.a..A6.a + 3 ajustes obligatorios. Scope: skill /pos:audit-session — read-only advisory main-strict que compara 3 superficies de policy.yaml contra .claude/logs/ reales: 1. policy.yaml.skills_allowed vs skills.jsonl invocations. 2. policy.yaml.lifecycle.*.hooks_required vs logs por hook (existencia + nonempty del archivo log esperado). 3. policy.yaml.audit.required_logs vs existencia/edad/no-vacio. RED state confirmado: 16 failures esperados. - 10 parametrizados [audit-session] en TestStructure / TestFrontmatter / TestBody. No existe .claude/skills/audit-session/SKILL.md. - 5 TestAuditSessionBehavior: * test_body_declares_three_audit_surfaces * test_body_declares_advisory_only * test_body_declares_main_strict_no_delegation * test_body_declares_30day_review_window * test_body_declares_prefix_normalization_assumption - 1 test_real_skills_allowed_populated_by_f1. policy.yaml todavia declara 13; ALLOWED_SKILLS ya crecio a 14. Tests behavior siguen el patron de TestPatternAuditBehavior E3a — la referencia mas cercana: read-only advisory main-strict. Ajuste 3 del usuario aplicado: el test del 30-day window valida DECLARACION del body, no ejecucion de date math. Renames: - test_real_skills_allowed_populated_by_e3b -> _by_f1. Tupla 13 -> 14 via ALLOWED_SKILLS shared. - test_all_thirteen_e1_e3b_skills_end_to_end -> test_all_fourteen_e1_e3b_f1_skills_end_to_end. GREEN phase proxima: crear SKILL.md + bump policy.yaml.skills_allowed. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
GREEN phase per CLAUDE.md regla #3 and .claude/rules/tests.md. RED commit (5d6091d ancestor + RED) introduced 16 failures; this commit turns all 16 green without touching any unrelated test. Skill body (.claude/skills/audit-session/SKILL.md ~110 lines): - Frontmatter minimal canonical: name=audit-session, description starts "Use when ...", allowed-tools list of 6 entries (Glob, Grep, Read, Bash(find:*), Bash(wc:*), Bash(.claude/skills/_shared/log-invocation.sh:*)). No Bash(git log:*) per ajuste 2 del usuario. - Read-only advisory main-strict: scope explicito MAY/MUST NOT. - Three audit surfaces declared (Fase -1 decision A1.a): Bucket 1: skills_allowed vs skills.jsonl invocations. Bucket 2: lifecycle.*.hooks_required vs per-hook log files. Bucket 3: audit.required_logs vs file existence/nonempty/mtime. - 30-day review window declared as textual guidance (A2.a + ajuste 3 del usuario): the skill does NOT execute date math, the human applies the lens when reading the report. - Prefix normalization assumption (A3.a): pos:<slug> stripped before cross-comparing with policy.yaml.skills_allowed. - Pre-existing drift expected (A4.a): hooks.jsonl declared in audit.required_logs but no such file exists. Skill reports it as Bucket 3 candidate, does NOT auto-fix. - Report structured by surface (A5.a): three sections + summary line. - audit.session_audit.schedule (e.g. weekly) explicitly NOT enforced (A6.a): documental cadence, no cron/CI hook in F1. - Out of scope: external fork delegation (main-strict by design), cross-session aggregation, date arithmetic, mutating policy or logs. Body satisfies all 5 TestAuditSessionBehavior tests literally: - skills_allowed + lifecycle + hooks_required + required_logs tokens. - "advisory"/"read-only"/"does not modify"/"no modifica" tokens. - No "subagent"/"code-architect"/"agent(" tokens (uses "fork" for external delegation refusal). - "30" + "day"/"review window" tokens. - "pos:" + "normaliz" tokens. policy.yaml: - skills_allowed: 13 -> 14 entries (audit-session appended). - Comment line 268 updated: "E3b 13 skills -> F1 14 skills". Test deltas (793 passed + 1 skipped, zero regression): - 10 parametrized [audit-session] in TestStructure / TestFrontmatter / TestBody pass. - 5 TestAuditSessionBehavior pass. - test_real_skills_allowed_populated_by_f1 passes (tuple is now 14). - test_all_fourteen_e1_e3b_f1_skills_end_to_end passes (logger -> Stop hook end-to-end with all 14 skills allowlisted). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Phase N+3 docs-sync per CLAUDE.md regla #2 (docs-sync within branch) and pre-pr-gate.py canonical baseline (ROADMAP + HANDOFF mandatory) plus conditional `.claude/rules/skills-map.md` for `skills/` paths. ROADMAP.md: - Top table: Fase F status `pendiente` -> `1/4 (F1 ok, F2..F4 pending)`. - F1 row: status `pending` -> `done (PR pending)` with concrete scope. - New section "Progreso Fase F" with feat/f1 detail block: entregables, allowed-tools rationale, contract locked by suite, A1.a..A6.a decisions, 3 mandatory user adjustments, criterio salida. HANDOFF.md: - Section 1 snapshot: Rama actual F1 (PR pendiente); next branch F2; F1 entregables one-liner. - Section 9 Proxima rama: F2 feat/f2-agents-subagents with scope (3 subagent definitions, naming-conflict question, agents_allowed evaluation). - New section 19 "Estado F1": full closure block parallel to E3a/E3b, with entregables + contract + 3 mandatory adjustments + YAML gotcha avoided + resultado (793 + 1 skip) + cross-references. MASTER_PLAN.md Rama F1: - Replaced 1-line stub with full closing block: scope concrete (3 surfaces), A1.a..A6.a decisions, 3 mandatory adjustments, contexto a leer, criterio de salida, carry-overs to F2..F4. Branch marker set to "PR pendiente". .claude/rules/skills-map.md: - Audit + Release section: audit-session row populated with concrete contract (3 surfaces + main-strict + 30-day textual guidance + no auto-fix + allowed-tools list). Replaces the 1-line stub from F0. Tests: 793 passed + 1 skipped (D5 intentional subprocess-no-cover). Zero regression D1..D6 + E1a..E3b. Behavior contract for audit-session locked across 5 tests. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds a new F1 skill to audit drift between declared policy and actual session logs, and wires it into the repo’s allowlist + contract tests/docs so it’s enforced and documented consistently with prior Phase E skills.
Changes:
- Introduces
/pos:audit-sessionskill definition as read-only advisory + main-strict, auditing three declared surfaces (skills_allowed,lifecycle.*.hooks_required,audit.required_logs) vs.claude/logs/. - Extends the enforced skill allowlist from 13 → 14 across
policy.yamland test fixtures/contracts. - Updates phase tracking docs (ROADMAP / MASTER_PLAN / HANDOFF) and the canonical skills map to reflect F1 completion and scope.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
policy.yaml |
Adds audit-session to skills_allowed and updates allowlist comment to reflect 14 skills. |
hooks/tests/test_skills_log_contract.py |
Renames the end-to-end allowlist/log contract test and updates messaging for 14 skills. |
hooks/tests/test_lib_policy.py |
Renames the “real skills_allowed populated” smoke test to F1 and updates docstring for 14-tuple expectation. |
ROADMAP.md |
Marks Phase F as started with F1 completed and expands the F1 branch entry + narrative section. |
MASTER_PLAN.md |
Expands F1 plan/closure details for audit-session, including surfaces and constraints. |
HANDOFF.md |
Updates snapshot/next-branch guidance and adds a dedicated “Estado F1” section. |
.claude/skills/tests/test_skill_frontmatter.py |
Adds behavior/contract tests for audit-session wording and constraints. |
.claude/skills/tests/_allowed_skills.py |
Extends test allowlist to include audit-session. |
.claude/skills/audit-session/SKILL.md |
Adds the new skill spec (scope, steps, framing, failure modes, out-of-scope). |
.claude/rules/skills-map.md |
Adds the canonical skills-map row for audit-session (lifecycle/model/context/allowed-tools). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| - For each `lifecycle.<gate>.hooks_required` entry: does `.claude/logs/<hook-base>.jsonl` exist? Is it nonempty? Is its mtime within the 30-day review window? | ||
| - For each `<hook>.jsonl` present in `.claude/logs/`: is its base name in any `lifecycle.*.hooks_required`? If not → candidate `logging hook not declared in any lifecycle gate`. | ||
|
|
||
| **Bucket 3 — Required logs drift**: | ||
| - For each `audit.required_logs` entry: does the file exist in `.claude/logs/`? Is it nonempty? Is its mtime within the 30-day review window? (Mtime check is advisory only; report it, do not block on it.) |
There was a problem hiding this comment.
These steps ask to check whether hooks/required logs’ file mtime is “within the 30-day review window”, which implies date-based logic. Earlier the skill says the 30-day window is only textual guidance and that it does not execute date math; consider clarifying that only file-level mtime heuristics are used (not per-entry timestamp arithmetic), or remove the mtime-within-window checks to avoid contradicting the scope section.
| - For each `lifecycle.<gate>.hooks_required` entry: does `.claude/logs/<hook-base>.jsonl` exist? Is it nonempty? Is its mtime within the 30-day review window? | |
| - For each `<hook>.jsonl` present in `.claude/logs/`: is its base name in any `lifecycle.*.hooks_required`? If not → candidate `logging hook not declared in any lifecycle gate`. | |
| **Bucket 3 — Required logs drift**: | |
| - For each `audit.required_logs` entry: does the file exist in `.claude/logs/`? Is it nonempty? Is its mtime within the 30-day review window? (Mtime check is advisory only; report it, do not block on it.) | |
| - For each `lifecycle.<gate>.hooks_required` entry: does `.claude/logs/<hook-base>.jsonl` exist? Is it nonempty? Record/report its file mtime as an advisory freshness heuristic relative to the 30-day review window; do not perform exact date math or per-entry timestamp analysis. | |
| - For each `<hook>.jsonl` present in `.claude/logs/`: is its base name in any `lifecycle.*.hooks_required`? If not → candidate `logging hook not declared in any lifecycle gate`. | |
| **Bucket 3 — Required logs drift**: | |
| - For each `audit.required_logs` entry: does the file exist in `.claude/logs/`? Is it nonempty? Record/report its file mtime as an advisory freshness heuristic relative to the 30-day review window; do not perform exact date math or per-entry timestamp analysis. (Mtime check is advisory only; report it, do not block on it.) |
|
|
||
| 1. **Skills allowlist drift** — `policy.yaml.skills_allowed` (plain slugs) vs `.claude/logs/skills.jsonl` invocations. Detects: declared but never invoked (dead allowlist entry), invoked but not declared (would have been denied today by the Stop hook). | ||
| 2. **Lifecycle hooks/log drift** — `policy.yaml.lifecycle.*.hooks_required` vs the per-hook log files in `.claude/logs/`. Detects: declared hook with no matching log file (hook never ran or never logged), declared hook with empty log (silently disabled), hooks logging that aren't declared in any lifecycle gate. | ||
| 3. **Required logs drift** — `policy.yaml.audit.required_logs` vs file system reality. Detects: declared log file missing entirely, declared log file empty, declared log file older than the review window. |
There was a problem hiding this comment.
This section uses “Detects:” to describe findings. Given the advisory framing elsewhere in this repo for audit-style skills (“declares candidate signals”), consider rephrasing to avoid sounding like a definitive detector (e.g., “Declares candidate signals such as …”).
| 3. **Required logs drift** — `policy.yaml.audit.required_logs` vs file system reality. Detects: declared log file missing entirely, declared log file empty, declared log file older than the review window. | |
| 3. **Required logs drift** — `policy.yaml.audit.required_logs` vs file system reality. Declares candidate signals such as a declared log file missing entirely, a declared log file being empty, or a declared log file being older than the review window. |
| assert any(tok in low for tok in advisory_tokens), ( | ||
| "audit-session body must declare advisory/read-only scope." | ||
| ) |
There was a problem hiding this comment.
The PR description says certain advisory/read-only tokens are “locked” (must appear literally), but this assertion only checks that any token exists. If the contract truly requires all tokens, tighten this to require each one (or add separate asserts) so wording drift can’t slip through.
There was a problem hiding this comment.
Skipping — the any(tok in low ...) is intentional. The body is bilingual (English 'does not modify' OR Spanish 'no modifica'), so requiring all-of would force redundant bilingual bodies. Pattern is consistent with other E3b behavior tests. The PR description wording was imprecise; the test asserts 'any of these advisory framings is present', not 'all four literal strings'.
* kickoff(f2): RED tests — agents/ + flips para pos-* namespace Fase 0 + Fase 1 RED-first de feat/f2-agents-subagents. Scope ratificado en Fase -1: - 2 plugin subagents en agents/: pos-code-reviewer + pos-architect. - auditor diferido (no consumer real hoy; regla #7 CLAUDE.md). - Namespace pos-* para evitar colisión con built-in/user/project agents. - NO tocar policy.yaml (sin agents_allowed; deferred sin consumer). - NO tocar hooks/_lib/policy.py. - NO extender audit-session. Shape primitive (oficial Claude Code subagent): - frontmatter: name + description + tools (comma-separated string) + model. - body Markdown como system prompt. - model: sonnet para ambos. - Sin campos inventados. Files RED en este commit: - agents/tests/test_agent_frontmatter.py (NEW) — 24 RED tests: * Structure (2): file exists + parses * Frontmatter (14): keys subset, required, name match filename, namespace pos-*, description non-empty, tools comma-separated string, model valid * Body (2): substantive (>100 chars) * Capabilities (4): pos-code-reviewer menciona bug/security/scope/invariant; pos-architect menciona pattern/design/cross-file consistency. - .claude/skills/tests/test_skill_frontmatter.py (MODIFIED): * TestPreCommitReviewBehavior::test_delegates_to_code_reviewer renombrado a test_delegates_to_pos_code_reviewer + asserta general-purpose fallback. * TestCompoundBehavior::test_body_declares_fallback renombrado a test_body_delegates_to_pos_architect_with_fallback (asserta pos-architect literal + general-purpose fallback). * pattern-audit + audit-session negation lists incluyen pos-architect / pos-code-reviewer (forward-compat: main-strict skills nunca deben referenciar plugin subagents). Confirmado RED: 26 fail (24 agents + 2 skills flips) + 791 pass + 1 skip. Regression intacta sobre E1a/E1b/E2a/E2b/E3a/E3b/F1. Próximo: Fase 2 GREEN — escribir agents/pos-code-reviewer.md + agents/pos-architect.md + actualizar bodies de pre-commit-review/SKILL.md + compound/SKILL.md. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * feat(f2): GREEN — pos-code-reviewer + pos-architect plugin subagents Fase 2 implementación que satisface los 24 RED tests + 2 skill flips. agents/pos-code-reviewer.md — plugin subagent para branch-diff review. Frontmatter primitive-correct (name + description + tools comma-separated + model: sonnet, sin campos inventados). Body declara las 5 capacidades explícitas que pre-commit-review delega: bugs / logic errors / security vulnerabilities / scope adherence / invariant violations. Output contract: findings agrupados por severidad (blocker/high/medium/nit), confidence- filtered, file:line refs. Hard limits: no Edit, no Write, no PR, no invocación de otras skills/subagents. agents/pos-architect.md — plugin subagent para pattern extraction + cross-file design. Frontmatter primitive-correct. Body declara 3 dimensiones: pattern extraction (≥2 repeticiones, regla #7), architectural design (cohesión + tradeoffs), cross-file consistency. Output contract: patterns en formato canónico (Name/Context/Signal/Rule/Examples/Rationale) listo para que compound los folde en .claude/patterns/<slug>.md. Hard limits: no refactor, no Edit, no overwriting de patterns existentes. .claude/skills/pre-commit-review/SKILL.md — flip code-reviewer → pos-code-reviewer (description + body + steps + failure modes). Fallback a general-purpose se mantiene literal. subagent_type / agent tool refs intactos. .claude/skills/compound/SKILL.md — flip code-architect → pos-architect (description + body + steps + failure modes). Fallback a general-purpose intacto. Pattern format + STOP signal + writer-scoped strict intactos. Resultado: 817 passed + 1 skipped (baseline 791 + 26 nuevos: 24 agents contract + 2 skill flips). Zero regression sobre E1a/E1b/E2a/E2b/E3a/ E3b/F1. Próximo: Fase N+1 simplify pre-PR + Fase N+3 docs-sync (ROADMAP/HANDOFF/ MASTER_PLAN/skills.md/skills-map.md/ARCHITECTURE.md). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs(f2): sync ROADMAP + HANDOFF + MASTER_PLAN + rules/ for plugin subagents Cierre de Fase N+3 docs-sync de F2: documenta los plugin subagents `pos-code-reviewer` + `pos-architect` (entregados en commits previos e63f438 RED + 2a5396b GREEN) en todas las superficies de docs del meta-repo. Cero cambios de código en este commit — sólo prosa. ROADMAP.md - Fila F status flippea a `🔄 (F1 ✅, F2 ✅, F3..F4 ⏳)`. - Fila F2 `⏳` → `✅ | — (PR pendiente)` con scope completo. - Sección `### feat/f2-agents-subagents — ✅ (PR pendiente)` nueva antes de "## Convenciones" — entregables, suite stats (817+1), contrato fijado, 6 decisiones Fase -1 ratificadas, exit criterion. HANDOFF.md - §1 snapshot: rama actual F2 ✅ PR pendiente, anterior F1 ✅ #25, siguiente F3 — `feat/f3-selftest-end-to-end`. - §8 reframe: built-in subagents → plugin agents `pos-*` críticos (consumed by pre-commit-review + compound), built-in residuales sólo para branch-plan reads. - §9 Próxima rama: F2 → F3 (selftest end-to-end). - §20 Estado F2 NEW: entregables + contrato + decisiones + ajustes + resultado 817+1. MASTER_PLAN.md - § Rama F2 expandida: scope 2 agents pos-*, archivos a crear/ modificar, 6 decisiones cerradas, ajustes v1→v2 (recorte de 3→2 + namespace + no policy), contexto a leer, criterio de salida, carry-overs F3/F4. .claude/rules/skills.md - § Fork / delegación: precedentes flippean a `pos-code-reviewer` + `pos-architect` (post-F2) con disclaimer de fallback `general- purpose`. Plugin agent primitive box explícito (shape distinto al skill: `tools` comma-separated string vs YAML list `allowed- tools`). Forward-compat negation list extendida con `pos-*`. - Behavior tests row: refleja flips F2 + negation lists extendidas. .claude/rules/skills-map.md - Filas `pre-commit-review` y `compound`: subagent_type flippea a `pos-code-reviewer` / `pos-architect` (post-F2), fallback `general-purpose` literal. - Sección "## Subagents del plugin (entregado en F2)" NEW: tabla con los 2 agents + contract tests + fallback + diferidos (`pos-auditor`, `agents_allowed`) + forward-compat negation. Resultado: 817 passed + 1 skipped (sin cambios al code; suite intacta). E1a..F1 + D1..D6 regression intacta. `docs/ARCHITECTURE.md` NO modificado (decisión Fase -1 ratificada: F2 no toca `generator/` ni `hooks/`; pre-pr-gate conditional no exige sync). Próximo: simplify pre-PR + pre-commit-review (dogfooding F2 sobre sí mismo: pre-commit-review delega a pos-code-reviewer) + gh pr create. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * simplify(f2): fix stale framing in pre-commit-review delegation disclaimer El disclaimer de Delegation rezaba "The string `pos-code-reviewer` here reflects the Claude Code default shipped today" — wording correcto cuando apuntaba a `code-reviewer` (built-in de Claude Code) pero stale post-flip F2: `pos-code-reviewer` es plugin agent, no default de Claude Code. Reescrito para reflejar la realidad post-F2: "The string `pos-code-reviewer` is the plugin subagent shipped by `pos` in F2 (defined in agents/pos-code-reviewer.md). It is hardcoded with a disclaimer: runtimes that do not load plugin agents (or load them under different names) may not expose it." Sin cambios de comportamiento (la fallback rule a `general-purpose` queda literal). Sin cambios al contrato de tests. Suite 817 passed + 1 skipped. Writer-scoped strict: archivo dentro del diff `git diff --name-only main..HEAD`. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(f2): address PR #26 review — required tools/model + ARCHITECTURE.md § 6 Atiende los 2 ajustes solicitados por el usuario sobre PR #26 (más un fix trivial de un test name reference flaggeado por Copilot): 1. Hardening del contract de agent primitive `agents/tests/test_agent_frontmatter.py`: - `tools` y `model` movidos a `REQUIRED_FRONTMATTER_KEYS` (antes opcionales vía early-return — dejaba el contrato flojo para drift). - `test_tools_is_comma_separated_string` ahora valida tokens (split por `,`, asserts non-empty + sin whitespace en el nombre antes de `(...)` — antes un space-separated string pasaba el test). - `test_model_valid_if_present` → `test_model_valid` (sin early-return). - NUEVO `test_model_is_sonnet_for_f2` parametrizado por agent: lockea decisión Fase -1 (1) `model: sonnet`. Bumpear a opus/haiku exige rama nueva + ratificación. 2. `docs/ARCHITECTURE.md § 6 Agents` reescrita La sección era stale (listaba `code-reviewer` / `architect` / `auditor` sin namespace, usaba `allowed-tools:` que es shape de skill, no de agent). Ahora documenta: - top-level superficie `agents/<slug>.md` con primitive oficial (`name` / `description` / `tools` comma-separated / `model`); - tabla shape skill vs agent (divergencia esencial post-F2); - namespace `pos-*` obligatorio + test que lo lockea; - 2 agents entregados + diferidos (auditor + agents_allowed) + forward-compat negation. 3. Trivial: `HANDOFF.md` test name reference `test_name_is_pos_prefixed` → `test_name_uses_pos_namespace` (matcheaba el doc al test real; el doc estaba desincronizado). Docs-sync sincronizado: ROADMAP + HANDOFF §20 + MASTER_PLAN § F2 ahora reportan 819 passed + 1 skipped (vs 817; +2 por el nuevo `test_model_is_sonnet_for_f2` parametrizado por 2 agents) y reconcilian la decisión (6) que ahora SÍ incluye `docs/ARCHITECTURE.md § 6 Agents` (antes "no requerido" — contradicción cerrada). No cambios de scope: sin `agents_allowed`, sin `pos-auditor`, sin modificar `policy.yaml`, sin tocar `audit-session`. Suite: 819 passed + 1 skipped. Sin regresión D1..D6 / E1a..E3b / F1. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs(f2): reconcile count math + stale comment + diff syntax across docs Five tweaks surfaced by Copilot's second pass on PR #26 (commit f230320): 1. .claude/skills/tests/test_skill_frontmatter.py:316 — stale comment said `code-reviewer` (built-in default) when the test now asserts `pos-code-reviewer` (plugin subagent shipped by F2). Reworded. 2. test_skill_frontmatter.py:351 + 419 — `main..HEAD` (two-dot, ancestor-only) in docstrings flipped to `main...HEAD` (three-dot, merge-base relative) matching what the skill bodies actually run. 3. HANDOFF.md:9 + §20:425 — count framing said "+24 contract + 2 skill flips" or "+28 nuevos". Suite delta is +26 net (793 → 819) from the new parametrized file (2 slugs × 13 methods). Behavior flips edit assertions in existing tests — they don't add count. Reframed everywhere. 4. ROADMAP.md:621 + MASTER_PLAN.md:694 + 722 — same reconciliation as (3). 5. MASTER_PLAN.md decision (6) line 706 + ROADMAP exit criteria 640 already updated in f230320 to include `docs/ARCHITECTURE.md § 6 Agents`; now the count math in the same paragraphs matches. No code change. No test added or removed. Suite still 819 passed + 1 skipped. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Javier <javier.abril@glassnode.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Summary
/pos:audit-session, read-only advisory main-strict que cierra la capa 3 del determinismo declarado endocs/ARCHITECTURE.md§ Determinismo: comparar lo quepolicy.yamldeclara contra lo que.claude/logs/realmente registra.skills_allowed↔skills.jsonlinvocations distintas (conpos:normalization); (2)lifecycle.<gate>.hooks_required↔<hook>.jsonl(existencia + nonempty); (3)audit.required_logs↔ existencia + nonempty + mtime. Reporte estructurado por surface (3 secciones + summary line) con bullets<entry> — <type>: <reasoning>.audit.required_logsdeclarahooks.jsonlpero los hooks logean a per-hook files (pre-branch-gate.jsonl, etc.). La skill reporta esto como Bucket 3 candidate y no auto-fixea — el usuario decide. Que el finding emerja en la primera invocación es evidencia de que el advisor funciona (decisión A4.a).policy.yaml.skills_allowed13 → 14 (audit-sessionañadido).stop-policy-check.pysigue en enforcement live, ahora con 14 skills aceptadas — sin cambio de código en el hook.policy.yamlantes del body; (2) recortarBash(git log:*)de allowed-tools (final: 6 entries); (3) test del 30-day window valida declaración del body, no ejecución de date math.Contrato locked por la suite (extiende E1..E3b)
skill.json; sin prefijopos:; sin campos inventados.audit-sessiones read-only advisory: nunca modificapolicy.yaml, nunca rota/trunca/edita logs, nunca auto-fixea drift detectado. Tokens locked:advisory,read-only,does not modify,no modifica.audit-sessiones main-strict: ausencia desubagent/code-architect/agent(enforce vivo. Si una rama futura propone delegation, abrir branch nueva con justificación (regla feat(c3): tests harness renderer — 13-file output per profile, deferred frameworks testeable #7 CLAUDE.md).30-day review windowdeclarado como textual guidance para el lector humano — la skill no ejecuta date arithmetic, no filtra entries por timestamp, no podría aunque quisiera (allowed-tools subset estricto).pos:<slug>↔<slug>normalization assumption explicit en body (decisión consciente, no bug).ALLOWED_SKILLS = 14entries enforce vivo. Invocar una skill no listada sigue produciendo deny exit 2 (contrato D6 intacto).Tests
.claude/skills/tests/test_skill_frontmatter.py— 22 parametrizados viaALLOWED_SKILLS13→14 + 5 nuevos enTestAuditSessionBehavior(3 surfaces / advisory-only / main-strict no delegation / 30-day window declaration / prefix normalization assumption)..claude/skills/tests/_allowed_skills.py—ALLOWED_SKILLS13 → 14; header docstring con línea F1.hooks/tests/test_lib_policy.py::test_real_skills_allowed_populated_by_e3brename a_by_f1; tupla 13 → 14.hooks/tests/test_skills_log_contract.py::test_all_thirteen_e1_e3b_skills_end_to_endrename atest_all_fourteen_e1_e3b_f1_skills_end_to_end; allowlist + loop cubren las 14 skills.TestIntegrationDiffUnavailable.Test plan
✅ PR pendiente,.claude/rules/skills-map.mdfilaaudit-sessionpopulada.docs/ARCHITECTURE.mdno requerido (F1 no tocagenerator/nihooks/).🤖 Generated with Claude Code