mirror of
https://github.com/we-promise/sure.git
synced 2026-09-09 08:34:26 +00:00
* Document instruction inventory and preservation decisions Trace main history from September 2025 through September 2026, including earlier policy origins. Record preserved requirements, detailed-guide destinations, stale facts, harness boundaries and explicit policy-strength decisions before consolidating instruction sources. * Consolidate repository instructions into shared guidance Keep AGENTS concise and vendor neutral, move detailed conventions into shared guides, and use thin adapters with preserved Cursor scopes. Preserve the strict pre-PR checks globally and document the stronger scope, retired migration pin and rule-generation trigger. Update existing API guidance verification without changing application behavior. * Narrow the always-on Cursor UI adapter and correct the SimpleFIN comment Split the design-system guidance out of docs/llm-guides/ui.md into docs/llm-guides/design-system.md. The ui-ux-design-guidelines rule is alwaysApply: true, so importing all of ui.md loaded the Stimulus, localization and ViewComponent guidance (previously confined to scoped rules) on every Cursor session; the always-on adapter now imports only the design-system guide, matching the scope it had before the consolidation. view_conventions and stimulus_conventions keep the full UI guide. Also correct the stale Provider::Simplefin header comment: pending inclusion defaults on and is resolved by the importer (explicit argument, then SIMPLEFIN_INCLUDE_PENDING, then Setting.syncs_include_pending); the previous comment described the flag as default-off. * Read guidance files as UTF-8 in the API consistency validators The frontmatter regex match ran against content read with the locale default external encoding; the Cursor rule's description contains an em dash, so under US-ASCII (LC_ALL=C) Regexp#match raised ArgumentError, breaking the standalone no-Rails fallback the docs point contributors to. Read all checked files with an explicit UTF-8 encoding in both the standalone script and the Rails test.
129 lines
5.9 KiB
Ruby
129 lines
5.9 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
# Standalone verification of the API endpoint consistency implementation (issue #944).
|
|
# Run without loading Rails: ruby test/support/verify_api_endpoint_consistency.rb
|
|
# Or with bundle: bundle exec ruby test/support/verify_api_endpoint_consistency.rb
|
|
#
|
|
# Option: pass --compliance to also scan the current API codebase and report violations
|
|
# (rswag specs using OAuth instead of API key, missing Minitest for API controllers,
|
|
# rswag specs with expect/assert).
|
|
|
|
require "yaml"
|
|
|
|
def project_root
|
|
dir = File.dirname(File.expand_path(__FILE__))
|
|
loop do
|
|
return dir if File.exist?(File.join(dir, "AGENTS.md")) && File.directory?(File.join(dir, "docs", "llm-guides"))
|
|
parent = File.dirname(dir)
|
|
raise "Could not find project root (AGENTS.md + docs/llm-guides)" if parent == dir
|
|
dir = parent
|
|
end
|
|
end
|
|
|
|
def assert(condition, message)
|
|
raise "FAIL: #{message}" unless condition
|
|
end
|
|
|
|
def assert_includes(content, substring, message)
|
|
assert content.include?(substring), "#{message} (missing: #{substring.inspect})"
|
|
end
|
|
|
|
root = project_root
|
|
rule_path = File.join(root, ".cursor", "rules", "api-endpoint-consistency.mdc")
|
|
guide_path = File.join(root, "docs", "llm-guides", "api-endpoint-consistency.md")
|
|
agents_path = File.join(root, "AGENTS.md")
|
|
|
|
assert File.exist?(rule_path), "Rule file should exist at #{rule_path}"
|
|
rule_content = File.read(rule_path, encoding: "UTF-8")
|
|
|
|
frontmatter = rule_content.match(/\A---\r?\n(?<yaml>.*?)\r?\n---\r?\n(?<body>.*)\z/m)
|
|
assert frontmatter, "Rule must start with YAML frontmatter"
|
|
keys = YAML.parse(frontmatter[:yaml]).root.children.each_slice(2).map { |key, _value| key.value }
|
|
assert keys.sort == %w[alwaysApply description globs], "Rule must have exactly one description, globs and alwaysApply key"
|
|
metadata = YAML.safe_load(frontmatter[:yaml])
|
|
expected_globs = [
|
|
"app/controllers/api/v1/**/*.rb",
|
|
"spec/requests/api/v1/**/*.rb",
|
|
"test/controllers/api/v1/**/*.rb"
|
|
]
|
|
assert metadata.fetch("globs").split(",").map(&:strip) == expected_globs, "Rule must retain exactly the API v1 globs"
|
|
assert metadata.fetch("alwaysApply") == false, "Rule must remain scoped, not always applied"
|
|
assert frontmatter[:body].strip == "@docs/llm-guides/api-endpoint-consistency.md", "Rule must import shared checklist"
|
|
assert File.exist?(guide_path), "Shared checklist should exist at #{guide_path}"
|
|
guide_content = File.read(guide_path, encoding: "UTF-8")
|
|
|
|
assert_includes guide_content, "Minitest behavioral coverage", "Shared checklist must include Minitest section"
|
|
assert_includes guide_content, "test/controllers/api/v1/{resource}_controller_test.rb", "Shared checklist must specify Minitest location"
|
|
assert_includes guide_content, "api_headers", "Shared checklist must mention api_headers"
|
|
assert_includes guide_content, "X-Api-Key", "Shared checklist must mention X-Api-Key"
|
|
assert_includes guide_content, "rswag is docs-only", "Shared checklist must include rswag docs-only section"
|
|
assert_includes guide_content, "run_test!", "Shared checklist must mention run_test!"
|
|
assert_includes guide_content, "rswag:specs:swaggerize", "Shared checklist must mention swaggerize task"
|
|
assert_includes guide_content, "Same API key auth", "Shared checklist must include API key auth section"
|
|
assert_includes guide_content, "ApiKey.generate_secure_key", "Shared checklist must show API key pattern"
|
|
assert_includes guide_content, "plain_key", "Shared checklist must mention plain_key"
|
|
assert_includes guide_content, "Doorkeeper", "Shared checklist must mention Doorkeeper (to avoid OAuth in specs)"
|
|
|
|
assert File.exist?(agents_path), "AGENTS.md should exist"
|
|
agents_content = File.read(agents_path, encoding: "UTF-8")
|
|
assert_includes agents_content, "Post-commit API consistency", "AGENTS.md must reference post-commit checklist"
|
|
assert_includes agents_content, "docs/llm-guides/api-endpoint-consistency.md", "AGENTS.md must link to shared checklist"
|
|
assert_includes agents_content, "Minitest", "AGENTS.md must mention Minitest"
|
|
assert_includes agents_content, "rswag", "AGENTS.md must mention rswag"
|
|
assert_includes agents_content, "X-Api-Key", "AGENTS.md must mention X-Api-Key"
|
|
|
|
puts "OK: API endpoint consistency implementation verified (shared checklist + scoped adapter + AGENTS.md)."
|
|
|
|
if ARGV.include?("--compliance")
|
|
puts "\n--- Compliance check (current APIs) ---"
|
|
spec_dir = File.join(root, "spec", "requests", "api", "v1")
|
|
test_dir = File.join(root, "test", "controllers", "api", "v1")
|
|
app_controllers_dir = File.join(root, "app", "controllers", "api", "v1")
|
|
|
|
rswag_oauth = []
|
|
rswag_assertions = []
|
|
missing_minitest = []
|
|
|
|
if File.directory?(spec_dir)
|
|
Dir.glob(File.join(spec_dir, "*_spec.rb")).each do |path|
|
|
basename = File.basename(path, "_spec.rb")
|
|
next if basename == "auth"
|
|
content = File.read(path, encoding: "UTF-8")
|
|
if content.include?("Doorkeeper") || content.include?("Bearer") || content.include?("access_token")
|
|
rswag_oauth << "#{basename}_spec.rb"
|
|
end
|
|
rswag_assertions << "#{basename}_spec.rb" if content.include?("expect(") || content.include?("assert_")
|
|
end
|
|
end
|
|
|
|
skip_controllers = %w[base_controller test_controller]
|
|
if File.directory?(app_controllers_dir)
|
|
Dir.glob(File.join(app_controllers_dir, "*_controller.rb")).each do |path|
|
|
basename = File.basename(path, ".rb")
|
|
next if skip_controllers.include?(basename)
|
|
test_path = File.join(test_dir, "#{basename}_test.rb")
|
|
missing_minitest << basename unless File.exist?(test_path)
|
|
end
|
|
end
|
|
|
|
if rswag_oauth.any?
|
|
puts "rswag using OAuth (should use API key per rule): #{rswag_oauth.join(", ")}"
|
|
else
|
|
puts "rswag auth: all specs use API key."
|
|
end
|
|
|
|
if rswag_assertions.any?
|
|
puts "rswag with expect/assert (should be docs-only): #{rswag_assertions.join(", ")}"
|
|
else
|
|
puts "rswag: no expect/assert found (docs-only)."
|
|
end
|
|
|
|
if missing_minitest.any?
|
|
puts "API v1 controllers missing Minitest: #{missing_minitest.join(", ")}"
|
|
else
|
|
puts "Minitest: all API v1 controllers have a test file."
|
|
end
|
|
|
|
puts "---"
|
|
end
|