// build log LIVE

From Zero to Running System

Phase by phase, one machine, still going

This is the diary of how Fulltrace was built. It started on 28 April 2026 as a folder of notes about one person's way of working. By June it had a local server, three connected AI assistants and a VSCode extension. From mid-June it could run jobs by itself, and soon after it could check the results with plain code. In August it started building itself with nobody in the session, and in October the same factory took on its first slice in another project. The log runs in the order things happened, including what broke along the way.

The Stack

The local server runs on Node.js and restarts itself if it crashes. Studio is a VSCode extension with no runtime dependencies of its own.

tech_stackexact versions and packaging
MCP Server
01Node.js v24 (ESM)
02@modelcontextprotocol/sdk v1.30
03Express + StreamableHTTP transport
04pm2 + Task Scheduler (Windows auto-start)
VSCode Extension
01TypeScript → ES2020 / CommonJS
02VSCode Extension API
03Zero runtime dependencies
04Packaged as VSIX via @vscode/vsce

Every Phase, In Order

Each phase left something that was useful without the next one. The personal notes are useful without a server, and the server is useful without Studio. Together they mean no AI session starts from zero.

Phases 01 to 17 built the foundations: the personal notes, the local server, Studio and three connected assistants. They are folded away below. The log picks up at phase 18, when Fulltrace started doing work by itself.

phases_01_17the plumbing: portfolio, server, studio, three clients
28 APR
Phase 01: Identity Consolidation
Context Portfolio

Worked through the AIDB AgentOS templates to fill out all ten portfolio files: identity, role, projects, team, tools, communication style, goals, preferences, domain knowledge, and decisions. Each file is a single page of dense, machine-readable markdown describing how the work actually gets done. Merged Claude Code's session-context file with the richer content from the identity file, creating a single authoritative file that loads automatically every session. Cleaned up duplication across all ten files so each is self-contained.

29 APR
Phase 02: Local MCP Server
Portfolio as a Service

Built a Node.js MCP server using the official Model Context Protocol SDK with StreamableHTTP (stateless) transport. Every portfolio file exposed as a typed portfolio:// resource over a loopback endpoint. Files read from disk on every request, so edits are live without a restart. Wrapped in pm2 with Task Scheduler auto-start on Windows login. The server now runs continuously in the background without any manual steps.

30 APR
Phase 03: VSCode Studio
Making the Invisible Visible

Built a VSCode extension with two surfaces: a sidebar TreeView (always visible) and a WebviewPanel (on demand). One polling loop drives both. Status endpoint added to the MCP server returning metadata, resource list, request count, and a rolling log of the last 100 requests. pm2 Start, Stop, and Restart buttons inside the editor. Click a portfolio file to open it. Seeing the request log live changed how the system was used: watching which resources Claude actually pulls is feedback that did not exist before.

1 MAY
Phase 04: Skills and Memory Tabs
Studio Depth

Added Skills and Memory tabs to Studio. Skills tab lists all Claude Code commands from global and project directories with scope badges. Memory tab parses project memory files with YAML frontmatter. Custom slash commands created for the full post-build workflow: update changelog, update docs, sync showcase copy, commit, push, all chained via a single jn-website-commit orchestrator with a confirmation gate at each step.

2 MAY
Phase 05: Full-Height Layout and Skill Logging Fix
Studio Polish

The Studio panel now fills the window and resizes with it. Active tab content scrolls; status card and tab nav stay fixed at the top. Fixed a critical bug: log-skill.js used CommonJS require in an ESM package, so every skill invocation threw a ReferenceError that nobody saw, and nothing was posted to the server. Fixed with an ES module import. Restarted the pm2 process to pick up the fix.

3 MAY
Phase 06: Portfolio MCP Wiring and Config Portability
Global Portability

Claude global config made portable: skills and memory versioned in the Fulltrace repo and synced to ~/.claude/ via sync.ps1. The global CLAUDE.md now travels with the repo and restores on any machine with a single push. Portfolio MCP section added to the project CLAUDE.md, instructing Claude to use portfolio:// URIs when reading portfolio files rather than searching the filesystem.

4–5 MAY
Phase 07: Codex MCP Bridge and Config-Driven Skills
Multi-Client and Registry

Codex connected to Fulltrace via an HTTP MCP bridge (no separate server). Portfolio-read events from Codex now flow back to the shared Fulltrace server and appear tagged in the request log. A global config/projects.md registry defined paths, changelogs, and web page targets for all four projects. All skills refactored to read from the registry rather than hardcoding paths. $env:AGENTOSROOT eliminates usernames and machine-specific paths from the repo.

10 MAY
Phase 08: Token Tracking Infrastructure
Visibility Into Cost

End-to-end token tracking built into the server: a normalisation pipeline converts token usage across providers, per-skill and per-tool totalTokens accumulated alongside invocation counters, and cumulative all-time totals persisted in persist.json. Both log-skill.js and log-tool.js now extract token usage from Claude hook payloads and include it in their POST bodies. Session and all-time totals returned in /status.

10 MAY
Phase 09: Haiku Sub-Agent Delegation
Cheaper Portfolio Reads

All ten portfolio-read skills now spawn Haiku sub-agents for resource retrieval. Token overhead shifted from the main session to cheaper Haiku contexts. The same delegation pattern applied to orchestration: jn-website-commit delegates changelog, docs, git, and showcase steps to sub-agents. The --auto flag added to five skills, allowing the orchestrator to skip confirmation gates when chaining. Only the changelog draft step still pauses for review.

12 MAY
Phase 10: Per-Model Token Tracking and Studio Redesign
Model-Level Visibility

MCP server extended to aggregate tokens per model (Haiku, Sonnet, Opus). The Studio status card was redesigned as a two-row table with session and all-time columns. Run buttons added to each skill entry for direct invocation from Studio, no terminal required. log-skill.js and log-tool.js now extract the model from Claude hook payloads and include it in POST bodies. 60-second auto-save interval added to server.js for regular state persistence between requests.

14–15 MAY
Phase 11: Setup Wizard, Sync Diff UI, and Agents Tab
Operational Tooling

Setup Wizard webview panel added: gather AGENTOSROOT, validate prerequisites, run setup steps with progress feedback, auto-close on success. SyncDiffPanel added: shows file-by-file differences between canonical repo and runtime ~/.claude/ state. Agents tab added alongside Skills and Memory. Server uptime and restart tracking made persistent across restarts. Graceful shutdown handlers flush state to disk before exit.

19 MAY
Phase 12: Create, Run, Remove from Studio
Studio Stops Being Read-Only

Skills, memories, and agents can now be created directly from Studio via wizard forms: fill in the fields, hit Create, the file lands in the correct directory with proper structure and YAML frontmatter. Remove buttons with confirmation dialogs enable deletion without touching the filesystem manually. Agent Run button wired to fire agents via the Claude Code extension directly. Search and filter controls added to all four registry tabs. New /agent-log server endpoint mirrors the skill and tool log pattern, tracking agent invocations with token usage and per-agent stats.

23 MAY
Phase 13: Cursor Integration and Multi-Client Nomenclature
Three Clients

Cursor connected to the shared Fulltrace MCP server via Streamable HTTP. Command logging via hooks.json posts Cursor slash command invocations to /command-log. Studio updated with client pill selectors in Setup and Analytics tabs. All skills renamed to the new Commands nomenclature and moved to clients/claude/commands/. bootstrap.ps1 added for automated new-machine setup. Codex README updated with gateway pattern documentation.

28 MAY
Phase 14: Shared Centralisation
One Source, Three Clients

Global memory files and skills moved from per-client directories into a single clients/shared/ directory. All three sync scripts updated to source from shared. Commands tab deduplication implemented: shared skills appearing in multiple clients collapse to a single row with stacked tool badges. An "All" badge replaces individual badges when all three clients carry the command. Scope terminology standardised from "local" to "project" throughout. Client colour assignments corrected: Claude = blue, Cursor = orange (previously swapped). Codex rate limit adapter fixed for expired rate limit windows.

28 MAY
Phase 15: Showcase Rewrite
Documenting the System

The showcase website Fulltrace section fully rewritten from scratch: seven new pages (overview, architecture, Claude, Codex, Cursor, studio, build log) with a persistent two-level navigation so users can discover and move between sections without getting lost. Pages sourced directly from the repo: READMEs, CHANGELOG, and source architecture. Previous pages archived with cross-links preserved for reference.

4 JUN
Phase 16: Templating, Security, and Telemetry Accuracy
Hardening the Shared Layer

Shared skills became client-aware: {{LIGHTWEIGHT_MODEL}} and {{CLIENT_NAME}} placeholders now expand per client at sync time, so one skill file resolves to Haiku on Claude and Cursor and GPT-4o-mini on Codex. Codex skills now self-report to /command-log via a logging block injected at sync, so Codex invocations show in Studio alongside Claude and Cursor. The pm2 controls were hardened against shell injection: child_process.exec through cmd.exe replaced with spawn (no shell) plus process-name validation. Stats-cache accuracy fixed: a full ISO lastComputedAt timestamp replaces the date-only cutoff so same-day sessions are re-counted, and the hour-of-day heatmap now bins by local time. jn-ext-deploy made self-contained so it runs without the MCP extension tools loaded.

11 JUN
Phase 17: Multi-Provider Models and Cost Tracking
Beyond One Vendor

Codex gained pay-per-token access to OpenRouter-hosted models with no subscriptions: one API key, four role profiles (planner on DeepSeek V4 Flash, tools on Qwen3 Coder, agentic on Kimi K2.5, cheap on the free Qwen tier), all deployed through the managed config block. Studio followed: a shared pricing module estimates cost per model across Anthropic, OpenAI, and OpenRouter, the Codex analytics adapter attributes tokens to real model IDs from rollout logs, and the model tables render columns dynamically from the data instead of a hardcoded Haiku/Sonnet/Opus trio. Two real bugs fell out of the work: Codex token totals were double-counting cached and reasoning tokens (subsets, not additions), and Codex could not reach the MCP server at all since the security hardening because nothing sent the Bearer token. The managed block now authenticates via AGENTOS_TOKEN, kept in sync by sync.ps1.

13 JUN
Phase 18: Agent Loops and the Website Update Pipeline
Agents That Run Themselves

Fulltrace started doing work by itself. One model writes a plan, a second carries it out with tools, and a third checks the result and sends it back when it falls short. Network errors are retried without the model seeing them, a badly formed tool call goes back to the model to fix, and a test harness runs the same task many times to measure how often it succeeds. The first job kept this website current from each project's changelog, readme and version. A model proposed the edits and plain code made them, inside the website folder only, with git blocked.

24 JUN
Phase 19: A Map of Steps, and a Way to Start a Run
From One Loop to a Graph

The single pipeline became one step in a larger map of steps. Code checks the map before any model is paid for, runs a few steps at a time, and stops the run if it goes over its token budget. The first run on it audited the code of every enrolled project at once. The local server gained a way to list workflows, start a run and stream its progress live, all behind a login token because these calls spend money.

25 JUN
Phase 20: Backup Models and Focused Audits
Planning for Outages

Free-tier rate limits blocked the first full run, so a stage could now take a list of models: a preferred one, then backups. If a provider is down or busy, the stage restarts on the next model. A real error is reported straight away, and the record names every model that was tried. The same push fixed the worst quality bug. Code now picks the most useful files for each audit, and a run that ends without sending its findings is a failure. Before, it looked like a clean pass.

26–27 JUN
Phase 21: The Verifier and the First Fixes
Code Checks the Model's Work

Plain code now re-checks an audit result in four ways: the output exists, the model finished, the report has the right shape, and every finding quotes a real line in a real file, word for word. If any finding cannot do that, the whole result fails, and a failed result gets one smaller retry. The path for making a fix landed alongside it. A fix is replayed from a saved report that passed the checks. It is a preview by default, limited to allowed folders, needs a clean working tree and must pass the project's own build. A line-ending mismatch blocked the first real fix, so matching now allows for line endings. Two real fixes went through the whole path and were committed.

28 JUN
Phase 22: A Challenger, and a Registry of Workflows
A Second Opinion That Cannot Overrule

A second model can now be asked to challenge a result that passed. It can add a warning. It cannot change the verdict or cause a write, and that policy is written down. Workflows also got a registry, where each one has a fixed id and a description that is checked before any model is called. Two new workflows use no model at all. One reports docs that have fallen behind the code, and the other reports commits the changelog does not mention.

29 JUN
Phase 23: Platform Foundation
Durable and Local

Runs are now saved twice: in logs that are only ever added to, and in a local database for fast lookups. A database row with no matching log entry is kept and reported as it is. Queued jobs hold no keys, because the worker adds credentials when it picks a job up. An approval record now exists for any future fix made with nobody present. It is tied to one exact change and issued by a command that refuses when in doubt. Applying a fix with nobody present stayed impossible.

30 JUN
Phase 24: Reading the Results, and the Website Audit
The Runtime Reads Its Own Output

A read-only layer over the audit results, with no model in it: a report that groups findings and links each one to its evidence, a log of what was decided about each finding, and a summary of what past runs show. Everything in it is a suggestion, and nothing fixes itself. The website audit also became a workflow. It reviews how this site tells each project's story. It can propose changes and cannot make them.

1–2 JUL
Phase 25: Studio
Running Jobs From the Editor

The extension grew Workflows, Runs and Graph tabs, then merged them into Studio: one screen built around the life of a run. A person picks a workflow, sets it up, sees a cost estimate from past runs, confirms the spend, watches it live and opens any step to read its findings. The lists of workflows and projects moved into files kept in git, so adding a project is a reviewed change. By the end of this phase the panel's code was one 12,000-line file. Splitting it up started in August, and the last big piece left on 29 September.

3–6 JUL
Phase 26: Approved Fixes
The First Kept Write

Making a fix became something done from Studio. Each step was designed first and reviewed by a second AI before it was built. The exact change is shown. Studio then rehearses it: it applies the change, runs the project's own build and undoes it. Only a change that passes can be approved, and the approval covers that one change. On 4 July the first approved fix landed on a real project and was kept, with its build passing. The fix model also got stricter instructions: stay within the evidence, or decline and say why. Around it came a shared model picker and a one-script setup for a new machine. Studio shipped a new release most days through this stretch.

6–8 JUL
Phase 27: Bigger Fixes, and What Needs Me
Bigger Fixes Without More Power

The next problem was a change too big for one edit. A model now splits it into steps, and that model cannot write anything itself. Each step goes through the same checks and gets its own commit, and a running cap reads the real git history so a large change cannot slip through as a run of small ones. The first live plan had three steps and cost about ten cents. Then, in one day, came the decision inbox: one read-only list of everything that needs a person. Five of its six parts shipped. The sixth needed several machines, which did not exist yet. It was marked deferred, because a paused row left in progress would show as work under way.

10–12 JUL
Phase 28: The Fence, the Phone, and the Fleet
Assuming the Input Is Hostile

The checks already assumed the model could be wrong. This phase assumed the files it reads could be hostile. Audits put real file contents and web pages into prompts, and a copied snippet could carry a line like "ignore your instructions". So every prompt now has one place instructions can come from. Everything else is wrapped as data and sealed with a random marker, and content that already holds the marker is refused. A before-and-after audit over three projects, for about US$0.32, showed no drop in quality. Two more things arrived. The phone started getting notifications and a read-only page, showing counts only, with no content. And Studio gained a set of models that run on the local machine. Their use was recorded from the first call, and they were kept out of task runs.

13–17 JUL
Phase 29: Fewer Tabs, and a Gate That Was Not There
Finding the Control Had Never Worked

Thirteen tabs became seven. A registry now lists every place a prompt is built, and a scan fails when one appears without an entry. It caught a real miss straight away: a stage that had shipped two days earlier without one. Then came the find this phase is named for. A test checked whether granting permission to change project code would ask first, and the command ran with no prompt. None of the three layers meant to stop it was working, and in one mode a rule that should ask is ignored entirely. Nothing would have flagged it. It was rebuilt to give a clear allow, ask or deny for every command. Two weeks later the registry's own coverage claim was checked and found to be half true. Phase 31 picks that up.

18–31 JUL
Phase 30: Reliability, and the Name
Every Call Has a Time Limit

A run could hang on one model call for ever, because a hung call spends no tokens and so never trips the budget. Every call now has a time limit, the stages that use tools have backup models, and a timeline shows which steps really ran at the same time. A run can be stopped part way through, and the stop is recorded as a person's act. Audits also started reading a short brief about how the work gets done, served by the local server and listed in each report. And halfway through, AgentOS became Fulltrace, because another product is called AgentOS and AI tools reading this site had started to mix the two up.

1–7 AUG
Phase 31: Projects, and a Registry With Two Halves
Enrolment That Only Proposes

Each project's details moved out of code into files kept in git, and Studio gained a Projects view: one card per project, a checklist of what it has, and Refresh as the only button. Enrolling a project starts an interview in a chosen AI tool, on a personal account, and what comes back is a proposal for a person to review. The local server stopped crashing on a broken settings file, where one typo used to take every route down. The prompt registry turned out to cover only half the system, so Studio's prompts got a registry and a scan of their own. The local models also got their first real job: a search index over the project's own docs, searched at $0, storing numbers only, with none of the text.

8–9 AUG
Phase 32: The Night, and the Receipts
A Scheduler, Inside Limits Set by Hand

Task runs can now be put on an overnight schedule. A schedule is a file, and switching it on is a separate recorded act tied to the schedule's exact contents, so editing a schedule switches it off again. Nothing runs until its limits are set by hand, and the limits file ships blank. One limit counts how many decisions a night can leave for a person by morning. Jobs are keyed to calendar dates, so a daylight saving change cannot run one twice, and every due job ends as ran, skipped or capped, with the reason named. The scheduler is built and tested, and no job has been scheduled on it yet. Studio also gained a Signals view: counts drawn from the run records, with no model involved. And a sweep closed gaps in the spending record. A mistyped option used to be read as a prompt and buy a model call. It is now refused, with the nearest real option named.

10–19 AUG
Phase 33: Workflows as Data, and a Line Around the Machine
What Runs, and What May Leave

A workflow can now be written down in a file and run. The file is checked against a fixed shape, nothing can use it until a person accepts it, and an edit after that cancels the acceptance. Steps can carry a condition such as "only if the report has findings", and a workflow that writes to files is refused. The same fortnight set the rule for what may leave this machine. The thirteen places data can leave were listed in code and locked by tests, and nine of them are this machine talking to itself. The push tool refuses a remote owned by anyone else, and the assistants lost the four shell commands that send data out. Spending got its own page, where runs can be filtered by model and two runs compared side by side. A tool also arrived that breaks the code on purpose and checks that the tests fail. Its first real run found a small group of tests that disagreed with themselves. And on 19 August the first slices, small planned pieces of work, shipped with nobody in the session.

20–26 AUG
Phase 34: The Rules Become Data, and a Second Builder
Rules With Receipts

The nineteen standing rules stopped being paragraphs. Each got a record saying how it is enforced, checked against the real code: a guard that refuses, a test that fails, a checklist step, or nothing yet. One rule turned out to have nothing, and the record says so. Eighteen were ruled permanent and one temporary in one sitting, and Studio lists them under Config > Governance. The steps of the method moved out of the extension's code into a file a project can own. A saved run became a test: replayed with no model called, 89 of 101 recorded runs came out exactly the same. A chat tab arrived in Studio, with the model and cost on every reply and a spending limit that stops it. Schedules could be switched on and off, created and edited from the screen. On 22 August the unattended runs moved from nights to around the clock. And the written process stopped assuming Claude. A short file at the top of the repo tells any assistant where the rules live and what only a person decides. The first watched Codex run found the rules and diagnosed the problem better than the backlog row had. Then it stopped, because in that mode Codex could not write files here.

27 AUG–3 SEP
Phase 35: Two Modes, and a Panel That Dates Its Numbers
Operate and Build

The panel had grown to nine tabs, and the screen for building Fulltrace sat last, behind eight tabs meant for using it. So the panel got a switch: Operate, eight tabs for using Fulltrace, and Build, six tabs for building it. It reopens where it was left, and nothing is more than two clicks deep. Seven panels that show a figure read from somewhere else now say where the figure came from and when it was taken, and an empty list gives a count and a reason. Chat learned to use a model on this machine at $0. How deep a code audit reads can be chosen, and every project says when it was last audited. Most of the remaining places the panel said AgentOS became Fulltrace. Four stayed, because other code reads them by exact name. And each build of the extension now carries a number and a list of the slices in it. The first list was wrong, and fixing it became a row.

4–17 SEP
Phase 36: A Security Review, and the Big File Comes Apart
Tightening What Was Already There

A security review on 4 September read through the code. Its four most serious findings were fixed within ten days, and thirteen small ones were closed in October. The file tools can no longer write to the files that decide what runs next. The logging endpoints now need the login token. Audits and other model-driven jobs stopped carrying the write token, which they never needed, and memory copied into the repo is checked for six common key patterns. Meanwhile the half of Studio's 22,000-line panel file that answers button presses moved into small files that can be tested, in eleven steps, with nothing on screen changing. On the factory side, one run that started just before midnight on 6 September took on 17 slices and shipped all 17 over the next 18 hours. After a run, a page now lists what to click to check the work, and the factory's board gained a stats page that shows how much of the machine's working time the unattended runs did. From 12 September a slice that changed the runner's own guard rails stopped the run until a person had looked.

18–30 SEP
Phase 37: A Lower Limit, and Steadier Runs
What One Risky Slice Changed

On 21 September a slice in the write-or-authority risk class shipped unattended, without the design review the rules recommend for that kind of work. The same day the unattended limit was lowered, so that work now only runs with a person present. Since 26 September raising the limit again would not be enough, because each such row also needs a dated clearance written by a person after its review. The unattended runs got steadier too. They pause when the Claude plan runs out of hours and pick the same slice back up, and since 28 September they run on a fixed copy of the runner's code, so a slice cannot change the runner it is running under. Codex had been refused every time it was asked since 9 September, and no check flagged that the first-choice reviewer was dead. It was repaired on 27 September, given the same guard as Claude, and offered as a builder for slices a person starts. A scan also found twenty-two of the project's own self-tests crashing before they tested anything. New in Studio: a Research workflow that answers from chosen files, chat that can read attachments, an Ideas tab, and a button to rule on a parked slice.

1–9 OCT
Phase 38: One Factory, Other Projects
Beyond Fulltrace

The factory had only ever built Fulltrace. In the first week of October it became able to work from another project's roadmap. Fulltrace can tell which project a folder belongs to, one command gives a new project a starter roadmap, and the board, the stats page and Studio's Build mode can each show any enrolled project. On 5 October the first slice outside Fulltrace, and so far the only one, shipped in the Salesforce Developer Tools extension, in a run started by hand. Studio's Start button still runs Fulltrace only. The same week the runner's queue could be changed from Studio, where before a session had to edit the file. Every deploy now writes its own page of manual checks, which can be finished inside Studio. A Films tab rebuilds the demo films on this site and reshoots the board one. And the Research workflow can cite the web when a box is ticked, and one bad quote no longer sinks the whole answer.

Lessons Learned

01
MCP is simpler than it looks

Connecting an assistant to personal information sounded hard. The standard, MCP, does most of the work, and its stateless mode means there are no sessions to manage. The hard part was understanding the ideas. The building was small.

02
Windows extension hosts have a stripped PATH

Tools do not always inherit your normal setup, and half the work is making things run reliably on a real machine. A VSCode extension does not get the shell's PATH, so tools installed with npm cannot be called directly. The first fix sent whole commands through cmd.exe. It worked, and it was later tightened, because a shell is also a way to inject commands. The process name is now checked against a strict pattern before anything runs.

03
Local-first is enough for now

Remote hosting was considered on day one. Every assistant in use runs on this machine, and a server that only accepts connections from this machine avoids most of the questions about encryption and hosting. The one thing added since is a read-only page a phone can reach over a private network. Moving to a different PC is the one real cost, so part of it is scripted. bootstrap.ps1 checks the machine and prepares pm2, and each assistant has a sync script that redeploys its setup. Starting the server the first time is still a step done by hand, and setup notes cover the rest.

04
Studio makes the system real

Watching which notes Claude actually reads changed how they are written. Token counts per model changed which model is used for which task. Seeing Cursor's commands logged beside Claude's confirmed that the wiring between assistants worked.

05
Shared before specialised

Moving each assistant's memory and commands into one shared folder was the right call. A change to a command or a memory file now reaches all three assistants on the next sync, so they stay in step. The repo is the master copy, and the live folders on each machine can always be rebuilt from it.

06
Test what actually runs

Four bugs shipped without ever crashing, all the same shape. The panel's script was built from one very large block of text, and a single backslash before a pattern was stripped when that text became code. \d{4} turned into d{4}, so every chart date fell back to the raw timestamp. Nothing threw an error. Reading the source would never have found them, because the code being read was not quite the code that ran. They turned up once the real script was built and its functions were run against known inputs. On 29 September the script moved into a file of its own, which removed the stripping.

07
A safety check nobody tests is a decoration

The permission check on project code let everything through for weeks, and nothing flagged it (phase 29 above). A check that blocks is noisy and gets fixed. A check that lets everything through looks the same as one that works. So a control is now assumed dead until it has been seen to refuse. That rule is now a step in the method. A slice that adds a check has to break the code on purpose and show that the check fails.