diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..933ad81 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true +charset = utf-8 +indent_style = space +indent_size = 4 + +[*.{yml,yaml,md}] +indent_size = 2 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..6313b56 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6d4e43a --- /dev/null +++ b/.gitignore @@ -0,0 +1,230 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[codz] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py.cover +*.lcov +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +# Pipfile.lock + +# uv +# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# uv.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +# poetry.lock +# poetry.toml + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python. +# https://pdm-project.org/en/latest/usage/project/#working-with-version-control +# pdm.lock +# pdm.toml +.pdm-python +.pdm-build/ + +# pixi +# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control. +# pixi.lock +# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one +# in the .venv directory. It is recommended not to include this directory in version control. +.pixi/* +!.pixi/config.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule* +celerybeat.pid + +# Redis +*.rdb +*.aof +*.pid + +# RabbitMQ +mnesia/ +rabbitmq/ +rabbitmq-data/ + +# ActiveMQ +activemq-data/ + +# SageMath parsed files +*.sage.py + +# Environments +.env +.envrc +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs/Zensical documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +# .idea/ + +# Abstra +# Abstra is an AI-powered process automation framework. +# Ignore directories containing user credentials, local state, and settings. +# Learn more at https://abstra.io/docs +.abstra/ + +# Visual Studio Code +# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore that +# can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore +# and can be added to the global gitignore or merged into this file. However, if you prefer, you +# could uncomment the following to ignore the entire vscode folder +# .vscode/ +# Temporary file for partial code execution +tempCodeRunnerFile.py + +# Ruff stuff: +.ruff_cache/ + +# PyPI configuration file +.pypirc + +# Marimo +marimo/_static/ +marimo/_lsp/ +__marimo__/ + +# Streamlit +.streamlit/secrets.toml + +# Project specific +# Local secrets, personal use only (never imported by the project) +.env +# Generated API documentation (doxygen Doxyfile) +/docs/api/ +# Scratch output of local and Docker runs; published screenshots live in docs/images/ +/runs/ +# AI prompt log: this repository is public +/docs/ai-prompts/ diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 0000000..32d92a4 --- /dev/null +++ b/Doxyfile @@ -0,0 +1,374 @@ +# Doxyfile 1.15.0 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = "Cookie Clicker Bot" +PROJECT_NUMBER = +PROJECT_BRIEF = "Selenium bot for Cookie Clicker (Udemy 100 Days of Code, day 48)" +PROJECT_LOGO = +PROJECT_ICON = +OUTPUT_DIRECTORY = docs/api +CREATE_SUBDIRS = NO +CREATE_SUBDIRS_LEVEL = 8 +ALLOW_UNICODE_NAMES = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = YES +JAVADOC_BANNER = NO +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +PYTHON_DOCSTRING = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 4 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = YES +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +OPTIMIZE_OUTPUT_SLICE = NO +EXTENSION_MAPPING = +MARKDOWN_SUPPORT = YES +MARKDOWN_STRICT = YES +TOC_INCLUDE_HEADINGS = 6 +MARKDOWN_ID_STYLE = DOXYGEN +AUTOLINK_SUPPORT = YES +AUTOLINK_IGNORE_WORDS = +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES +DISTRIBUTE_GROUP_DOC = NO +GROUP_NESTED_COMPOUNDS = NO +SUBGROUPING = YES +INLINE_GROUPED_CLASSES = NO +INLINE_SIMPLE_STRUCTS = NO +TYPEDEF_HIDES_STRUCT = NO +LOOKUP_CACHE_SIZE = 0 +NUM_PROC_THREADS = 1 +TIMESTAMP = NO +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = NO +EXTRACT_PRIV_VIRTUAL = NO +EXTRACT_PACKAGE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +RESOLVE_UNNAMED_PARAMS = YES +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_UNDOC_NAMESPACES = YES +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = SYSTEM +HIDE_SCOPE_NAMES = NO +HIDE_COMPOUND_REFERENCE= NO +SHOW_HEADERFILE = YES +SHOW_INCLUDE_FILES = YES +SHOW_GROUPED_MEMB_INC = NO +FORCE_LOCAL_INCLUDES = NO +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_MEMBERS_CTORS_1ST = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +STRICT_PROTO_MATCHING = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_FILES = YES +SHOW_NAMESPACES = YES +FILE_VERSION_FILTER = +LAYOUT_FILE = +CITE_BIB_FILES = +EXTERNAL_TOOL_PATH = +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = YES +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_IF_INCOMPLETE_DOC = YES +WARN_NO_PARAMDOC = NO +WARN_IF_UNDOC_ENUM_VAL = NO +WARN_LAYOUT_FILE = YES +WARN_AS_ERROR = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LINE_FORMAT = "at line $line of file $file" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = src README.md +INPUT_ENCODING = UTF-8 +INPUT_FILE_ENCODING = +FILE_PATTERNS = *.py +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +FILTER_SOURCE_PATTERNS = +USE_MDFILE_AS_MAINPAGE = README.md +IMPLICIT_DIR_DOCS = YES +FORTRAN_COMMENT_AFTER = 72 +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +REFERENCES_LINK_SOURCE = YES +SOURCE_TOOLTIPS = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +CLANG_ASSISTED_PARSING = NO +CLANG_ADD_INC_PATHS = YES +CLANG_OPTIONS = +CLANG_DATABASE_PATH = +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_EXTRA_STYLESHEET = +HTML_EXTRA_FILES = +HTML_COLORSTYLE = AUTO_LIGHT +HTML_COLORSTYLE_HUE = 220 +HTML_COLORSTYLE_SAT = 100 +HTML_COLORSTYLE_GAMMA = 80 +HTML_DYNAMIC_MENUS = YES +HTML_DYNAMIC_SECTIONS = NO +HTML_CODE_FOLDING = YES +HTML_COPY_CLIPBOARD = YES +HTML_PROJECT_COOKIE = +HTML_INDEX_NUM_ENTRIES = 100 +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_FEEDURL = +DOCSET_BUNDLE_ID = org.doxygen.Project +DOCSET_PUBLISHER_ID = org.doxygen.Publisher +DOCSET_PUBLISHER_NAME = Publisher +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +CHM_INDEX_ENCODING = +BINARY_TOC = NO +TOC_EXPAND = NO +SITEMAP_URL = +GENERATE_QHP = NO +QCH_FILE = +QHP_NAMESPACE = org.doxygen.Project +QHP_VIRTUAL_FOLDER = doc +QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = +QHG_LOCATION = +GENERATE_ECLIPSEHELP = NO +ECLIPSE_DOC_ID = org.doxygen.Project +DISABLE_INDEX = NO +GENERATE_TREEVIEW = YES +PAGE_OUTLINE_PANEL = YES +FULL_SIDEBAR = NO +ENUM_VALUES_PER_LINE = 4 +SHOW_ENUM_VALUES = NO +TREEVIEW_WIDTH = 250 +EXT_LINKS_IN_WINDOW = NO +OBFUSCATE_EMAILS = YES +HTML_FORMULA_FORMAT = png +FORMULA_FONTSIZE = 10 +FORMULA_MACROFILE = +USE_MATHJAX = NO +MATHJAX_VERSION = MathJax_2 +MATHJAX_FORMAT = HTML-CSS +MATHJAX_RELPATH = +MATHJAX_EXTENSIONS = +MATHJAX_CODEFILE = +SEARCHENGINE = YES +SERVER_BASED_SEARCH = NO +EXTERNAL_SEARCH = NO +SEARCHENGINE_URL = +SEARCHDATA_FILE = searchdata.xml +EXTERNAL_SEARCH_ID = +EXTRA_SEARCH_MAPPINGS = +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = +MAKEINDEX_CMD_NAME = makeindex +LATEX_MAKEINDEX_CMD = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4 +EXTRA_PACKAGES = +LATEX_HEADER = +LATEX_FOOTER = +LATEX_EXTRA_STYLESHEET = +LATEX_EXTRA_FILES = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +LATEX_BIB_STYLE = plainnat +LATEX_EMOJI_DIRECTORY = +#--------------------------------------------------------------------------- +# Configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +RTF_EXTRA_FILES = +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_SUBDIR = +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_PROGRAMLISTING = YES +XML_NS_MEMB_FILE_SCOPE = NO +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- +GENERATE_DOCBOOK = NO +DOCBOOK_OUTPUT = docbook +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# Configuration options related to Sqlite3 output +#--------------------------------------------------------------------------- +GENERATE_SQLITE3 = NO +SQLITE3_OUTPUT = sqlite3 +SQLITE3_RECREATE_DB = YES +#--------------------------------------------------------------------------- +# Configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +EXTERNAL_PAGES = YES +#--------------------------------------------------------------------------- +# Configuration options related to diagram generator tools +#--------------------------------------------------------------------------- +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +DOT_NUM_THREADS = 0 +DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10" +DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10" +DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4" +DOT_FONTPATH = +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +UML_LIMIT_NUM_FIELDS = 10 +UML_MAX_EDGE_LABELS = 10 +DOT_UML_DETAILS = NO +DOT_WRAP_THRESHOLD = 17 +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DIR_GRAPH_MAX_DEPTH = 1 +DOT_IMAGE_FORMAT = png +INTERACTIVE_SVG = NO +DOT_PATH = +DOTFILE_DIRS = +DIA_PATH = +DIAFILE_DIRS = +PLANTUML_JAR_PATH = +PLANTUML_CFG_FILE = +PLANTUML_INCLUDE_PATH = +PLANTUMLFILE_DIRS = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 0 +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +MSCGEN_TOOL = +MSCFILE_DIRS = diff --git a/docs/adr/adr-0001-selenium-runtime-dependency.md b/docs/adr/adr-0001-selenium-runtime-dependency.md new file mode 100644 index 0000000..4ff1407 --- /dev/null +++ b/docs/adr/adr-0001-selenium-runtime-dependency.md @@ -0,0 +1,56 @@ +# Selenium as the single runtime dependency + +## Metadata +| Key | Value | +| --- | --- | +| ID | ADR-0001 | +| CrossReference | [BC-001], [SA-001] | + +## Version History +| Date | Status | Author | Reviewer | Change | Commit | +| --- | --- | --- | --- | --- | --- | +| 2026-10-28 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version (reviewed in RC-009) | [ad3334f] | + +Allowed Status values: `Proposed`, `Accepted`, `Rejected`, `Deprecated`, `Superseded by ADR-NNNN`. + +--- + +## Context + +The assignment is to automate the Cookie Clicker game in a real browser with Selenium ([BC-001], objective O1). GitHub viewers (S03) asked for no runtime dependencies (concern CN-006 in [SA-001]), and the Business Case constraint says to avoid runtime dependencies unless needed. The bot must read the page and click elements, so something has to drive a browser. + +Options evaluated: + +1. **Selenium** as the one runtime dependency. It is what the assignment and the course use, and Selenium Manager downloads a matching driver. +2. **No dependency**, driving Chrome through the DevTools protocol with the standard library only. This needs a hand-written WebSocket client and protocol code, which is long, fragile and unreadable for S02. +3. **Playwright**. A comparable dependency, but not the library of the assignment, so S02 could not compare solutions. +4. **Selenium plus a threading helper** (the author's earlier solution used `continuous_threading`). A second dependency for something the standard library `threading` or a single loop already does. + +## Decision + +Selenium is the only runtime dependency; pytest, ruff and mypy are development dependencies, and everything else uses the standard library. + +## Consequences + +**Positive:** + +- The code matches the assignment, so S02 can compare solutions directly. +- Only one package is installed to run the bot (`pip install .`). +- The decision logic is behind a port, so tests need neither Selenium nor a browser. + +**Negative:** + +- S03's wish for no dependencies is met only in part; the README states why Selenium is needed. +- Running the bot needs Chrome installed (Selenium Manager fetches the driver); the Docker image covers this for the screenshots. +- Performance Efficiency: Selenium calls cost milliseconds each, which limits the clicks per second. + +## Affected Artifacts + +- [BC-001] — fixes the runtime dependency list for success criterion 4. +- [SA-001] — records the mitigation of the conflict between CN-006 and the assignment. + +--- + +[BC-001]: ../business-case.md +[SA-001]: ../stakeholder-analysis.md +[ad3334f]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/048-the-coockie-factory/commit/ad3334fa13c4261c3d034fbffcc7b43fe95fbb31 diff --git a/docs/artifact-registry.md b/docs/artifact-registry.md index 5fcec41..a112fe8 100644 --- a/docs/artifact-registry.md +++ b/docs/artifact-registry.md @@ -15,9 +15,9 @@ document of a type. `Primary File` may contain a glob (e.g. | SA | Stakeholder Analysis | docs/stakeholder-analysis.md | 002 | | PP | Project Plan | docs/project-plan.md | 002 | | MIL | Milestone / Gateway | docs/milestones/mil-*.md | 006 | -| ADR | Architecture Decision Record | docs/adr/adr-*.md | 0001 | +| ADR | Architecture Decision Record | docs/adr/adr-*.md | 0002 | | TM | Traceability Matrix | docs/sqa/traceability-matrix.md | 002 | -| RC | SQA Review Record | docs/sqa/reviews/rc-*.md | 009 | +| RC | SQA Review Record | docs/sqa/reviews/rc-*.md | 011 | ## Languages diff --git a/docs/sqa/reviews/rc-009-adr-0001-selenium-runtime-dependency.md b/docs/sqa/reviews/rc-009-adr-0001-selenium-runtime-dependency.md new file mode 100644 index 0000000..dcc43df --- /dev/null +++ b/docs/sqa/reviews/rc-009-adr-0001-selenium-runtime-dependency.md @@ -0,0 +1,55 @@ +# SQA Review Record + +## Metadata +| Key | Value | +| --- | --- | +| ID | RC-009 | +| CrossReference | [ADR-0001], [QC-ADR-001] | + +## Version History +| Date | Status | Author | Reviewer | Change | Commit | +| --- | --- | --- | --- | --- | --- | +| 2026-10-28 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [ad3334f] | + +--- + +## Artifact Under Review + +- Instance reviewed: ADR-0001 ([ADR-0001]) +- Checklist used: [QC-ADR-001] +- Scope: full review +- Language and domain: n/a (technical type) +- Language reviewer: none +- Mode: autonomous, not independent (the reviewer is `AI as stand-in for S01`) + +## Checklist Results + +| # | Criterion | Status | Evidence/Notes | +| --- | --- | --- | --- | +| 1 | The ID (`ADR-NNNN`, 4-digit) matches the filename number and is unique and sequential | Pass | ID ADR-0001 matches the file name adr-0001 and is the first. | +| 2 | Context states the problem, the forces (cost, risk, constraints) and the options evaluated | Pass | Context names the forces (S03 concern, constraint) and four options. | +| 3 | At least two options were considered, or the absence of alternatives is justified | Pass | Four options evaluated. | +| 4 | Decision is stated in one or two unhedged sentences and matches one of the evaluated options | Pass | One sentence, matches option 1. | +| 5 | Consequences list both Positive and Negative outcomes | Pass | Positive and Negative lists present. | +| 6 | Quality-attribute impacts (performance, security, portability, etc.) are named where the decision affects them | Pass | Performance Efficiency cost of Selenium calls named. | +| 7 | Affected Artifacts are listed as links, and each is also in CrossReference | Pass | BC-001 and SA-001 are linked and in CrossReference. | +| 8 | Status changes are recorded as new Version History rows with a Change summary and Commit link; retained rows are never rewritten | Pass | Single row with Change and Commit columns. | +| 9 | A superseded or deprecated ADR names its successor, and the successor links back | N-A | Not superseded. | +| 10 | Written in business or technical language of the domain, with no unexplained abbreviations | Pass | Abbreviation Selenium is a product name; others spelled out. | +| 11 | Status is one of `Proposed`, `Accepted`, `Rejected`, `Deprecated` or `Superseded by ADR-NNNN`, and every Version History row uses only these | Pass | Status Accepted. | + +## Overall Verdict + +Go - All Mandatory criteria pass. Stand-in review, not independent. + +## Action Items + +| Action | Owner | Due | +| --- | --- | --- | +| None | S01 | - | + +--- + +[ADR-0001]: ../../adr/adr-0001-selenium-runtime-dependency.md +[QC-ADR-001]: ../../../framework/qc/artifacts/qc-adr.md +[ad3334f]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/048-the-coockie-factory/commit/ad3334fa13c4261c3d034fbffcc7b43fe95fbb31 diff --git a/docs/sqa/reviews/rc-010-mil-001-source.md b/docs/sqa/reviews/rc-010-mil-001-source.md new file mode 100644 index 0000000..1ed242c --- /dev/null +++ b/docs/sqa/reviews/rc-010-mil-001-source.md @@ -0,0 +1,62 @@ +# SQA Review Record + +## Metadata +| Key | Value | +| --- | --- | +| ID | RC-010 | +| CrossReference | [MIL-001], [QC-PY-001] | + +## Version History +| Date | Status | Author | Reviewer | Change | Commit | +| --- | --- | --- | --- | --- | --- | +| 2026-10-28 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [ad3334f] | + +--- + +## Artifact Under Review + +- Instance reviewed: source of milestone MIL-001 (src/cookie_clicker_bot, tests/, pyproject.toml) ([MIL-001]) +- Checklist used: [QC-PY-001] +- Scope: full review +- Language and domain: n/a (technical type) +- Language reviewer: none +- Mode: autonomous, not independent (the reviewer is `AI as stand-in for S01`) + +## Checklist Results + +| # | Criterion | Status | Evidence/Notes | +| --- | --- | --- | --- | +| 1 | Packages, modules, functions, variables, classes and constants follow PEP 8 casing (`snake_case`, `PascalCase`, `UPPER_SNAKE`) | Pass | snake_case modules, UPPER_SNAKE constants. | +| 2 | Names state purpose in the domain's language; no unexplained abbreviations, no single-letter names outside tiny scopes | Pass | Names state purpose (RUN_DURATION_SECONDS). | +| 3 | Code is produced by the project's formatter and passes its linter with no unexplained suppressions | Pass | `ruff check src tests` reports no findings; ruff configured in pyproject.toml. | +| 4 | Every function and method signature is type-annotated, including `-> None` | Pass | Test functions annotated with -> None; constants annotated. | +| 5 | No bare `except:`, no swallowed exceptions; specific exceptions are raised and the cause is kept (`raise ... from`) | N-A | No exception handling in this milestone. | +| 6 | No mutable default arguments and no shadowed builtins | Pass | None present. | +| 7 | Files, locks and connections are managed with context managers | N-A | No files or connections yet. | +| 8 | Public modules, classes and functions have docstrings that say what, not how | Pass | Module docstrings use Doxygen @file/@brief. | +| 9 | Logging uses `logging`, not `print`; no secrets or personal data in log output | N-A | No logging yet. | +| 10 | Classes and operations trace to the Design Class Diagram they implement; deviations are recorded | N-A | Plain technical task; no Design Class Diagram exists or is required. | +| 11 | Tests exist for new behaviour, are named for the behaviour, and do not depend on order or the network | Pass | tests/unit/test_constants.py runs offline; `pytest` passes 2 tests. | +| 12 | Type checker runs in strict mode without errors; `Any` is justified in a comment | Pass | mypy strict configured; no Any. | +| 13 | Dependencies are declared and pinned in the project's dependency file, none unused | Pass | selenium>=4.25 is the only runtime dependency (ADR-0001). | +| 14 | Each piece of knowledge (a business rule, constant, format, validation or query) is defined in one place; code is merged only where it expresses the same knowledge, not where it merely looks alike | Pass | Timing constants defined once in constants.py. | +| 15 | Imports point inward: business-rule modules import no framework, database, UI or delivery-mechanism code, and there are no import cycles | Pass | Layer packages exist; no cross imports yet. | +| 16 | SOLID holds: a class or module has one reason to change; new behaviour is added by extension, not by editing a type test in several places; subclasses honour the contract of their base; protocols are narrow; high-level code depends on protocols or abstract types and receives its implementations | N-A | No classes yet. | +| 17 | Source is laid out in the layers and folders of the clean architecture folder structure (`domain`, `application`, `infrastructure`, `presentation` packages under `src/`, and `unit`, `integration` and `e2e` under `tests/`), in `snake_case`, and imports between the layers point inward | Pass | domain, application, infrastructure and presentation under src/; unit, integration and e2e under tests/. | +| 18 | File and folder names are English, contain no space and no character outside letters, digits, `-`, `_` and `.`, and follow the casing of the language for files | Pass | All names English, snake_case, no spaces. | + +## Overall Verdict + +Go - All Mandatory criteria pass or are not applicable to this skeleton. Stand-in review, not independent. + +## Action Items + +| Action | Owner | Due | +| --- | --- | --- | +| None | S01 | - | + +--- + +[MIL-001]: ../../milestones/mil-001-project-setup.md +[QC-PY-001]: ../../../framework/qc/code/qc-programming-python.md +[ad3334f]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/048-the-coockie-factory/commit/ad3334fa13c4261c3d034fbffcc7b43fe95fbb31 diff --git a/docs/sqa/traceability-matrix.md b/docs/sqa/traceability-matrix.md index 063887d..a92b6c5 100644 --- a/docs/sqa/traceability-matrix.md +++ b/docs/sqa/traceability-matrix.md @@ -10,6 +10,7 @@ | Date | Status | Author | Reviewer | Change | Commit | | --- | --- | --- | --- | --- | --- | | 2026-10-28 | Proposed | Jens Tirsvad Nielsen | | Initial version | [96a9a78] | +| 2026-10-28 | Proposed | Jens Tirsvad Nielsen | AI as stand-in for S01 | Added ADR-0001, RC-009 and RC-010 | [ad3334f] | --- @@ -26,11 +27,12 @@ updated whenever an artifact instance is created or reviewed. | [BC-001] | BC | en | it | - | [SA-001], [PP-001] | [RC-001] | | [SA-001] | SA | en | it | [BC-001] | [PP-001] | [RC-002] | | [PP-001] | PP | en | it | [BC-001], [SA-001] | [MIL-001], [MIL-002], [MIL-003], [MIL-004], [MIL-005] | [RC-003] | -| [MIL-001] | MIL | en | it | [PP-001] | [MIL-002] | [RC-004] | +| [MIL-001] | MIL | en | it | [PP-001] | [MIL-002], [ADR-0001] | [RC-004], [RC-010] | | [MIL-002] | MIL | en | it | [MIL-001] | [MIL-003] | [RC-005] | | [MIL-003] | MIL | en | it | [MIL-002] | [MIL-004] | [RC-006] | | [MIL-004] | MIL | en | it | [MIL-003] | [MIL-005] | [RC-007] | | [MIL-005] | MIL | en | it | [MIL-004] | - | [RC-008] | +| [ADR-0001] | ADR | - | - | [BC-001], [SA-001], [MIL-001] | - | [RC-009] | ## Concern Coverage @@ -41,7 +43,7 @@ updated whenever an artifact instance is created or reviewed. | CN-003 | [MIL-002] | - | - | Covered | | CN-004 | [MIL-004] | - | - | Covered | | CN-005 | [MIL-001] | - | - | Covered | -| CN-006 | [MIL-001] | - | - | Covered | +| CN-006 | [MIL-001] | [ADR-0001] | - | Covered | | CN-007 | [MIL-005] | - | - | Covered | ## Open Inconsistencies @@ -53,6 +55,7 @@ updated whenever an artifact instance is created or reviewed. --- [BC-001]: ../business-case.md +[ADR-0001]: ../adr/adr-0001-selenium-runtime-dependency.md [SA-001]: ../stakeholder-analysis.md [PP-001]: ../project-plan.md [MIL-001]: ../milestones/mil-001-project-setup.md @@ -69,3 +72,6 @@ updated whenever an artifact instance is created or reviewed. [RC-007]: ./reviews/rc-007-mil-004-screenshots-and-readme.md [RC-008]: ./reviews/rc-008-mil-005-wiki-and-release.md [96a9a78]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/048-the-coockie-factory/commit/96a9a78f010ce8ae3fce8d84602317d8b5808a13 +[RC-009]: ./reviews/rc-009-adr-0001-selenium-runtime-dependency.md +[RC-010]: ./reviews/rc-010-mil-001-source.md +[ad3334f]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/048-the-coockie-factory/commit/ad3334fa13c4261c3d034fbffcc7b43fe95fbb31 diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..93c0505 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,55 @@ +[build-system] +requires = ["setuptools>=75"] +build-backend = "setuptools.build_meta" + +[project] +name = "cookie-clicker-bot" +version = "0.1.0" +description = "A Selenium bot that plays Cookie Clicker for five minutes and reports its cookies per second (Udemy 100 Days of Code, day 48)." +readme = "README.md" +requires-python = ">=3.13" +license = "AGPL-3.0-or-later" +license-files = ["LICENSE"] +keywords = ["selenium", "cookie-clicker", "automation", "udemy", "100-days-of-code"] +classifiers = [ + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.13", + "Intended Audience :: Education", +] +dependencies = [ + "selenium>=4.25", +] + +[project.optional-dependencies] +dev = [ + "pytest>=8", + "ruff>=0.6", + "mypy>=1.11", +] + +[project.scripts] +cookie-clicker-bot = "cookie_clicker_bot.presentation.cli:main" + +[project.urls] +Repository = "https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/048-the-coockie-factory" + +[tool.setuptools.packages.find] +where = ["src"] + +[tool.pytest.ini_options] +testpaths = ["tests"] +pythonpath = ["src"] +addopts = "-ra" + +[tool.ruff] +line-length = 88 +target-version = "py313" +src = ["src", "tests"] + +[tool.ruff.lint] +select = ["E", "F", "I", "N", "UP", "B"] + +[tool.mypy] +strict = true +python_version = "3.13" +mypy_path = "src" diff --git a/src/cookie_clicker_bot/__init__.py b/src/cookie_clicker_bot/__init__.py new file mode 100644 index 0000000..5e19b36 --- /dev/null +++ b/src/cookie_clicker_bot/__init__.py @@ -0,0 +1,3 @@ +"""@file +@brief Cookie Clicker bot: a Selenium player for the Cookie Clicker browser game. +""" diff --git a/src/cookie_clicker_bot/application/__init__.py b/src/cookie_clicker_bot/application/__init__.py new file mode 100644 index 0000000..683fac1 --- /dev/null +++ b/src/cookie_clicker_bot/application/__init__.py @@ -0,0 +1,3 @@ +"""@file +@brief Application layer: the bot's use cases and the ports they need. +""" diff --git a/src/cookie_clicker_bot/constants.py b/src/cookie_clicker_bot/constants.py new file mode 100644 index 0000000..799889c --- /dev/null +++ b/src/cookie_clicker_bot/constants.py @@ -0,0 +1,14 @@ +"""@file +@brief Constants shared by every layer of the bot. + +Game specific values (URL, element ids) are added with the code that uses them. +""" + +## Seconds the bot plays before it reads the cookies per second (lecture step 5). +RUN_DURATION_SECONDS: int = 300 + +## Seconds between two looks at the store while the bot keeps clicking. +STORE_CHECK_INTERVAL_SECONDS: int = 5 + +## Seconds to wait for an element before the bot gives up. +ELEMENT_TIMEOUT_SECONDS: int = 20 diff --git a/src/cookie_clicker_bot/domain/__init__.py b/src/cookie_clicker_bot/domain/__init__.py new file mode 100644 index 0000000..c21abd2 --- /dev/null +++ b/src/cookie_clicker_bot/domain/__init__.py @@ -0,0 +1,3 @@ +"""@file +@brief Domain layer: game rules that know nothing about Selenium. +""" diff --git a/src/cookie_clicker_bot/infrastructure/__init__.py b/src/cookie_clicker_bot/infrastructure/__init__.py new file mode 100644 index 0000000..b317e2f --- /dev/null +++ b/src/cookie_clicker_bot/infrastructure/__init__.py @@ -0,0 +1,3 @@ +"""@file +@brief Infrastructure layer: the Selenium adapter that implements the game port. +""" diff --git a/src/cookie_clicker_bot/presentation/__init__.py b/src/cookie_clicker_bot/presentation/__init__.py new file mode 100644 index 0000000..2023559 --- /dev/null +++ b/src/cookie_clicker_bot/presentation/__init__.py @@ -0,0 +1,3 @@ +"""@file +@brief Presentation layer: the command line entry point. +""" diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..9144c7f --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1,2 @@ +"""@file +@brief Tests for the Cookie Clicker bot.""" diff --git a/tests/e2e/__init__.py b/tests/e2e/__init__.py new file mode 100644 index 0000000..c9fb4a6 --- /dev/null +++ b/tests/e2e/__init__.py @@ -0,0 +1,2 @@ +"""@file +@brief End to end tests (headless Chrome in Docker only).""" diff --git a/tests/integration/__init__.py b/tests/integration/__init__.py new file mode 100644 index 0000000..3310ad7 --- /dev/null +++ b/tests/integration/__init__.py @@ -0,0 +1,2 @@ +"""@file +@brief Tests that cross a boundary.""" diff --git a/tests/unit/__init__.py b/tests/unit/__init__.py new file mode 100644 index 0000000..ea0c067 --- /dev/null +++ b/tests/unit/__init__.py @@ -0,0 +1,2 @@ +"""@file +@brief Tests of the pure logic (no browser needed).""" diff --git a/tests/unit/test_constants.py b/tests/unit/test_constants.py new file mode 100644 index 0000000..cfe8742 --- /dev/null +++ b/tests/unit/test_constants.py @@ -0,0 +1,13 @@ +"""@file +@brief Guards the timing constants the bot relies on. +""" + +from cookie_clicker_bot import constants + + +def test_run_duration_is_five_minutes() -> None: + assert constants.RUN_DURATION_SECONDS == 300 + + +def test_store_check_happens_inside_the_run() -> None: + assert 0 < constants.STORE_CHECK_INTERVAL_SECONDS < constants.RUN_DURATION_SECONDS