diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..39d4bb3 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,135 @@ +# OpenTag3D agent guide + +Guidance for AI coding agents working in this repository. This file owns routing, hard boundaries, co-change rules, and minimal verification. Deeper procedures live in `_docs/` and nested `AGENTS.md` files. + +## What this repo is + +OpenTag3D is an open, community-driven specification for RFID/NFC tags on 3D-printer filament spools. This repository is the public home for the spec and the source for the [opentag3d.info](https://opentag3d.info) Jekyll site. + +The repo is a website, but it publishes a binary data contract. Some edits are fixed by the next deploy; others are written onto physical tags or consumed by third-party firmware/apps. Match caution to blast radius. + +The spec defines hardware, mechanical placement, on-tag data structure, and an optional Web API. Tag data must remain authoritative offline; the Web API can never become required for reading a tag. + +Spec governance belongs to the OpenTag3D Consortium described in `about.md`. Site/code fixes are normal PR work; `core` field layout and version changes are standards decisions. + +## Where to start + +| If you're... | Read first | Key rule | +| --- | --- | --- | +| A new/outside contributor or their agent | `_docs/contributor-agent-guide.md` | Propose high-blast-radius changes; do not silently change the spec contract. | +| The maintainer or a trusted maintainer-directed agent | `_docs/maintainer-runbooks.md` | Use runbooks for triage, review, release, and context upkeep. | +| Editing site content/supporters | This file's gotchas and co-change map | Supporter data can live in two places. | +| Editing `make.html` / `read.html` | `_docs/make-read-tools.md` and `assets/scripts/AGENTS.md` | Pages expect `globalThis.OpenTag3D.spec` before shared code runs. | +| Touching `assets/scripts/opentag3d.js` | `assets/scripts/AGENTS.md` | Round-trip verify; Web NFC/config pages require extra caution. | +| Touching `_data/spec.json` | `_data/AGENTS.md` | Classify the edit first; `core` layout is a proposal, not a casual commit. | +| Cutting a version/release | `_docs/spec-change-process.md` | Maintainer-only unless explicitly delegated. | +| "Fixing" something that seems missing | `_docs/known-gaps.md` | Known gaps are not unprompted work. | + +## Tech stack + +- Jekyll 4.4 with the `minimal-mistakes-jekyll` theme. +- Markdown/YAML front matter plus a few raw HTML pages. +- Vanilla browser ES modules; no JS bundler/framework. +- Node/npm is used for Prettier formatting only. +- Web NFC requires a secure browser context for real tag reads/writes. + +## The spec is data-driven + +Edit `_data/spec.json`, not root `spec.json`. + +- `_data/spec.json` is the source of truth for version, MIME type, `core` byte fields, and `web_api` fields. +- `spec.md`, `_includes/spec_table.md`, and `_includes/memory_map.html` render human-readable spec pages from `site.data.spec`. +- Root `spec.json` is a Jekyll page that publishes `site.data.spec` at `/spec.json`. +- `assets/json/spec_v*.json` files are frozen legacy snapshots used by `opentag3d.js` to decode old major versions. + +## Directory map + +| Path | Purpose | +| --- | --- | +| `*.md`, `*.html` | Jekyll pages and tools | +| `_docs/` | Unpublished agent/contributor reference docs | +| `_data/` | Site/spec data; read `_data/AGENTS.md` before editing spec/supporter data | +| `_includes/` | Liquid partials/templates | +| `_sass/` | Theme overrides | +| `assets/scripts/` | Shared browser JS; read `assets/scripts/AGENTS.md` before protocol edits | +| `assets/json/` | Frozen legacy spec snapshots; do not edit casually | +| `articles/` | Blog-style posts, linked manually | +| `.github/workflows/` | Build, format, and Pages deploy workflows | + +## Build, dev, and verification + +Common commands: + +```bash +bundle exec jekyll build +npm run format:check +npm run format +``` + +Local HTTPS dev server, per `README.md`: + +```bash +./setup.sh +npm start +``` + +Verify by change type: + +| Change type | Minimum verification | +| --- | --- | +| Markdown/content/Liquid | `bundle exec jekyll build`; browser check if rendered layout matters | +| `js`/`scss`/`json`/`yml`/`yaml` | `npm run format:check` | +| `make.html` / `read.html` UI | Jekyll build plus browser check of affected flow | +| `opentag3d.js` protocol logic | Node round-trip recipe in `assets/scripts/AGENTS.md` plus browser check | +| `_data/spec.json` | `_data/AGENTS.md` checklist, changelog, byte-map checks as applicable | +| Web NFC write/config behavior | Ask first; verify with supported Chrome/Android/Web NFC and a disposable tag, or state not locally verified | + +CI runs Jekyll build and Prettier checks. GitHub Pages deploys `main` to production; there is no staging environment in this repo. + +## Boundaries + +Always: + +- Edit `_data/spec.json`, never root `spec.json`, when changing spec data. +- Pair `_data/spec.json` changes with a `spec.md` changelog entry. +- Keep Jekyll build and `npm run format:check` green for touched file types. +- Keep tag data usable offline; the Web API is supplemental only. + +Ask first: + +- Any `core` field layout, requiredness, size, meaning, or top-level `version` change. +- NTAG config-page, AUTH0/PWD/PACK, or Web NFC write-path edits. +- Adding a supporter without matching issue/maintainer context. +- Workflow, `Gemfile`, `package.json`, or release-process changes. + +Never: + +- Push directly to `main`; it is production. +- Create or push git tags unless the maintainer explicitly instructs you. +- Edit an existing `assets/json/spec_v*.json` casually. +- Make the Web API required for tag interpretation. +- Edit consortium/governance membership in `about.md` unprompted. + +## Co-change map + +| When you change... | Also update/check... | +| --- | --- | +| `_data/spec.json` anything | `spec.md` changelog | +| `_data/spec.json` `version`, major bump | New frozen `assets/json/spec_v{oldMajor}.json` before current layout changes | +| `_data/spec.json` `core` layout | Byte-map stamp/table in `_docs/spec-data-model.md` | +| Supporter status/details | `_data/supporters.yml` and affected `getting-started.md` tables | +| New article | A link from somewhere; articles are not auto-listed | +| Workflows, scripts, directories, or agent-routing assumptions | This file and the owning `_docs/` page | + +## Gotchas + +- Root `spec.json` and `_data/spec.json` have different roles. The root file publishes data; `_data/spec.json` is the editable source. +- `make.html` and `read.html` depend on an inline Jekyll script setting `globalThis.OpenTag3D.spec` before `opentag3d.js` evaluates. +- Existing `assets/json/spec_v*.json` snapshots support tags already in the field. +- `getting-started.md` duplicates some supporter/product data by hand. +- New `articles/` pages are not discovered automatically. +- There are no automated protocol tests yet; verification evidence matters. + +## Keeping context current + +If an agent doc is wrong, fix it in the same PR as the work that exposed the problem. If you add a rule, put it in the one place it belongs and link to it; see `_docs/decisions.md`. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..43c994c --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/README.md b/README.md index 17ee4fd..1726ab5 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,8 @@ Want to provide a financial contribution? Donate to the Gooborg Studios' founder ## Website Development +Contributor and AI-agent notes: see [`AGENTS.md`](./AGENTS.md) and [`_docs/`](./_docs/). + To start a local version of the website for development, you will need Node.js and Ruby. Run the `setup.sh` script to run the setup commands, and then `npm start` to start the web server. > [!NOTE] diff --git a/_config.yml b/_config.yml index 897f5dd..d013280 100644 --- a/_config.yml +++ b/_config.yml @@ -26,6 +26,12 @@ og_image: /assets/images/og_image.jpg atom_feed: hide: true +exclude: + - AGENTS.md + - CLAUDE.md + - assets/scripts/AGENTS.md + - OpenTag3D-agent-scaffolding/ + defaults: - scope: path: "" diff --git a/_data/AGENTS.md b/_data/AGENTS.md new file mode 100644 index 0000000..1dcb10d --- /dev/null +++ b/_data/AGENTS.md @@ -0,0 +1,41 @@ +# `_data/` agent notes + +This file owns local rules for data files. Root `AGENTS.md` routes here before spec/supporter data edits. + +## `spec.json`: classify the edit first + +`_data/spec.json` is the editable source for the public spec data. The root `spec.json` page is generated from it; do not edit root `spec.json` to change the spec. + +| Edit class | Typical version effect | Agent posture | +| --- | --- | --- | +| Description or wording clarification | patch | Do it when requested; add a `spec.md` changelog entry. | +| New `web_api` field | minor | Do it when requested; add changelog; flag as a spec change in PR notes. | +| New `core` field in unused space | minor | Draft as a proposal; maintainer/consortium decides. | +| Move, resize, remove, or reinterpret a `core` field | major/breaking | Proposal only; legacy snapshot requirement applies. | +| Top-level `version` change | release-dependent | Ask first unless explicitly assigned by maintainer. | + +## `core` field checklist + +Before changing any `core.fields` byte layout, read `_docs/spec-data-model.md` and verify: + +- `type` is implemented by `encodeFieldValue()` and `decodeTagBuffer()` in `assets/scripts/opentag3d.js`: `int`, `utf8`, `ascii`, `rgba`, `date`, or `time`. +- No byte range overlaps another field. +- `start` + `length` fits inside `core.address_range`. +- `id` remains unique and stable unless the change is explicitly breaking. +- `added` is set to the introducing spec version. +- `_data/spec.json` and `spec.md` changelog change together. +- Major bumps freeze the old layout into `assets/json/spec_v{oldMajor}.json` before current fields move. + +Unrecognized `core` types can fail silently during decode. Jekyll build success is not proof a spec edit is safe. + +## `supporters.yml` + +Supporter entries should come from a GitHub issue or maintainer direction. The enum lists at the top of the file are authoritative for `category` and `implstage` values. + +Some supporter/product facts are duplicated by hand in `getting-started.md` tables. When a requested supporter edit affects those tables, update both files or say clearly why only one changed. + +Do not add or change consortium/governance membership in `about.md` as part of a supporter-data task unless explicitly asked. + +## `navigation.yml` + +Navigation changes are site UX changes. Verify the target page/link exists and run the normal Jekyll build/format checks. diff --git a/_docs/AGENTS.md b/_docs/AGENTS.md new file mode 100644 index 0000000..fd0d470 --- /dev/null +++ b/_docs/AGENTS.md @@ -0,0 +1,11 @@ +# Agent reference docs + +These docs are unpublished working context for contributors and AI coding agents. Start at root `AGENTS.md`; use this index when a task needs deeper context. + +- [`contributor-agent-guide.md`](contributor-agent-guide.md): outside-contributor safety model and escalation rules. +- [`maintainer-runbooks.md`](maintainer-runbooks.md): trusted maintainer workflows for review, triage, releases, and context upkeep. +- [`make-read-tools.md`](make-read-tools.md): architecture and verification expectations for `make.html`, `read.html`, and page-local tool code. +- [`spec-data-model.md`](spec-data-model.md): `_data/spec.json` field model, type enum, byte budget, and recompute command. +- [`spec-change-process.md`](spec-change-process.md): observed path from spec idea to release/deploy. +- [`known-gaps.md`](known-gaps.md): known missing automation/process gaps with safe workarounds; not an unprompted work queue. +- [`decisions.md`](decisions.md): settled agent-context decisions and rationale. diff --git a/_docs/contributor-agent-guide.md b/_docs/contributor-agent-guide.md new file mode 100644 index 0000000..b50ce74 --- /dev/null +++ b/_docs/contributor-agent-guide.md @@ -0,0 +1,52 @@ +# Contributor and agent guide + +This guide is for outside contributors and their AI agents. It owns the safety posture for non-maintainer work; detailed protocol checklists live in `_data/AGENTS.md` and `assets/scripts/AGENTS.md` once those files are added. + +## Safety model + +OpenTag3D is both a website and a published data contract. Some edits are fixed by the next deploy; others affect bytes written to physical NFC tags or implementations that consume `/spec.json`. + +If in doubt, open a proposal or ask first. Do not silently change the spec contract. + +## Usually routine changes + +These are usually safe when the requested change is clear: + +- Prose fixes in Markdown pages. +- Link or copy updates with an obvious source of truth. +- Small styling changes, verified with a Jekyll build and browser check. +- Supporter updates when there is matching issue or maintainer context, and all duplicated locations are kept in sync. + +Still run the relevant verification and say what you checked in the PR notes. + +## Changes that need extra context + +- `_data/spec.json`: read `_data/AGENTS.md` and classify the edit before changing anything. +- `make.html` or `read.html`: read [`make-read-tools.md`](make-read-tools.md); shared protocol changes also require `assets/scripts/AGENTS.md`. +- `assets/scripts/opentag3d.js`: treat byte encode/decode, NDEF/NTAG packing, import/export, and Web NFC as protocol work. +- Releases, tags, spec version bumps, workflows, `Gemfile`, and `package.json`: ask first unless the maintainer explicitly assigned the task. + +## Propose, do not silently implement + +Open a proposal or stop for maintainer direction before: + +- Changing `core` field layout, field sizes, requiredness, or the spec `version`. +- Editing Web NFC write behavior or NTAG config pages. +- Editing legacy snapshots in `assets/json/spec_v*.json`. +- Making the web API required for tag interpretation; offline tag data is authoritative. +- Changing governance/consortium records in `about.md` unprompted. + +## Co-change reminders + +Use the co-change map in root `AGENTS.md` once added. Until then, key pairs are: + +- `_data/spec.json` changes need a `spec.md` changelog entry. +- Major spec bumps need a frozen legacy snapshot before the current layout changes. +- Supporter status/details may appear in both `_data/supporters.yml` and `getting-started.md`. +- New articles are not auto-listed; link them intentionally from somewhere. + +## Known gaps are not a work queue + +[`known-gaps.md`](known-gaps.md) documents missing automation, suspected findings, and manual workarounds so agents do not rediscover them. It is not permission to fix those items unprompted. + +When you encounter a known gap, follow its "Meanwhile" line. If it blocks the requested work, report that and ask how to proceed. diff --git a/_docs/decisions.md b/_docs/decisions.md new file mode 100644 index 0000000..aaf8ece --- /dev/null +++ b/_docs/decisions.md @@ -0,0 +1,81 @@ +# Agent-context decisions + +Short decision log for agent scaffolding. Format: Decision · Why · Revisit when. + +## Tiered agent context + +Decision: use root `AGENTS.md`, nested `AGENTS.md` files in `_data/` and `assets/scripts/`, and reference docs in `_docs/`. +Why: a single root file would have to carry every checklist and would be too large for routine work. +Revisit when: tooling or repo structure makes local checklists unnecessary. + +## `_docs/` for reference docs + +Decision: keep agent reference docs in `_docs/`. +Why: Jekyll ignores underscore-prefixed directories by default, it matches the repo's `_data`/`_includes` idiom, and it avoids publishing agent context as website content. +Revisit when: Jekyll configuration changes to publish `_docs/` or the maintainer wants a different private-doc location. + +## Known gaps stay short and in-repo for now + +Decision: keep a neutral [`known-gaps.md`](known-gaps.md) with safe workarounds; convert items to GitHub issues only if the maintainer asks. +Why: agents need the "meanwhile" guidance to avoid rediscovering gaps or fixing them opportunistically. +Revisit when: the maintainer chooses an issue-tracking workflow. + +## `AGENTS.md` is canonical; `CLAUDE.md` is a shim + +Decision: root `AGENTS.md` is the cross-tool source. `CLAUDE.md` should only import it. +Why: multiple agent tools read `AGENTS.md`; duplicating guidance would drift. +Revisit when: tool conventions change. + +## Root README pointer + +Decision: add one root `README.md` line pointing contributors/agents to `AGENTS.md` and `_docs/`. +Why: humans browsing the repo need a visible entry point. +Revisit when: a future `CONTRIBUTING.md` becomes the better entry point. + +## One PR with separable commits + +Decision: land the reflow as one PR split into independently reviewable commits. +Why: two PRs would ship temporary duplication first; separable commits still let the maintainer drop pieces. +Revisit when: review requests a narrower PR. + +## Agent docs describe the repo, not one machine + +Decision: do not add Windows-local dev-server notes to root agent rules. +Why: they would document one contributor environment and go stale. +Revisit when: the maintainer wants a supported Windows/WSL development guide. + +## No guessed house-style section yet + +Decision: do not invent PR or house-style conventions before maintainer review teaches them. +Why: process details are currently undocumented and should not be guessed from history. +Revisit when: this PR review reveals stable conventions. + +## One home per fact + +Decision: each operational fact should have one owning doc; other docs link to it. +Why: duplicated warnings like "main is production" and "no tests" drift and bloat context. +Revisit when: a fact is repeated often enough that its ownership is unclear. + +## Point, do not copy + +Decision: agent docs point to source files for volatile/public facts instead of restating them. +Why: consortium membership, version semantics, field lists, and changelog details already have public homes. +Revisit when: a source file lacks enough context for safe agent work. + +## Separate stable from volatile + +Decision: stable architecture can be prose; volatile facts need verification stamps or recompute commands. +Why: byte maps, counts, line numbers, and versions go stale quickly. +Revisit when: scripts/CI replace manual commands. + +## Rules, not research + +Decision: final agent docs state what to do and why, not how the fact was discovered. +Why: research narrative belongs in git history and planning commits. +Revisit when: provenance is needed for a specific disputed decision. + +## Mechanical rules should migrate into checks + +Decision: prose checklists are temporary homes for rules that can eventually be scripted. +Why: executable checks reduce context load and review burden. +Revisit when: adding or changing a checklist item that could be automated. diff --git a/_docs/known-gaps.md b/_docs/known-gaps.md new file mode 100644 index 0000000..1d8a86b --- /dev/null +++ b/_docs/known-gaps.md @@ -0,0 +1,71 @@ +# Known gaps + +These gaps are context and safe-workaround notes, not an unprompted work queue. Do not fix one unless the maintainer asked for it or it directly blocks the assigned task. + +### No CONTRIBUTING.md — status: needs maintainer decision + +Why it matters: first-time contributors cannot see the expected PR, review, or spec-proposal path in one place. +Meanwhile, agents should: use [`contributor-agent-guide.md`](contributor-agent-guide.md) and ask when process authority is unclear. +Do not: invent maintainer policy or branch rules. + +### Consortium vote trail is not visible in-repo — status: needs maintainer confirmation + +Why it matters: `about.md` describes consortium approval for spec changes, but the checkout does not show how approvals map to PRs. +Meanwhile, agents should: treat `core` spec changes and major bumps as proposals requiring human confirmation. +Do not: create vote logs, issue templates, or governance process unprompted. + +### Release/version drift is unchecked — status: idea + +Why it matters: `_data/spec.json` version, `spec.md` changelog, legacy snapshots, homepage announcement, and git tags are manually coordinated. +Meanwhile, agents should: follow [`spec-change-process.md`](spec-change-process.md) and call out every touched/untouched release surface. +Do not: create tags or release automation without maintainer direction. + +### Merge rights and review process are unconfirmed — status: needs maintainer confirmation + +Why it matters: branch protection and merge rights are GitHub settings, not files in the repo. +Meanwhile, agents should: avoid assuming who can merge or approve; ask if it matters to the task. +Do not: infer policy from commit history alone. + +### No automated protocol tests — status: idea + +Why it matters: `opentag3d.js` handles byte encoding/decoding, NDEF/NTAG packing, import/export formats, and Web NFC with no test suite. +Meanwhile, agents should: use the manual/Node round-trip guidance in `assets/scripts/AGENTS.md` once added and include verification evidence. +Do not: refactor protocol code opportunistically. + +### No schema or byte-range validation for `_data/spec.json` — status: idea + +Why it matters: bogus types, overlaps, out-of-range fields, and missing legacy snapshots can pass build/format checks. +Meanwhile, agents should: use [`spec-data-model.md`](spec-data-model.md)'s byte-map command and `_data/AGENTS.md` once added. +Do not: treat a passing Jekyll build as proof a spec edit is safe. + +### Suspected 6-byte `barcode` integer round-trip issue — status: needs maintainer confirmation + +Why it matters: planning suggested large multi-byte integers may interact with 32-bit shift behavior. +Meanwhile, agents should: reproduce with the suspected-protocol-bug triage flow in [`maintainer-runbooks.md`](maintainer-runbooks.md), present bytes and decoded values, and ask for confirmation. +Do not: patch integer packing/reading as a side quest. + +### Remaining `core` byte budget is manual — status: idea + +Why it matters: only 24 bytes are free as of spec v2.003, and no script enforces the budget. +Meanwhile, agents should: recompute gaps with [`spec-data-model.md`](spec-data-model.md)'s command before proposing `core` fields. +Do not: choose field offsets by inspection only. + +### Supporter tables duplicate `_data/supporters.yml` — status: idea + +Why it matters: `getting-started.md` tables and structured supporter data can drift. +Meanwhile, agents should: update both places when a requested supporter change affects both. +Do not: add supporters without issue context or maintainer direction. + +### Link, Markdown, and content cross-reference checks are minimal — status: idea + +Why it matters: Markdown formatting, outbound links, navigation targets, supporter logo paths, and data enums are not comprehensively checked in CI. +Meanwhile, agents should: manually check links/data paths touched by the task. +Do not: broaden a content edit into CI tooling unless asked. + +### No staging or post-deploy smoke test — status: idea + +Why it matters: `main` deploys to production through GitHub Pages. +Meanwhile, agents should: build locally/CI and use browser checks for rendered behavior when relevant. +Do not: push to `main` or change deploy workflows without maintainer instruction. + +Ideas, not proposals: article/feed automation, supporter-intake PR automation, Discord announcements, Windows dev-server notes, and CODE_OF_CONDUCT norms may be useful later if the maintainer wants them. diff --git a/_docs/maintainer-runbooks.md b/_docs/maintainer-runbooks.md new file mode 100644 index 0000000..1f5d7c1 --- /dev/null +++ b/_docs/maintainer-runbooks.md @@ -0,0 +1,52 @@ +# Maintainer runbooks + +This doc owns trusted maintainer workflows. Use it only when acting as the maintainer or as a maintainer-directed agent; it is procedure support, not new policy. + +## Review an agent-generated PR + +Review by blast radius first, file diff second: + +1. Classify the change: routine content, tool UI, protocol code, spec data, release/process, governance, or automation. +2. Check the co-change map in root `AGENTS.md` once added. +3. For `_data/spec.json`, classify the edit before reviewing details: wording, `web_api`, additive `core`, breaking `core`, or version bump. +4. For protocol-code changes, require round-trip evidence and browser/manual evidence appropriate to the path touched. +5. For Web NFC write/config-page changes, require maintainer intent and real-device evidence or an explicit "not locally verified" note. +6. For release or governance changes, confirm the human decision trail before accepting repo edits. +7. If review teaches a new repo convention, record it in [`decisions.md`](decisions.md) or the one doc where that rule belongs. + +Prefer shrinking future review burden: when a prose checklist becomes mechanical, move it toward a script or CI check and shorten the docs. + +## Triage a suspected protocol bug + +Treat protocol bugs as suspected until reproduced and confirmed. + +1. Identify the area: display-only UI, field encode/decode, NDEF/NTAG packing, Web NFC write, config pages, import/export, or legacy-spec handling. +2. Build the smallest reproduction. Use the Node recipe in `assets/scripts/AGENTS.md` once added when the path does not require DOM or Web NFC. +3. Compare behavior against `_data/spec.json`, `spec.md`, and relevant `assets/json/spec_v*.json` legacy snapshots. +4. Separate "new writes would be wrong" from "already-written tags may be affected". +5. Present bytes, decoded values, expected behavior, and uncertainty; ask the maintainer to confirm before patching. + +Example target: a suspected 6-byte `barcode` integer round-trip issue. Reproduce it, show the exact encoded bytes and decoded value, and ask whether the observed behavior is incorrect before changing `packInt()` or decode logic. + +## Release/version bump checklist + +The full process lives in [`spec-change-process.md`](spec-change-process.md). Maintainer-level reminders: + +- Confirm the spec change is approved through the appropriate human process before editing the repo. +- Update `_data/spec.json` `version` and the `spec.md` changelog together. +- For a major bump, freeze the old major layout into `assets/json/spec_v{oldMajor}.json` before changing current fields. +- Review whether `index.md`'s announcement banner should be updated or retired. +- Tags are maintainer-owned release markers; do not delegate tag creation to an agent without explicit instruction. + +## Context upkeep + +After each agent-docs or process-affecting PR: + +- Fix agent docs in the same PR if they were wrong or incomplete. +- Put each new rule in exactly one owning doc and link to it elsewhere. +- Record durable rationale in [`decisions.md`](decisions.md). +- If a new script or CI check replaces a manual rule, shrink the prose to point at the executable check. + +## Unknowns to keep explicit + +The checkout does not confirm branch protection, merge rights, release authority, or how consortium votes are recorded. Ask the maintainer rather than inferring these from commit history. diff --git a/_docs/make-read-tools.md b/_docs/make-read-tools.md new file mode 100644 index 0000000..e2769b3 --- /dev/null +++ b/_docs/make-read-tools.md @@ -0,0 +1,78 @@ +# Make/read tools architecture + +This doc owns architecture context for `make.html`, `read.html`, and their page-local JavaScript. Protocol-code danger zones and the Node round-trip recipe live in `assets/scripts/AGENTS.md` once added. + +## Boot sequence and spec injection + +Both tool pages are Jekyll-rendered pages. Before importing shared code, they inject the current spec: + +```html + +``` + +`assets/scripts/opentag3d.js` reads `globalThis.OpenTag3D.spec` at module evaluation time. Do not reorder imports or remove this bootstrap unless the shared module is refactored to accept the spec explicitly. + +## Responsibility map + +- `_data/spec.json`: source of truth for field ids, types, offsets, lengths, scaling, descriptions, and version. +- `make.html`: form UX, form state, required-field validation, encoding orchestration, write/export/share UI. +- `read.html`: read/import UI, optional-field suppression, friendly display rendering. +- `assets/scripts/opentag3d.js`: protocol encode/decode, NDEF/NTAG packing, Web NFC, import/export formats, legacy-version loading. +- `assets/scripts/site.js`: DOM helper `h()`, flash messages `msg()`, dropdown button menus. + +Use page-local code for presentation and user-flow glue. Byte-level or format-level transformations belong in shared protocol code and need protocol verification. + +## `make.html` flow + +1. Jekyll injects `_data/spec.json` into `globalThis.OpenTag3D.spec`. +2. The page imports shared helpers and gets `allFields` from the active spec. +3. `renderForm()` builds inputs from spec fields, skipping `tag_version`. +4. User input, URL params, example fill, or imports update page-local state. +5. `buildMemory()` validates required fields, calls `encodeFieldValue()`, writes bytes into the payload buffer, updates the hex dump/hash/filename, and prepares outputs. +6. User writes through Web NFC or exports raw `.bin`, Proxmark3 `.bin`, Flipper `.nfc`, NFC Tools JSON, clipboard hex, or share links. + +Import-to-edit follows the reverse path: read/load/import text, parse with shared helpers, `decodeTagBuffer()`, push decoded values into inputs, then rebuild the payload. + +## `read.html` flow + +1. Jekyll injects the spec and the page imports parsing/decoding/Web NFC helpers. +2. User loads file/clipboard/`?hex=`, or Web NFC scanning starts automatically where supported. +3. Shared helpers normalize the source into payload bytes. +4. `loadBufferIntoDisplay()` shows a hex dump and calls `decodeTagBuffer()`. +5. `decodeTagBuffer()` reads `tag_version`, loads an old major snapshot when needed, and returns values plus warnings. +6. `renderTag()` applies display rules, suppresses unset optional defaults with `fieldValue()`, and fills the friendly UI. + +## Important shared function areas + +In `opentag3d.js`, use function/section names rather than line numbers when discussing code: + +- Constants/state: `SPEC`, `allFields`, `NFC_INFO`, `nfcController`. +- Encoding/byte utilities: `packInt()`, `parseHex()`, `bufferFromText()`, `bufferToHex()`, `hexdump()`, `generateHash()`. +- Field logic: `encodeFieldValue()`, `decodeTagBuffer()`, `getFieldsForMajorVersion()`. +- Web NFC: `writeViaWebNFC()`, `readViaWebNFC()`, `startAutomaticWebNFC()`, `cancelWebNFC()`. +- NTAG/NDEF/export/import: `buildNtagPageDump()`, Flipper, Proxmark3, NFC Tools builders/parsers, `parseImportedText()`. + +## Danger zones + +Slow down or ask first around: + +- Spec bootstrap/import order. +- `_data/spec.json` `core` layout and `tag_version` semantics. +- Legacy snapshots in `assets/json/spec_v*.json`. +- `packInt()`/decode integer width handling. +- Web NFC writes and `NFC_INFO.ntag.types.*.configPages`. +- NDEF/NTAG packing and external import/export formats. +- NFC Tools mobile payload handling. +- Required vs optional display semantics in `read.html`. +- Share-link and URL parameter serialization in `make.html`. + +## Verification expectations + +- UI-only change: Jekyll build, browser-load affected page, check console, and exercise affected controls. +- Encode/decode or import/export change: use the Node round-trip recipe from `assets/scripts/AGENTS.md` once added, plus browser verification through `/make` and `/read`. +- Web NFC write/config-page change: ask first; verify on a supported Chrome/Android/Web NFC setup with a disposable tag, or state clearly that real NFC was not locally verified. +- Legacy decode change: include the old major-version snapshot and sample payload used for verification. + +No automated test suite currently covers these flows, so verification evidence in PR notes matters. diff --git a/_docs/spec-change-process.md b/_docs/spec-change-process.md new file mode 100644 index 0000000..5ed1eb0 --- /dev/null +++ b/_docs/spec-change-process.md @@ -0,0 +1,52 @@ +# Spec change process + +This doc owns the observed path from spec idea to production. It describes what can be seen from the repo and labels unknown process details as unknown. + +## Governance touchpoint + +`about.md` describes the OpenTag3D Consortium: voting members evaluate spec-modification proposals, and non-voting members may propose changes. It points people to Discord and direct maintainer contact. + +The checkout does not show how votes are called, quorum rules, or whether approvals are recorded in git. A PR that changes the on-tag contract should therefore point to maintainer/consortium approval rather than assuming CI is sufficient. + +## Edit classification + +Before editing `_data/spec.json`, classify the change: + +- Description/wording clarification: usually patch-level; still add a `spec.md` changelog entry. +- New `web_api` field: usually minor/additive; changelog and PR callout required. +- New `core` field in unused space: standards proposal first; maintainer/consortium decides. +- Move, resize, remove, or reinterpret a `core` field: breaking/major proposal; legacy snapshot requirement applies. +- Version bump: maintainer-only unless explicitly delegated. + +Detailed data-model checks live in [`spec-data-model.md`](spec-data-model.md) and `_data/AGENTS.md` once added. + +## PR and CI gates + +Observed mechanical gates: + +- `.github/workflows/ci.yml`: `bundle exec jekyll build` on PRs and pushes to `main`. +- `.github/workflows/format.yml`: `npm run format:check` for `js`, `scss`, `json`, `yml`, and `yaml`. +- `.github/workflows/pages.yml`: deploys `main` to production. + +Observed from history, unconfirmed as policy: PRs appear to be squash-merged, and recent history is mostly a single maintainer plus Dependabot. Branch protection, merge rights, and review requirements are GitHub settings and are not visible in the checkout. + +## Maintainer-only release runbook + +1. Confirm the human decision/approval for the spec change. +2. If the next release is a major bump, freeze the old layout into `assets/json/spec_v{oldMajor}.json` before changing current `core.fields`. +3. Edit `_data/spec.json` `version` and fields. +4. Add the matching entry to the `spec.md` changelog. +5. Review whether `index.md`'s `announcement:` should change. +6. Run build/format checks and any manual protocol verification needed. +7. Merge to `main`; GitHub Pages deploys on push to `main`, not on tag creation. +8. Maintainer creates the lightweight version tag if appropriate. Agents must not create or push tags unless explicitly instructed. + +## Versioning reference + +Do not restate version semantics here. Link readers to `spec.md`'s Reader Implementation Guidelines and changelog for the authoritative public wording. + +Operational reminders from observed history: + +- The `version` field, `spec.md` changelog, and git tag can drift because there is no release automation. +- Major bumps require legacy snapshots for old tags in the field. +- Existing `assets/json/spec_v*.json` files are historical compatibility data; do not edit them casually. diff --git a/_docs/spec-data-model.md b/_docs/spec-data-model.md new file mode 100644 index 0000000..7004b76 --- /dev/null +++ b/_docs/spec-data-model.md @@ -0,0 +1,85 @@ +# Spec data model + +This doc owns reference facts about `_data/spec.json`: field structure, type handling, byte budget, and the command for recomputing the current byte map. Edit rules live in `_data/AGENTS.md` once added. + +## Source of truth + +`_data/spec.json` is the editable source for the public spec data. The root `spec.json` page is generated from `site.data.spec`; do not edit root `spec.json` to change the spec. + +Two field lists exist: + +- `core.fields`: the on-tag byte layout within `core.address_range`. +- `web_api.fields`: optional supplemental JSON fields with no byte positions. + +## Core field shape + +Core fields use keys such as `name`, `id`, `required`, `added`, `unit`, `type`, `scaling`, `start`, `length`, `usage`, `examples`, and `description`. `start` is a hex string and `length` is bytes. + +`web_api` fields are descriptive JSON API fields. They do not use `start`, `length`, or `usage`, and their `type` strings are not consumed by the browser protocol code. + +## Type enum + +For `core` fields, the practical type enum is whatever `encodeFieldValue()` and `decodeTagBuffer()` in `assets/scripts/opentag3d.js` implement: + +- `int` +- `utf8` +- `ascii` +- `rgba` +- `date` +- `time` + +`decodeTagBuffer()` also skips `type: "-"`, apparently for reserved bytes, but no current field uses it. + +A typo or new unimplemented `core` type may fail silently during decode. Treat type changes as protocol work. + +## Byte budget + +Verified 2026-09-26 against spec v2.003: the `0x00`–`0xDF` range has 24 free bytes and 0 overlapping byte positions. + +| Gap | Size | +| --- | ---: | +| `0x82`–`0x83` | 2 bytes | +| `0x8B` | 1 byte | +| `0xAB`–`0xB7` | 13 bytes | +| `0xD8`–`0xDF` | 8 bytes | + +The command below is the authority; update the table only after rerunning it against the current spec. + +```bash +node - <<'NODE' +const s = require('./_data/spec.json'); +const start = parseInt(s.core.address_range.start, 16); +const end = parseInt(s.core.address_range.end, 16); +const used = new Array(end - start + 1).fill(0); +for (const f of s.core.fields) { + const fieldStart = parseInt(f.start, 16) - start; + for (let i = fieldStart; i < fieldStart + f.length; i++) used[i]++; +} +const gaps = []; +let i = 0; +while (i < used.length) { + if (used[i]) { + i++; + continue; + } + let j = i; + while (j < used.length && !used[j]) j++; + gaps.push([start + i, start + j - 1, j - i]); + i = j; +} +const hx = (n) => `0x${n.toString(16).toUpperCase().padStart(2, '0')}`; +console.log('version', s.version, 'free', used.filter((x) => !x).length, 'overlap', used.filter((x) => x > 1).length); +for (const [a, b, n] of gaps) console.log(`${hx(a)}${a === b ? '' : `-${hx(b)}`}: ${n}`); +NODE +``` + +## Manual checks until validation exists + +Until a spec validation script exists, manually confirm every `core` change: + +- Type is implemented by shared protocol code. +- `start`/`length` fits inside `core.address_range`. +- No overlap with existing fields. +- `id` remains unique. +- `added` is set to the introducing spec version. +- Changelog and snapshot requirements are handled by the spec-change process. diff --git a/assets/scripts/AGENTS.md b/assets/scripts/AGENTS.md new file mode 100644 index 0000000..9e3514b --- /dev/null +++ b/assets/scripts/AGENTS.md @@ -0,0 +1,82 @@ +# `assets/scripts/` agent notes + +This file owns local rules for shared browser scripts, especially protocol code in `opentag3d.js`. For page-local tool architecture, read `_docs/make-read-tools.md` too. + +## Responsibility map + +`opentag3d.js` expects `globalThis.OpenTag3D.spec` at module evaluation time and owns: + +- Constants/state: `SPEC`, `allFields`, `urlParams`, `NFC_INFO`, `nfcController`. +- Web NFC dialogs: `showWebNfcDialog()`, `finishWebNfcAction()`. +- Byte/encoding utilities: `hex()`, `addrHex()`, `parseHex()`, base64 helpers, `packInt()`, `encodeAscii()`, `encodeUtf8()`, `rgbaFromHex()`, `fixHexRgba()`, `bufferFromText()`, `bufferToHex()`, `hexdump()`, `downloadFile()`, `generateHash()`. +- Field encode/decode: `encodeFieldValue()`, `decodeTagBuffer()`, `getFieldsForMajorVersion()`. +- Web NFC: `writeViaWebNFC()`, `readViaWebNFC()`, `startAutomaticWebNFC()`, `cancelWebNFC()`. +- NTAG/NDEF packing: `buildNtagPageDump()`. +- External formats: Flipper export, Proxmark3 import/export, NFC Tools Desktop/Mobile import/export, and `parseImportedText()`. + +`site.js` owns small site-wide UI helpers: `h()`, `msg()`, and dropdown menu behavior. + +## Danger zones + +Ask first or slow down before touching: + +- `NFC_INFO.ntag.types.*.configPages`, especially AUTH0/PWD/PACK bytes. Wrong bytes can password-protect or lock physical tags. +- `writeViaWebNFC()`, `readViaWebNFC()`, automatic scanning, dialog cancellation, and real tag write behavior. +- `packInt()` and the local `readInt()` in `decodeTagBuffer()`; multi-byte integers need explicit round-trip evidence. +- `tag_version` handling and `getFieldsForMajorVersion()`; old tags rely on legacy `assets/json/spec_v*.json` snapshots. +- `buildNtagPageDump()`; Flipper/Proxmark3 exports can break even if the raw OpenTag3D payload is valid. +- NFC Tools Mobile payload/base64 handling; do not simplify without fixtures or real app verification. +- Import parsers that accept user-provided text/files; keep error messages useful and avoid broadening accepted formats by accident. + +Existing `assets/json/spec_v*.json` files are compatibility data for tags already in the field. Do not edit them from this directory unless the task is explicitly about legacy snapshot maintenance. + +## Node round-trip recipe + +Pure encode/decode paths can be exercised from Node without DOM or Web NFC. Use this as manual verification until a real test script exists: + +```bash +node --input-type=module - <<'NODE' +import { readFileSync } from 'node:fs'; +import { pathToFileURL } from 'node:url'; + +globalThis.window = { location: { search: '' }, addEventListener() {} }; +globalThis.OpenTag3D = { + spec: JSON.parse(readFileSync('_data/spec.json', 'utf8')), +}; + +const { allFields, encodeFieldValue, decodeTagBuffer, bufferToHex } = + await import(pathToFileURL('assets/scripts/opentag3d.js').href); + +const buffer = new Uint8Array(0xe0); +for (const field of allFields) { + let value = field.id === 'tag_version' ? undefined : field.examples?.[0]; + if (field.id !== 'tag_version' && value === undefined) continue; + if (field.type === 'date' && Array.isArray(value)) { + value = `${String(value[0]).padStart(4, '0')}-${String(value[1]).padStart(2, '0')}-${String(value[2]).padStart(2, '0')}`; + } + if (field.type === 'time' && Array.isArray(value)) { + value = `${String(value[0]).padStart(2, '0')}:${String(value[1]).padStart(2, '0')}:${String(value[2]).padStart(2, '0')}`; + } + + buffer.set(encodeFieldValue(field, value), parseInt(field.start, 16)); +} + +const { values, warnings } = await decodeTagBuffer(buffer.buffer); +console.log('bytes', bufferToHex(buffer).slice(0, 95) + '...'); +console.log('decoded fields', values.size); +console.log('warnings', warnings); +NODE +``` + +Caveats: + +- Leave `tag_version` undefined/current unless you are explicitly testing legacy decoding. +- `date` and `time` encoders take strings; `spec.json` examples may be arrays, so convert them. +- This proves shared encode/decode behavior only. UI changes still need a browser check, and Web NFC writes need a supported real-device check or an explicit "not locally verified" note. + +## Verification expectations + +- UI helper changes in `site.js`: browser-check affected pages and menus/messages. +- Encode/decode changes: run a Node round-trip and browser-check `/make` to `/read` behavior. +- Import/export changes: test the specific file format changed with sample content. +- Web NFC/config-page changes: ask first, test with a disposable tag, read back the result, and document the device/browser/tool used.