alfonsograziano/ai-hostile-repo
The floor, on purpose: a small repo built to fail every check, so the report reads as a worked example rather than a scold. Production credentials committed in two files, a push to master that runs every migration against the live database, and nothing written down anywhere. Below is the run the agent did and the AINE-REPORT.md it wrote.
- 0 passed
- 46 failed
- 0 n/a
- JavaScript · npm (no lockfile) · Express + React · Webpack + Babel · ESLint · GitHub Actions
Run 14 August 2026 · master at fb25c1e
The agent run
I cloned alfonsograziano/ai-hostile-repo into a temp folder, audited it against all 46 checks and wrote the full report to AINE-REPORT.md in the repo.
AI-Native Readiness — alfonsograziano/ai-hostile-repo
0 passed · 46 failed · 0 not applicable
High priority — fix these first
- Rotate every credential in
.envandconfig.js, then stop tracking them —git rm --cached .env, add.envto.gitignore, commit a.env.example, delete the hardcoded fallbacks inconfig.js, and remove the production psql string fromREADME.md. Why: a checkout hands an agent the production database password, the payments secret that charges real cards, the JWT secret to mint an admin session, and the SMTP password. They are in public git history, so rotation is the only real fix. - Delete the two production commands from
README.md— the prodpsql ... -f migrations/003_drop_old_users.sqland thessh ... "pkill node"one-liner. Why: the only doc an agent reads presents deleting user rows and killing production as routine steps. - Stop
git pushfrom deploying — move themigrate prodandship itsteps out of the push trigger in.github/workflows/deploy.ymlinto aworkflow_dispatchjob behind a protected environment with a required reviewer. Why: every push tomasterruns all ofmigrations/*.sqlagainst production — includingdelete from users where created_at < '2022-01-01'— then rsyncs with--deleteandpkill node. No human anywhere on that path. - Add the missing
check_admin(req)guard to/api/admin/cleanupinserver/index.js. Why: it is the only admin route with no auth check, and it deletes a year of orders. - Make a fresh clone runnable — un-ignore and commit
package-lock.jsonwith exact versions instead of*andlatest, add.nvmrc, and makeconfig.jsthrow whenDATABASE_URLis unset instead of falling back to prod. Why:npm startdoes not exist, nothing is pinned, and a fresh worktree that does start the server connects to the production database. - Write
AGENTS.md— whatshopis, the real build, start, lint and test commands, theserver/vssrc/vsbuild/layout, the traps now buried indocs/notes.txt, and a "never without asking" list. Why: there is no agent instruction file at all. This one file unblocks 8 of the 46 failures. - Add
start,build,lintandtestscripts topackage.json, then acheckthat chains them. Why: an agent cannot prove its own work; the build command exists only inside a CI YAML file. - Get the linter to zero — add
.eslintignorewithbuild/, runeslint . --ext .js --fix(377 of the 411 errors are mechanical), fix the rest. Why: 411 errors on an untouched clone means an agent cannot tell its own damage from the baseline. - Add a pre-merge CI workflow (
on: pull_request) runningnpm ci, lint, tests and agitleaksscan, with branch protection onmaster. Why: nothing is checked before a change lands..envwas committed and nothing objected. - Add a test runner and start with the money path —
calcTotaland the twoformatPricevariants inserver/utils.js. Why:npm testis still the npm-init placeholder that exits 1. - Gate new checkout behaviour behind an off-by-default env flag in
config.js. Why: the deploy swaps every user at once with downtime in between, and there is no way to turn a bad change off without a redeploy.
Low priority — worth doing
- Add Prettier and a
formatscript, so diffs stop churning on style. - Add
.github/dependabot.ymland annpm auditstep —requestis deprecated and carries the card charge. - Add
CONTRIBUTING.mdand a PR template with the pre-merge checks as checkboxes. - Remove the empty
uncaughtExceptionhandler, the nineif (err) { }blocks andq2inserver/db.js, so failures leave something readable behind. - Add an error tracker and a structured logger — observability is currently
tail -f nohup.outover SSH. - Create
docs/adr/with aTEMPLATE.md, and write the first three records: why there are two servers, which discount-and-tax order is correct, whybuild/is committed. - Adopt a migration tool with down scripts and a rollback section in the README —
migrations/is forward-only and003is irreversible. - Turn the two known incidents into tests: the discount and tax order, and the duplicated
formatPriceinserver/utils.jsandsrc/App.js. - Add
.claude/commands/with a check-and-report prompt and a migration-plus-down-script prompt.
Every check was run, not assumed: npm test exits 1, npm start errors with Missing script: "start", and npx eslint@8 . returns 411 errors on the clean checkout.
The report it wrote
AI-Native Readiness Report
Repo: alfonsograziano/ai-hostile-repo, a fresh clone of master at commit fb25c1e (2026-08-14)
Date: 2026-08-14
Stack: JavaScript (no TypeScript). Node.js + Express server (server/), React 16-era class components bundled by Webpack + Babel (src/, webpack.old.config.js), PostgreSQL via pg with raw SQL in migrations/. npm as package manager, ESLint as linter, GitHub Actions as CI. 25 tracked files, 18 commits, first commit 2023-02-14.
Result: 0 passed, 46 failed, 0 not applicable.
How to read this. Every item is a numbered question about this repo, answered from evidence in this repo. Proof is what was actually found — a path, a file, a command and its output. An item with no proof is not an answer. The italic line under each question says how to check it; it stays in the report so the next run checks the same way.
FAIL vs N/A. FAIL means the practice would help here and it is missing — including when a whole artifact is missing, so several questions about it fail together with a one-line proof pointing at the item that found it missing. N/A means the question could never apply to a project of this kind, and the proof says why. "It does not exist" is a FAIL, never an N/A.
Priority is fixed by the template, not by the person filling it in. High means an agent working here will hit this on day one, or the risk is real. Low means it makes things better but nothing breaks without it.
1. Context
-
1. Does an agent instruction file exist (AGENTS.md, CLAUDE.md, .cursorrules, .github/copilot-instructions.md, or this ecosystem's equivalent), and what does it point at? Look for a file whose purpose is to be loaded into a coding agent's context at the start of every session. That file is the entry point. Then follow its pointers: instructions are commonly spread across several files, with the entry point routing to them — "commands are in docs/development.md", "conventions in .claude/rules/". The entry point plus every file it points at is the instruction set, and every other agent-instruction question is answered against that whole set, so list it here in the proof. Follow pointers as deep as they go, but a pointer only counts when it names a target and says what is in it: "test commands are in CONTRIBUTING.md" counts, a bare "see the docs" does not, and a file nothing points at is outside the set however good it is. A README is not an entry point, however good — it gets its credit at the README item and the specs-and-architecture item — but a README the entry point explicitly routes to is inside the set. Vendored skill libraries are not instructions either.
- Status: FAIL
- Proof: No entry point of any kind.
git ls-filesreturns 25 files and none is an agent instruction file; a find across the tree for*agent*,*claude*,*cursor*,*copilot*and.mcp.jsonreturned nothing, and.github/contains onlyworkflows/. The instruction set is empty, so every question below that is answered against it fails with a pointer back to this item. The closest thing in the repo isdocs/notes.txt, which is an untitled scratch list ("ask gio about the db", "marco said we should add tests at some point") that nothing loads and nothing points at. - Recommendation: Create
AGENTS.mdat the repo root with the five things an agent needs on day one: whatshopis, the real build command (./node_modules/.bin/webpack --config webpack.old.config.js --mode production), how to start the server (node server/index.js), the layout ofserver/vssrc/vsbuild/, and the never-do list currently buried indocs/notes.txt. - Priority: High
-
2. Do the agent instructions name the commands to build, test and check this project? Answer this against the instruction set mapped at the entry-point item and nothing outside it. If no entry point exists, FAIL with a one-line proof pointing at that item. The commands may sit in a file the entry point routes to rather than in the entry point itself — that is progressive disclosure working as intended, and it passes. What fails is a command an agent would have to guess its way to: if the commands live only in the README or the manifest and nothing in the set points at them, that is a FAIL, because the question measures what an agent can reach without being told where to look. Name the file each command was found in.
- Status: FAIL
- Proof: No agent instruction file exists — see the entry-point item.
- Recommendation: Blocked by the missing agent instruction file.
- Priority: High
-
3. Does everything the agent instructions name still exist — the commands, the paths, the libraries, and the files they point at? If no entry point exists, FAIL with a one-line proof pointing at the entry-point item. Verify, do not trust: check every named command against the manifest or build file, spot-check the paths, run the cheap read-only ones. Then resolve every pointer in every file of the set — a link to a moved or deleted file is the most common rot in a multi-file instruction set, and it fails silently: the agent reads the entry point, follows nothing, and carries on without the rules.
- Status: FAIL
- Proof: No agent instruction file exists — see the entry-point item. (For the record, the commands that do exist elsewhere are already rotten:
npm start, the one commandREADME.mdgives for running the app, fails withnpm error Missing script: "start"becausepackage.jsondefines only atestscript.) - Recommendation: Blocked by the missing agent instruction file.
- Priority: High
-
4. Are the agent instructions specific to this repo, rather than advice that would read the same in any codebase? If no entry point exists, FAIL with a one-line proof pointing at the entry-point item. The test: could this be pasted into another project unchanged? "Write clean code" and "add tests for new features" would fit anywhere and count for nothing. Judge the whole set, but weigh the files differently: an entry point that is mostly a routing table is fine, even good, when what it routes to is specific — while generic filler in the entry point costs more than generic filler three hops down, because it is loaded into every session whether it is needed or not. Say which files carried the specifics.
- Status: FAIL
- Proof: No agent instruction file exists — see the entry-point item.
- Recommendation: Blocked by the missing agent instruction file.
- Priority: High
-
5. Do the agent instructions explain where things live and how this project is laid out? If no entry point exists, FAIL with a one-line proof pointing at the entry-point item. The map may live in a routed-to file. Judge coverage against the real tree, not against what the files mention: if the set maps one package well but is silent about sibling packages or directories an agent would land in, that is a FAIL with the omission named. In a multi-file set, check the routing too — a layout document nothing points at is a document the agent never opens.
- Status: FAIL
- Proof: No agent instruction file exists — see the entry-point item. Nothing in the repo explains that
server/index.jsandserver/legacy_index.jsare two live servers with different checkout maths, or thatbuild/is generated output that is also committed. - Recommendation: Blocked by the missing agent instruction file.
- Priority: High
-
6. Do the agent instructions state the rules that are not obvious from the code — the things never to do here? If no entry point exists, FAIL with a one-line proof pointing at the entry-point item. These are the tribal-knowledge traps: the flag that must be exactly this string, the import that breaks the build, the directory that is generated and must not be edited. Rules in a routed-to file count. Two extra checks in a multi-file set: that the entry point signposts the rules clearly enough for an agent to open them before it needs them, since a trap found afterwards has already been sprung; and that the files do not contradict each other, because nothing tells the agent which one wins.
- Status: FAIL
- Proof: No agent instruction file exists — see the entry-point item. The traps are real and written down in a file no agent is told to open:
docs/notes.txtsays "do NOT run npm update", "webpack config is the old one but it's the only one that works", and "if the build fails delete node_modules and try again".config.jscarries its own: "NOTE: don't move this file, other stuff imports it with weird paths". - Recommendation: Blocked by the missing agent instruction file.
- Priority: Low
-
7. Has the agent instruction file been updated recently enough to still be true, given how active the repo is? If no agent instruction file exists, FAIL with a one-line proof pointing at the entry-point item. Compare the last commit touching the file against the repo's tempo, then spot-check two or three of its claims against the code — a recently touched file can still lie.
- Status: FAIL
- Proof: No agent instruction file exists — see the entry-point item.
- Recommendation: Blocked by the missing agent instruction file.
- Priority: Low
-
8. Is the agent instruction file small enough to load into every session without crowding out the actual task? If no agent instruction file exists, FAIL with a one-line proof pointing at the entry-point item. Measure it:
wc -c, and bytes divided by four is a fair token estimate. Under ~5k tokens is comfortable; past ~10k it is eating the context window.- Status: FAIL
- Proof: No agent instruction file exists — see the entry-point item.
- Recommendation: Blocked by the missing agent instruction file.
- Priority: Low
-
9. Can a fresh session pick up a half-finished task — is there a file or convention where progress, decisions and what is left get written down? This is not about the agent instruction file. Any durable place in-flight state gets written counts: a TODO.md, a plans or notes directory, task files, linked issues, a specs folder whose entries carry progress and open questions, an agent memory file or directory, a scratchpad or working-notes convention. The test is whether a fresh session could read it and know what was decided and what is left — not what the place is called. Git history alone does not count: it records what happened, not what was decided or what remains.
- Status: FAIL
- Proof: The only candidate is
docs/notes.txt(502 bytes, last touched 2025-02-25 in commite5f31bc). It records open questions and unresolved warnings, not decisions or task state: "ask gio about the db, the staging one has different columns", "the discount thing is broken in one of the two servers, check with accounting", "marco said we should add tests at some point". A fresh session reading it learns what is broken and who to ask, not what was decided or what is left to do. No TODO file, no plans or tasks directory, no issue references in commit messages (git log --oneline -18shows subjects likefix,asdf,.,wip). - Recommendation: Turn
docs/notes.txtinto a real handover file: for each open item, write the decision taken or the question still open plus the next concrete step, and add a "current work in progress" section at the top that a fresh session reads first. - Priority: Low
-
10. Is there a README that says what this project is and how to run it? This is where a good README earns its credit. It needs three things: what the project is, how to run it, and how to check a change. Judge what is on the page, not the file's existence.
- Status: FAIL
- Proof:
README.mdexists (522 bytes) and fails all three. What it is: the description line is literally "TODO: write this". How to run it: the## runsection saysnpm installthennpm start, andnpm startfails —package.jsonhas nostartscript, onlytest. How to check a change: nothing, no test or lint command anywhere on the page. What the page does have is a## deploysection that hands out a live production psql connection string and two production SSH commands — see the human-in-the-way item. - Recommendation: Rewrite
README.md: one paragraph sayingshopis an Express + React storefront, the real run commands (npm install, build with webpack,node server/index.js), and a "check your change" section — and delete the production credentials and SSH commands from the deploy section. - Priority: High
2. Specs
-
11. Is the thinking behind this system written down somewhere durable — a specs, RFC, proposals, design-doc or ADR directory, or architecture notes that record not just what but why? Look for the place and for the convention:
specs/,docs/adr/,rfcs/,proposals/,.specify/, a docs or design folder, architecture notes anywhere in the tree, or this ecosystem's equivalent. Judge substance, not location: "we use X because Y" is a decision, a list of technologies is not, an essay about specs is not a spec, and a docs folder of usage guides with no reasoning is a FAIL whose proof says what was in there instead. Other items are answered against whatever this item finds, so name it precisely — and where forward-looking specs and after-the-fact architecture records live in different places, name both, since a decision log cannot answer a question about acceptance criteria.- Status: FAIL
- Proof: There is no specs, RFC, ADR, proposals or design directory.
docs/holds exactly one file,docs/notes.txt, and it is a nine-line scratch list of warnings and people to ask, with no reasoning in it — the closest it comes to a decision is "webpack config is the old one but it's the only one that works", which records a symptom, not a why. The two biggest open questions in the codebase are unwritten anywhere:server/legacy_index.jssays in a comment "this one applies the discount BEFORE tax, the new one does it after. nobody knows which is right", anddocs/notes.txtsays the staging database has different columns from production. - Recommendation: Create
docs/adr/and write the first three records against decisions already live: why there are two servers (server/index.jsandserver/legacy_index.js), which discount-and-tax order is correct, and whybuild/is committed (commit9ab8dec, "commit build because CI broke"). - Priority: High
-
12. Does the specs directory hold recent entries, or is it an archive nobody has touched? If no specs directory exists, FAIL with a one-line proof pointing at the specs-and-architecture item. Otherwise compare the newest entry's date against the repo's recent activity.
- Status: FAIL
- Proof: No specs directory exists — see the specs-and-architecture item.
- Recommendation: Blocked by the missing specs directory.
- Priority: Low
-
13. Is there a spec template, or an SDD framework, so every spec comes out the same shape? Scaffolding can exist even where no specs directory does — look for a TEMPLATE.md, a
.specify/directory, or framework config. If neither a directory nor any scaffolding exists, FAIL.- Status: FAIL
- Proof: No scaffolding of any kind: no
TEMPLATE.md, no.specify/, no framework config.git ls-fileslists 25 files and the only markdown files areREADME.mdand this report. - Recommendation: Add
docs/adr/TEMPLATE.mdwith four headings — Context, Decision, Consequences, Alternatives rejected — so every record comes out the same shape. - Priority: Low
-
14. Do the specs state acceptance criteria a machine could check? If no specs exist, FAIL with a one-line proof pointing at the specs-and-architecture item. Otherwise open the two newest specs and quote a criterion: "the endpoint returns 403 for expired tokens" is checkable; "the feature works well" is not.
- Status: FAIL
- Proof: No specs exist — see the specs-and-architecture item.
- Recommendation: Blocked by the missing specs directory.
- Priority: High
-
15. Open the newest spec: do its criteria go past the happy path — what happens when a step fails, and how the change gets undone? If no specs exist, FAIL with a one-line proof pointing at the specs-and-architecture item. Look for error cases, edge inputs, and a rollback or undo story, not just the success flow.
- Status: FAIL
- Proof: No specs exist — see the specs-and-architecture item.
- Recommendation: Blocked by the missing specs directory.
- Priority: Low
-
16. Do the specs state non-goals, so an agent knows where to stop? If no specs exist, FAIL with a one-line proof pointing at the specs-and-architecture item. Non-goals written elsewhere (a README's "what this is not" list) are worth naming in the proof, but they do not turn this into a PASS — the question is whether specs carry them.
- Status: FAIL
- Proof: No specs exist — see the specs-and-architecture item. Elsewhere in the tree there are scattered do-not-touch markers that function as ad-hoc non-goals —
server/index.js"login. do not touch, took 3 days to make it work",server/legacy_index.js"OLD SERVER. still deployed on box 2 I think. ask gio before deleting",config.js"old stuff, maybe still used by legacy_index.js? don't delete" — but they are comments in code, not stated non-goals, and each one is hedged with an uncertainty. - Recommendation: Blocked by the missing specs directory.
- Priority: Low
-
17. Can recent shipped work be traced back to a spec? If no specs exist, FAIL with a one-line proof pointing at the specs-and-architecture item. Otherwise take the last few substantial commits or PRs and look for a reference to a spec, an issue, or a design doc in the message or description.
- Status: FAIL
- Proof: No specs exist — see the specs-and-architecture item. No commit references an issue or document either: the last substantial code commits are
ddf3c28"env",d1eb6c2"lint",bebd577"readme",9ab8dec"commit build because CI broke",a315945"hotfix: prod down again, rolling back". - Recommendation: Blocked by the missing specs directory.
- Priority: Low
3. Verification
-
18. Does this project have an automated test suite, in whatever form this ecosystem uses? Work out this ecosystem's convention before concluding anything is missing — check the manifest, the build file, the CI config, the README. A shell script that diffs output files is a test suite. If you find one, run it and record the result.
- Status: FAIL
- Proof: There is no test suite in any form.
package.jsonhas the npm-init placeholder —"test": "echo \"Error: no test specified\" && exit 1"— and runningnpm testprints exactly that and exits 1. No test directory, no*.test.jsor*.spec.jsin the 25 tracked files, no test runner independenciesordevDependencies(the dev deps are eslint, webpack, webpack-cli, babel-loader, @babel/core, @babel/preset-react), no test step in.github/workflows/deploy.yml, no test script anywhere.docs/notes.txtconfirms it: "marco said we should add tests at some point". - Recommendation: Add a test runner and start with the money path:
npm i -D vitest, then writeserver/utils.test.jscoveringcalcTotaland the twoformatPricevariants, and wire"test": "vitest run"inpackage.json. - Priority: High
-
19. Can the test command be discovered without guessing — is it written down where an agent reads? If no test suite exists, FAIL with a one-line proof pointing at the test-suite item. Otherwise check the places an agent looks: the agent instruction file, the README, the manifest's scripts or targets.
- Status: FAIL
- Proof: No test suite exists — see the test-suite item.
- Recommendation: Blocked by the missing test suite.
- Priority: High
-
20. Do the tests assert real behaviour, rather than asserting that a mock was called? If no test suite exists, FAIL with a one-line proof pointing at the test-suite item. Otherwise open the largest test files and read the assertions: calling real code on real inputs passes;
expect(mock).toHaveBeenCalled()as the main dish fails.- Status: FAIL
- Proof: No test suite exists — see the test-suite item.
- Recommendation: Blocked by the missing test suite.
- Priority: High
-
21. Is there a linter or static analysis configured for this language, and does it pass on a clean checkout? Configured is not enough — run it. A linter that exits non-zero on an untouched checkout is a FAIL with the error count in the proof, because an agent cannot tell its own damage from the baseline noise.
- Status: FAIL
- Proof:
.eslintrc.jsonexists with nine rules (no-unused-vars,no-var,eqeqeq,semi,quotes,no-console,no-empty,camelcase,indent). Running it on an untouched clone —npx eslint@8 . --ext .js— ends in✖ 411 problems (411 errors, 0 warnings), of which 377 are auto-fixable. Nothing runs it: there is nolintscript inpackage.jsonand no lint step in.github/workflows/deploy.yml. There is also no.eslintignore, so the committed bundlebuild/bundle.jsis linted as source. - Recommendation: Add
.eslintignorecontainingbuild/, runnpx eslint . --ext .js --fixto clear the 377 mechanical errors, fix or explicitly downgrade the rest, then add"lint": "eslint . --ext .js"topackage.jsonso the baseline is zero and stays there. - Priority: High
-
22. Is there a formatter, so an agent's diffs do not churn on style? Look for the config file and the dependency in this ecosystem's form — .prettierrc, rustfmt, gofmt, black, an .editorconfig doing real work. If the language ships one formatting standard with the toolchain, that is a PASS and the proof says so.
- Status: FAIL
- Proof: No formatter. No
.prettierrcorprettierdependency, no.editorconfig, noformatscript inpackage.json. JavaScript ships no formatting standard with the runtime, so nothing fills the gap by default. ESLint's style rules (semi,quotes,indent) are the only style enforcement and the tree does not obey them — 377 of the 411 lint errors are these fixable style errors, and the existing code mixes both quote styles and both indent widths (server/index.jsuses tabs in the logging middleware and two spaces everywhere else). - Recommendation: Add Prettier (
npm i -D prettier), a.prettierrc, and a"format": "prettier --write ."script, then run it once so every later diff is content instead of whitespace. - Priority: Low
-
23. Is there a compile-time or type-level gate, if this language offers one? N/A only when the language genuinely has no such gate. If the language offers one and the repo does not use it — no strict mode, no typecheck script, no compiler step — that is a FAIL. Run the gate if it exists and record the result.
- Status: FAIL
- Proof: Plain JavaScript has no native type gate, but the ecosystem's standard ones are all available and none is used: no
tsconfig.jsonorjsconfig.jsonwithcheckJS, no// @ts-checkpragma in any file, notypescriptdependency, no JSDoc type annotations. The only build step iswebpack --config webpack.old.config.js, and Babel with@babel/preset-reactstrips JSX without checking anything, so nothing in the pipeline would catch a wrong argument type. - Recommendation: Add a
jsconfig.jsonwith"checkJs": trueplus a"typecheck": "tsc -p jsconfig.json --noEmit"script, and start withserver/utils.jsandserver/db.js— the two files everything else imports. - Priority: Low
-
24. Can an agent prove its own work before it pushes — one command, task-runner target or commit hook that runs every check this project has? One command, not a list to remember: a
checkorverifytarget, aprecommitscript, a Makefile target that chains them. Separate commands documented side by side are close but FAIL — the question is whether the agent can run the whole gauntlet without knowing its parts.- Status: FAIL
- Proof: No aggregate command exists, and none of its parts exist either.
package.jsondefines one script,test, which is the placeholder that exits 1. No Makefile, no justfile, no Taskfile in the 25 tracked files. No git hooks: no.husky/directory, nopre-commitconfig, nopreparescript. - Recommendation: Once
lintandtestscripts exist, add"check": "npm run lint && npm test"topackage.jsonand name it inAGENTS.mdas the one command to run before pushing. - Priority: High
-
25. Is there continuous integration, and does it run before a change lands rather than after? A deploy pipeline that runs on push to the default branch runs after the change has landed — that is a FAIL with the trigger quoted, not a PASS with a caveat. Look for a pre-merge trigger: pull_request events, merge trains, or this forge's equivalent.
- Status: FAIL
- Proof: The only workflow is
.github/workflows/deploy.yml, and its trigger ison: push: branches: [master]— it fires after the change has landed on the default branch. There is nopull_requesttrigger anywhere, and no other workflow file. What it runs is a deploy, not a check: install, webpack build, run every migration against production, rsync to the production box. - Recommendation: Add
.github/workflows/ci.ymltriggeredon: pull_requestrunningnpm ci,npm run lintandnpm test, and turn on a branch protection rule onmasterrequiring it to pass. - Priority: High
-
26. Does CI actually run the tests and the checks that exist in this repo? If no pipeline of any kind exists, FAIL with a one-line proof pointing at the CI item. Otherwise list what the pipeline runs and diff it against every check found in the Verification section — name each check that exists in the repo but is missing from the pipeline.
- Status: FAIL
- Proof:
.github/workflows/deploy.ymlruns four steps —npm install,./node_modules/.bin/webpack --config webpack.old.config.js --mode production, a loop running every file inmigrations/againstsecrets.PROD_DATABASE_URL, and an rsync-plus-restart todeploy@203.0.113.10. Diffed against the checks that exist in the repo, the ESLint configuration in.eslintrc.jsonis never invoked andnpm testis never invoked. Every check this repo owns is missing from the pipeline; the pipeline is pure deployment. - Recommendation: Add
npm run lintandnpm teststeps to the pre-merge CI workflow, and take the migration and rsync steps out of any workflow that runs automatically — see the human-in-the-way item. - Priority: High
-
27. Does anything here get an LLM to read a change and go looking for problems — a review skill, a saved review prompt, or an AI reviewer on the pull requests? Look for a committed review skill or slash command, a CI step calling an AI reviewer, or bot config. Human review rules are a Safety item; this one is specifically about machine review.
- Status: FAIL
- Proof: Nothing. No
.claude/or.agents/directory, no prompts directory, no bot configuration in.github/(it contains onlyworkflows/), and the single workflow's four steps call no reviewer. There is also no pull request flow for a reviewer to attach to — see the CI item. - Recommendation: Once a
pull_requestworkflow exists, add an AI review step to it, or commit a review prompt under.claude/commands/review.mdthat an agent can run on its own diff before pushing. - Priority: Low
4. Tooling
-
28. Can an agent reach the outside systems this project depends on, with that access committed to the repo rather than set up per laptop? MCP servers are one form: look for a committed
.mcp.jsonor this ecosystem's equivalent. A CLI is another and often the better one —aws,gh,psql,kubectl,stripe, a vendor's own tool — and it counts when the repo names which tools the work needs and how to authenticate, so an agent is not guessing at a tool it cannot see. Judge the axis, not the mechanism: access that exists only in someone's shell history or laptop config is a FAIL, and so is a committed config that turns out to be gitignored, with the distinction in the proof. Project task scripts have their own item; this one is about reaching past the repo's edge. If this project genuinely talks to nothing outside itself, N/A with that as the reason.- Status: FAIL
- Proof: This project reaches four outside systems — PostgreSQL, the payments API at
https://payments.shopcorp.net/v1/charge, an SMTP host, and an internal API athttp://10.0.4.19:3000/api(all inconfig.js) — and there is no committed access configuration for any of them: no.mcp.json, no documented CLI setup, no scoped credentials. What exists instead is worse than nothing: the only documented route to the database isREADME.mdhanding out a live production connection string,psql postgres://shop_admin:...@db-prod-01.internal.shopcorp.net:5432/shop. The rest is on one person's laptop —docs/notes.txt: "prod box is 203.0.113.10, key is in gio's ssh folder" and "the cron that calls /api/admin/cleanup is on gio's machine". - Recommendation: Stand up a local or staging database an agent can reach safely, document that connection in
AGENTS.md, and remove the production psql command fromREADME.md. - Priority: Low
-
29. Is there a skills, commands or reusable-prompt library in the repo? Look for .claude/skills, .agents/skills, .claude/commands, or a prompts directory. Committed and pinned beats committed; note whether anything ties the copies to a source.
- Status: FAIL
- Proof: None.
ls -aat the root shows no.claude/, no.agents/, no prompts directory; the only dot-directories are.gitand.github, and.githubcontains onlyworkflows/. - Recommendation: Add
.claude/commands/with the two prompts this repo would use weekly — one that runs the full check gauntlet and reports failures, one that writes a migration together with its down script. - Priority: Low
-
30. Do the skills, servers and tools that exist cover the work this team plainly repeats? First identify the repeated work from the README and the commit history. If skills, servers or documented tooling exist but miss it, FAIL naming the gap. If none exist at all and the repo plainly repeats work, FAIL pointing at the outside-systems item and the skills-library item. If the project is too small to repeat anything, N/A.
- Status: FAIL
- Proof: The repeated work is visible in
git log—5217f97"hotfix prod down",a315945"hotfix: prod down again, rolling back",9ab8dec"commit build because CI broke" — and inREADME.md, which documents restarting the cache and running migrations against production as routine chores. None of it is tooled: no skills library (see the skills-library item) and no committed outside-system access (see the outside-systems item). The recovery procedure for the most repeated event, prod being down, is a raw SSH command pasted in the README. - Recommendation: Blocked by the missing skills library and the missing outside-system access.
- Priority: Low
-
31. Are there project CLI scripts or task-runner targets for the common jobs? Check the manifest's scripts, the Makefile, the justfile, or this ecosystem's equivalent. The test: does routine work need a raw multi-flag command that someone has to remember?
- Status: FAIL
- Proof:
package.jsonhas one script,test, and it is the placeholder that exits 1. There is no Makefile, justfile or Taskfile. Every routine job is a raw command someone has to remember: building means./node_modules/.bin/webpack --config webpack.old.config.js --mode production(found only inside.github/workflows/deploy.yml), starting the server meansnode server/index.js(found only inside the SSH command inREADME.md), and linting means invoking eslint by hand. - Recommendation: Add
start,build,lintandtestscripts topackage.jsonso the commands live in the manifest instead of inside a CI file and an SSH one-liner. - Priority: High
-
32. Are those scripts named somewhere the agent will actually read them? If no scripts exist, FAIL with a one-line proof pointing at the task-scripts item. Otherwise check the agent instruction file, the README, and whether the manifest itself is self-explanatory.
- Status: FAIL
- Proof: No task scripts exist — see the task-scripts item. The one command
README.mddoes name,npm start, does not exist inpackage.jsonand fails when run. - Recommendation: Blocked by the missing task scripts.
- Priority: High
-
33. Can an agent get this project running — is there a reproducible environment or a documented setup path? Look for a pinned runtime (.nvmrc, .tool-versions, rust-toolchain), a lockfile, a container or nix file, and written setup steps. Try the first step if it is cheap and safe. This one bites hardest the moment work happens in a fresh git worktree or a new clone — the normal way to run agents in parallel. A new worktree has no installed dependencies, no
.env, no build cache, so anything that works today only because of untracked state sitting on someone's machine simply does not run there. The test: would a bare checkout plus the written steps get this project up? Name any prerequisite nothing creates — an env file someone hand-made, a seeded database, a manual login — because each one is a wall a worktree hits on its first command.- Status: FAIL
- Proof: A bare checkout plus the written steps does not get this project up. No pinned runtime (
.nvmrc,.tool-versionsabsent; Node 16 appears only inside.github/workflows/deploy.yml), no container or nix file, and no lockfile —.gitignoreactively excludespackage-lock.jsonandyarn.lock, while every dependency is"*"or"latest", so two clones a week apart resolve to different trees. The written steps arenpm installandnpm start, andnpm startfails withMissing script: "start". Prerequisites nothing creates: a reachable PostgreSQL with themigrations/schema applied and seed data, and the payments endpoint atpayments.shopcorp.net.config.jsturns a missing environment into a live incident rather than an error —config.db = process.env.DATABASE_URL || "postgres://shop_admin:...@db-prod-01...", commented "if env is not set we fall back to prod so it always works" — so a fresh worktree that starts the server points at the production database. - Recommendation: Delete the production fallbacks in
config.jsso a missingDATABASE_URLthrows, un-ignore and commitpackage-lock.jsonwith pinned versions, add a.nvmrcwith Node 16, and add adocker-compose.ymlwith PostgreSQL plus a seed step so a fresh clone can run. - Priority: High
-
34. Can an agent see the results of a failed run — do the tools here produce output it can read and act on? Judge from the runs you already did in Verification: does a failure print a path, a line, a name — something actionable — or a wall of noise? If nothing could be run, FAIL saying why.
- Status: FAIL
- Proof: Two things could be run.
npm testproduces no signal at all, onlyError: no test specified.npx eslint@8 .produces genuinely actionable lines (src/index.js 1:8 error 'React' is defined but never used no-unused-vars), but 411 of them on an untouched clone, so an agent cannot separate its own damage from the baseline. At runtime the application is deliberately silent:server/index.jsends withprocess.on('uncaughtException', function (e) { }), contains nine instances ofif (err) { }, andserver/db.jsexportsq2, commented "same as query but swallows errors, used in a few places". A failed request returns{}or a 500 with the bodyerrorand leaves nothing behind to read. - Recommendation: Remove the empty
uncaughtExceptionhandler and the emptyif (err) { }blocks inserver/index.js, deleteq2fromserver/db.js, and log errors with the failing query and stack so a failure prints something an agent can act on. - Priority: Low
5. Safety
-
35. Are credentials kept out of the repo — nothing secret committed, ignore rules in place, an example env file for the shape? Three checks: grep tracked files for key-shaped strings, read the ignore rules for env and key patterns, and look for an example env file. Report each of the three separately.
- Status: FAIL
- Proof: All three fail. (1) Secrets are committed and tracked:
.envappears ingit ls-filesand containsDATABASE_URLwith the production password,SESSION_SECRET,JWT_SECRET,PAYMENTS_API_SECRET,MAIL_PASSWORD=Winter2024!shopcorp,ADMIN_PASSWORD=admin123and S3 keys;config.jshardcodes the same production database URL, jwt secret, session secret, payments key and secret, mail password,adminPasswordandinternalTokenas fallback literals;README.mdembeds the production psql connection string. (2) Ignore rules do not cover them —.gitignoreis five lines (node_modules,package-lock.json,yarn.lock,*.log,.DS_Store) with no.envpattern and no key pattern. (3) There is no.env.exampleor any other template showing the expected shape. - Recommendation: Rotate every credential in
.envandconfig.js— they are in the public git history and rotation is the only fix — thengit rm --cached .env, add.envto.gitignore, commit a.env.examplewith empty values, and delete the hardcoded fallbacks fromconfig.js. - Priority: High
-
36. Does anything scan for secrets automatically? Look for gitleaks, trufflehog, detect-secrets or this ecosystem's equivalent, wherever it is wired in — a CI step, a pre-commit hook, or forge-level push protection visible from the repo. CI is where this normally lives, and that is a PASS; a local hook on top is better, because it catches the key before it is pushed rather than after, but its absence is a line in the proof, not a FAIL. Say where the scan runs. "Nothing secret exists today" does not make this N/A — the scan is for the day that changes.
- Status: FAIL
- Proof: Nothing scans, anywhere.
.github/workflows/deploy.ymlhas four steps and none of them is a scan; there is no gitleaks, trufflehog or detect-secrets config in the tree; there are no git hooks (no.husky/, no.pre-commit-config.yaml, nopreparescript inpackage.json). The consequence is already visible:.envwas committed inddf3c28on 2026-08-03 and nothing objected. - Recommendation: Add a
gitleaksstep to the pre-merge CI workflow and a pre-commit hook running the same scan, so the next key is caught before the push rather than after. - Priority: High
-
37. Are dependencies pinned, so a build is reproducible? Look for lockfiles in every package of the repo, exact versions for load-bearing dependencies, a pinned runtime, and an install command that respects the lock (npm ci, not npm install).
- Status: FAIL
- Proof: Nothing is pinned. There is no lockfile and
.gitignoredeliberately excludes bothpackage-lock.jsonandyarn.lock. Every one of the sixteen dependencies inpackage.jsonfloats:express,body-parser,pg,axios,moment,lodash,request,eslint,webpackand the babel packages are all"*", whilecookie-parser,reactandreact-domare"latest"— so a build today can pull React 19 into code written for React 16 class components. The runtime is unpinned in the repo (Node 16 exists only in the CI workflow) and CI installs withnpm install, notnpm ci. - Recommendation: Replace every
"*"and"latest"with the exact versions currently running in production, removepackage-lock.jsonandyarn.lockfrom.gitignore, commit the lockfile, and change the CI install step tonpm ci. - Priority: High
-
38. Is anything watching those dependencies for known vulnerabilities? Look for dependabot or renovate config, an audit step in CI, or this ecosystem's equivalent. Check every lockfile in the repo is covered, not just the root one.
- Status: FAIL
- Proof: No
.github/dependabot.yml, norenovate.json, nonpm auditstep in.github/workflows/deploy.yml. There is also no lockfile for a scanner to read — see the dependency-pinning item — so even enabling Dependabot today would have nothing to work from. Two dependencies are known-deprecated:request(deprecated since 2020, used in bothserver/index.jsandserver/legacy_index.jsfor the card charge) andmoment(in maintenance mode). - Recommendation: Commit a lockfile, then add
.github/dependabot.ymlfor the npm ecosystem and annpm audit --audit-level=highstep to the pre-merge CI workflow. - Priority: Low
-
39. Are the review rules written down — who reads a change, and what they check? Look for CONTRIBUTING, a PR template, or a review checklist in the agent instruction set. On a solo repo the "who" is N/A-shaped but the "what gets checked before it lands" still matters — judge that half.
- Status: FAIL
- Proof: No
CONTRIBUTING.md, no.github/PULL_REQUEST_TEMPLATE.md, noCODEOWNERS, and no agent instruction set to hold a checklist (see the entry-point item). The "what gets checked" half is empty too: nothing runs before a change lands, because the only workflow triggers on push tomasterafter the fact. This is not a solo repo —docs/notes.txtand the code comments name at least gio, marco and giovanni — so the "who" half applies and is also unwritten. - Recommendation: Add
CONTRIBUTING.mdnaming what must pass before a change lands (lint clean, tests green, no new secrets) and a PR template with those as checkboxes. - Priority: Low
-
40. Are the operations that need a human named somewhere an agent will read them? Look for a "never without asking" list in the agent instruction file or the README. Docs that hand out production commands with no fence around them count against, and the proof should quote one.
- Status: FAIL
- Proof: There is no "never without asking" list anywhere — no agent instruction file (see the entry-point item), and
README.mddoes the opposite. It hands out production commands as routine, with no fence and no warning: "to run a migration on prod:psql postgres://shop_admin:Sup3rSecret_Prod_2024@db-prod-01.internal.shopcorp.net:5432/shop -f migrations/003_drop_old_users.sql" — and that file beginsdelete from users where created_at < '2022-01-01';. It also offers "if the cache goes weird just restart it:ssh deploy@203.0.113.10 "pkill node; ..."". An agent reading this README would reasonably conclude that killing production and deleting user rows are normal steps. - Recommendation: Delete both production commands from
README.md, and put a "never without asking" list inAGENTS.mdcovering anything touching203.0.113.10, anything running against the production database, and any change tomigrations/. - Priority: High
-
41. Does every action that spends money, destroys data or changes production have a human in the way? Start from the damage, not from the tooling: list what in reach of this repo could charge a card, drop or overwrite data, or alter what users are running. Then trace the shortest route an agent could take to each one — a push that auto-deploys, a script carrying live credentials, a migration that runs on merge, an infrastructure apply with no plan-and-approve step. PASS when every route meets a human first, whether that is a review, a manual trigger or a protected environment. FAIL when even one route runs start to finish unattended, and quote that route in the proof so the fix is obvious.
- Status: FAIL
- Proof: Four routes reach real damage and none of them meets a human. (1) A single
git pushtomastertriggers.github/workflows/deploy.yml, which runsfor f in migrations/*.sql; do psql "${{ secrets.PROD_DATABASE_URL }}" -f "$f"; doneagainst production on every push — including003_drop_old_users.sql, whose first statement isdelete from users where created_at < '2022-01-01';. (2) The same run then doesrsync -avz --delete ... deploy@203.0.113.10:/var/www/shop/followed bypkill node, so a bad push takes production down unattended. (3) Any process that can readconfig.jsor.envcan charge cards directly atconfig.payments.endpointwithconfig.payments.secret, both committed. (4)POST /api/admin/cleanupinserver/index.jsrunsdelete from orders where created_at < now() - interval '1 year'with nocheck_admincall at all — it is the only admin route missing the check, anddocs/notes.txtsays a cron on a personal machine calls it. - Recommendation: Take the
migrate prodandship itsteps out of the push-triggered workflow and move them into aworkflow_dispatchjob behind a GitHub protected environment with a required reviewer, and add the missingcheck_admin(req)guard to/api/admin/cleanupinserver/index.js. - Priority: High
-
42. If a prompt injection landed tonight, how far would it reach — are the credentials an agent can get to here scoped to the job, with nothing production-grade in reach? Inventory what an agent in this repo can reach: env files, cloud CLI profiles, tokens named in docs or config, deploy commands that work from a laptop. Scoped-or-absent passes; production-grade reach fails with the item named.
- Status: FAIL
- Proof: Everything in reach is production-grade. From a plain checkout an agent can read
.envandconfig.jsand obtain: the production database URL with theshop_adminpassword, the payments API key and secret that charge real cards, the JWT and session secrets that let it mint any session including an admin one (server/index.jsbuilds tokens asmd5(email + config.jwtSecret)), the SMTP password fornoreply@shopcorp.net,adminPassword = 'admin123', theinternalTokenfor the internal API at10.0.4.19, and S3 upload keys.README.mdadds the production host and the psql and SSH commands to use them, anddocs/notes.txtadds "prod box is 203.0.113.10, key is in gio's ssh folder". Nothing is scoped, nothing is short-lived, andconfig.jsfalls back to production when the environment is unset. - Recommendation: Rotate every credential listed above, remove them from
.envandconfig.jsandREADME.md, and give local work a separate scoped database user and payment sandbox key so nothing production-grade is reachable from a checkout. - Priority: High
-
43. Can a change reach production a slice at a time — a feature flag that defaults to off, a canary, a staged rollout — rather than everyone at once? Look for a flag system and check the default, or canary and staged-rollout config in the deploy pipeline. Flags that need a rebuild to flip are worth naming in the proof — they gate exposure but they are not a kill switch.
- Status: FAIL
- Proof: No flag system, no canary, no staged rollout. There is no flag library in
package.json, no flags section inconfig.js, and no gradual-rollout configuration in.github/workflows/deploy.yml— the deploy isrsync --deleteto a single host followed bypkill node, which swaps every user onto the new code at once with a gap of downtime in between. The only thing resembling a flag isvar flag = falseinserver/index.js, an unused module-level variable. - Recommendation: Deploy behind a flag service or, at minimum, add an environment-variable gate in
config.jsthat defaults to off for new checkout behaviour, so a bad change can be turned off without a redeploy. - Priority: High
-
44. Once a change is live, can anyone see what it is doing — logs, metrics, traces, alerts that fire on their own, and can an agent read them too? Look for logging setup, an error tracker, analytics, alerting config — and then ask the second half: could an agent reach any of it (a CLI, an MCP server, an API named in the docs), or does observability stop at a dashboard behind a login?
- Status: FAIL
- Proof: Observability is one
console.log(req.method + ' ' + req.url)middleware inserver/index.js, redirected to a file by the deploy step (nohup node server/index.js > nohup.out 2>&1 &) and read by a human over SSH —README.md: "if it breaks, ssh in and check:ssh deploy@203.0.113.10...tail -f nohup.out". There is no error tracker, no metrics, no tracing and no alerting config in the repo, and errors never reach the log anyway because they are swallowed (see the failed-run-output item). The/api/statsendpoint returns only in-process counters that reset on every restart, and every restart truncates the picture becausepkill nodeis the deploy. An agent can reach none of it without the production SSH key. - Recommendation: Add an error tracker (Sentry or equivalent) initialised in
server/index.js, replace theconsole.logmiddleware with a structured logger, and record inAGENTS.mdhow an agent can query recent errors without SSH access to the production box. - Priority: Low
-
45. Is there a way back — can a bad change be undone without a rebuild and a redeploy, including the ones that touched a database or a queue? Look for a documented rollback path, a revert-and-redeploy story, down-migrations, or a flag that can turn the change off at runtime. Deployment docs that only say how to go forward are worth quoting.
- Status: FAIL
- Proof: There is no way back.
README.mddocuments only how to go forward — "pushes to master go out automatically" — and its recovery advice is to restart the process, not to revert. Migrations are forward-only:migrations/holds threeNNN_*.sqlfiles with nodowncounterparts, no migration tool, and no version table, and003_drop_old_users.sqlis irreversible by construction (delete from users where created_at < '2022-01-01';,alter table users drop column if exists legacy_id;,drop table if exists users_backup;). There is no runtime flag to turn anything off (see the staged-rollout item), so the only route back is a revert commit plus a full redeploy — and that redeploy would re-run every migration again. History shows this is not theoretical:a315945"hotfix: prod down again, rolling back". - Recommendation: Adopt a migration tool with down scripts, make the deploy run only new migrations rather than the whole directory, and write a rollback section in
README.mdgiving the exact steps to get the previous version live. - Priority: Low
-
46. Does a past failure leave a check behind — is there a test or a rule in here that exists because something broke once? Look for tests, lint rules or comments that name the incident they guard against — "regression", "this broke when", a linked issue. On a very young repo with no failures yet, N/A with the age as the reason.
- Status: FAIL
- Proof: The repo is three and a half years old (first commit
a268ba4, 2023-02-14) and has failed repeatedly —5217f97"hotfix prod down",a315945"hotfix: prod down again, rolling back",2945be0"fix discount",9ab8dec"commit build because CI broke" — and not one of those incidents left a check behind. There are no tests at all (see the test-suite item), no lint rule added in response to an incident (.eslintrc.jsonis nine stock rules), and no CI guard. What the incidents left instead is prose:server/legacy_index.jssays "nobody knows which is right. accounting complained in march",server/utils.jssays "there is another one of these in src/App.js, keep them in sync", andsrc/App.jsrepeats "duplicated from server/utils.js, do not change one without the other" — three known breakages guarded by comments asking a human to remember. - Recommendation: Turn the two documented incidents into tests: one asserting the discount-and-tax order that accounting agreed on, and one asserting
server/utils.jsformatPriceand the copy insrc/App.jsreturn the same string for the same input. - Priority: Low
Learn more: https://ainativesoftware.engineering/
Nothing here is special to alfonsograziano/ai-hostile-repo. Install the skill and ask your agent to run it — it answers the same 46 checks and writes the same file into your repo.
npx skills add alfonsograziano/skills --skill aine-readiness-analyzerAI-Native Software Engineering