Run artifact

workspace/logs/20260814.051109.985Z_toml_build_codex.prompt.md

System Instructions

This prompt is divided into three sections:

  1. System Instructions (this section) — structural orientation only. Do not treat this

section as task input.

  1. Input Context — begins with the heading # Input Context. All blocks are wrapped in

<pblock> tags. Two block types:

guidance attribute carries context-specific instructions; content is in a fenced block.

rules, instructions, or group headers.

  1. Agent Task — begins with the heading # Agent Task. Defines your persona, constraints,

and required outputs. Read all input context before acting on this section.

Input Context

<pblock label="Build block job" kind="job">

Build block job

</pblock>

<pblock label="Stories in this block" kind="section">

Stories in this block

</pblock>

<pblock label="Files on disk" kind="section">

Files on disk in the build directory

These are the only imported files present on disk. Every other file named in this prompt is supplied as prompt context and is not on disk; read it here and do not report it as a missing input.

</pblock>

COMPASS - Target Orientation

<pblock filename="COMPASS.md" role="compass" path="/mnt/c/Users/barlo/projects/drydock/uat/Toml/runs/20260814.050011/workspace/targets/toml/COMPASS.md" guidance="Important: This is the core project intent, constraints, and guardrails. It should have presecedence in conflicts.">

# COMPASS: TOML 1.0.0 Parser

## Compass
Build a Go command-line TOML 1.0.0 parser for users and harnesses that need a deterministic stdin-to-tagged-JSON decoder. The parser must implement the supplied specification and distinguish valid documents from invalid documents through its output and exit behavior.

## Constraints
- Use Go with no `go.mod` dependencies.
- Support the Go toolchain floor stated by the sources.
- Read TOML only from stdin and write results only to stdout or diagnostics to stderr.
- Preserve lossless signed 64-bit integers.
- Stage and run the supplied conformance harness assets.
- Complete acceptance uses the installed `toml-test` v2.2.0 suite.

## Guardrails
- Never modify the supplied scoring scripts.
- Never import a third-party TOML parser.
- Reject invalid TOML rather than accepting it permissively.
- Do not add arguments, configuration, or side effects to the decoder command.
- Treat the unfiltered full-suite exit status as the acceptance verdict.

<!-- drydock:build-write-guardrail:start -->
## Build Write Guardrail

- Authorized build directory: `/mnt/c/Users/barlo/projects/drydock/uat/Toml/runs/20260814.050011/build/toml`
- Authorized Target directory: `/mnt/c/Users/barlo/projects/drydock/uat/Toml/runs/20260814.050011/workspace/targets/toml`
- Build agents have permission to create, modify, and remove files required by the active build block inside these authorized directories.
- No path outside these authorized directories may be modified.
- Protected Drydock artifacts:
  - `/mnt/c/Users/barlo/projects/drydock/uat/Toml/runs/20260814.050011/workspace/targets/toml/blueprint/`
  - `/mnt/c/Users/barlo/projects/drydock/uat/Toml/runs/20260814.050011/workspace/targets/toml/MANIFEST.md`
  - `/mnt/c/Users/barlo/projects/drydock/uat/Toml/runs/20260814.050011/workspace/targets/toml/COMPASS.md`
  - `/mnt/c/Users/barlo/projects/drydock/uat/Toml/runs/20260814.050011/workspace/targets/toml/QuarterDeck/`
  - `/mnt/c/Users/barlo/projects/drydock/uat/Toml/runs/20260814.050011/workspace/targets/toml/evidence/`
<!-- drydock:build-write-guardrail:end -->

<!-- Drydock author intent sha256=d780c57ad3d283f3377384df3c315069d74577e15441c2c30e359ecde1d3a0b4 source=INSTRUCTIONS.md -->

# Build Instructions: TOML 1.0.0 Parser

## Objective

Build a TOML v1.0.0 parser that conforms to the specification in
`sources/toml-v1.0.0.md`. Correctness is measured by the upstream `toml-test`
conformance suite. The goal is to pass every valid and every invalid case the
installed suite supplies, with no case failed, errored, or skipped. The suite's
size is a property of the version `setup_harness.sh` installs; never assert a
case count.

Rejecting invalid input is scored as heavily as accepting valid input. A parser
that is merely permissive fails roughly 70 percent of the suite.

The implementation language is Go, fixed by this Target's `TECHNOLOGY_STACK.md`
and governed by `stack/go.md`. The conformance harness itself is written in Go
but is a scoring instrument, not part of the deliverable.

## Run Harness

`sources/full_test.sh` is the single scoring entry point. It is supplied, not
authored: it is staged verbatim into the build directory alongside the other
imported assets, and `drydock uat` runs `sh sources/full_test.sh` from the
completed application root and takes its exit code and output as the score. It
reads:

```sh
#!/bin/sh
# full_test.sh — scoring entry point. Do not filter, skip, or reinterpret.
set -eu
go build -o toml-decoder ./cmd/toml-decoder
DECODER="$PWD/toml-decoder" exec sh sources/run_conformance.sh
```

The build step is deliberately separate from the scoring step so that a
compilation failure and a conformance failure are distinguishable in the
evidence. `DECODER` is the harness's only knowledge of the implementation
language; the harness itself is language-neutral.

**The scoring assets are read-only.** `sources/full_test.sh`,
`sources/run_conformance.sh`, and `sources/setup_harness.sh` are hash-verified
against the import and restored before grading, so a modification is reported as
tampering rather than honored. Do not write to them. Build `cmd/toml-decoder` so
that the supplied entry point succeeds; changing the entry point is not a
repair.

## Interface Contract

The program is a filter: read TOML from **stdin**, write tagged JSON to
**stdout**, exit `0`. On invalid TOML, write a diagnostic to **stderr** and exit
non-zero. No arguments, no config, no side effects.

Minimal shape (`cmd/toml-decoder/main.go`):

```go
package main

import (
	"encoding/json"
	"fmt"
	"io"
	"os"

	"github.com/owner/toml-decoder/internal/toml"
)

func main() {
	input, err := io.ReadAll(os.Stdin)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	tagged, err := toml.Decode(string(input))
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	if err := json.NewEncoder(os.Stdout).Encode(tagged); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
```

The parser lives in `internal/toml`; `main` reads, delegates, and encodes. See
`stack/go.md` for the module layout and the toolchain floor.

### Tagged JSON encoding

- TOML tables become JSON objects. Empty tables become `{}`.
- TOML arrays become JSON arrays. Empty arrays become `[]`.
- Every TOML **value** becomes `{"type": "<TOML_TYPE>", "value": "<TOML_VALUE>"}`.
- `TOML_VALUE` is always a JSON string, including for integers, floats, and booleans.
- `TOML_TYPE` is one of: `string`, `integer`, `float`, `bool`, `datetime`,
  `datetime-local`, `date-local`, `time-local`.
- Offset datetimes are encoded as RFC 3339. Local datetimes are RFC 3339 without
  the offset. Local dates are the date part; local times are the time part.

| TOML | JSON |
|---|---|
| `a = 42` | `{"a": {"type": "integer", "value": "42"}}` |
| `a = true` | `{"a": {"type": "bool", "value": "true"}}` |
| `a = ["a", 2]` | `{"a": [{"type":"string","value":"a"}, {"type":"integer","value":"2"}]}` |
| `[tbl]`<br>`a = 42` | `{"tbl": {"a": {"type": "integer", "value": "42"}}}` |

## Test / Verification Process

The imported source files are placed in a `sources/` subdirectory of the
application directory. Install the harness once (network required, one time
only):

```bash
sh sources/setup_harness.sh
```

Then run the suite from the application directory. `DECODER` is required — the
harness has no default implementation language:

```bash
go build -o toml-decoder ./cmd/toml-decoder
DECODER="$PWD/toml-decoder" sh sources/run_conformance.sh
```

During development, `sh sources/full_test.sh` does both steps and is the same
command the score is taken from.

Mechanics: `toml-test` holds the corpus internally. For each valid case it pipes
TOML into the decoder on stdin and compares the emitted tagged JSON against the
expected description. For each invalid case it requires a non-zero exit. The
summary is:

```
  valid tests: NNN passed,  N failed
invalid tests: NNN passed,  N failed
```

The passed counts are the correctness score. Exit code is non-zero while any
test fails.

### Useful flags

Flags pass straight through `sources/run_conformance.sh` to `toml-test test`.

- `-run 'valid/string/*'` — run one feature group. Use this to develop one
  construct at a time.
- `-run=valid/string-empty,valid/string-nl` — run named cases.
- `-skip 'invalid/datetime/*'` — exclude a group.
- `-json` — machine-readable report instead of text.
- `-v` — list passing tests as well as failures.
- `-script` — emit a shell script of `-skip` flags for the current failures,
  which is the fastest way to snapshot known failures between passes.

Feature groups available to `-run`:

- valid: `array bool comment datetime float inline-table integer key spec-1.0.0 string table`
- invalid: the above plus `control encoding local-date local-datetime local-time`

## Suggested Implementation Order

TOML parsing is lexically simple and structurally fussy. The difficulty is in
key/table semantics and in rejecting malformed input, not in the grammar.

1. **Scaffolding** — line handling, comments, whitespace, the stdin/stdout/exit
   contract, tagged JSON emission.
2. **Scalars** — booleans, integers (including `0x`, `0o`, `0b`, underscores),
   floats (including `inf`, `nan`, exponents), basic and literal strings, then
   multi-line strings with their line-ending backslash and trimming rules.
3. **Keys** — bare, quoted, and dotted keys; the redefinition rules.
4. **Tables** — `[table]`, `[a.b.c]` implicit creation, `[[array of tables]]`,
   and the rules governing which of these may follow which.
5. **Inline tables and arrays** — including nesting and the TOML 1.0 restriction
   that inline tables are closed to later extension.
6. **Datetimes** — offset, local datetime, local date, local time.
7. **Invalid-input hardening** — control characters, bad UTF-8, duplicate keys,
   redefinition after an inline table, unterminated constructs. This is where
   most of the remaining score lives.

The specification is normative and short. Follow it directly.

## Files the LLM Needs

- `sources/toml-v1.0.0.md` — the specification. Primary input. Required.
- `sources/full_test.sh` — the supplied scoring entry point.
- `sources/run_conformance.sh` — the conformance harness it invokes.
- `sources/setup_harness.sh` — one-time harness installation.

## Definition of Done

- `sh sources/full_test.sh` runs cleanly with zero errors and exits zero.
- The program satisfies the stdin → tagged-JSON → exit-code contract.
- Every supplied valid and invalid case passes: the failed, errored, and skipped
  counts are all zero. The harness exit status is the verdict and the whole
  verdict — assert `returncode == 0` and stop there. Do not assert on the text
  of the summary line at all: the case totals belong to the installed suite, and
  a check that reads a runner's printed output is measuring the runner rather
  than the parser.
- The parser is written from the specification. **Every third-party TOML module is
  forbidden** — `github.com/BurntSushi/toml`, `github.com/pelletier/go-toml`,
  `github.com/naoina/toml`, and any other. `BurntSushi/toml` scores near-perfectly
  on this suite, so importing it makes the exercise meaningless.
- `go.mod` declares no `require` dependencies. The standard library is sufficient:
  `encoding/json`, `strconv`, `strings`, `unicode`, `unicode/utf8`, `time`, `math`,
  `fmt`, `io`, `os`, `errors`.
- No network access at test time after `setup_harness.sh` has run once.

</pblock>

STACK - Technology HOW

<pblock filename="go.md" role="stack" path="/mnt/c/Users/barlo/projects/drydock/Rigging/stack/go.md">

# Go Best Practices

**Version:** 20260809 V2  
**Category:** Technologies
**Description:** Go language conventions and patterns for specification-driven projects

Technology reference for Go development. Framework-agnostic — applies to any Go project. This file does not change between projects.

Prerequisite: `stack/common.md`

---

## 1. Code Style and Understandability

**Rule**: Code must be understandable on its own through naming, structure, small focused units, explicit types, clear interfaces, appropriate abstractions, and tests. If a reader needs a comment to follow the mechanics, improve the code instead.

Rules:
- **Formatting is not a decision** — `gofmt` output is the only accepted formatting. Never hand-format, never argue about it, never commit unformatted code.
- **Naming** — short names for short scopes (`i`, `buf`, `err`), descriptive names for package-level identifiers. Package names are short, lowercase, single-word nouns: `parser`, not `parserutils` or `parser_helpers`. Never `util`, `common`, `base`, or `helpers`.
- **No stutter** — the package qualifies the name. `parser.New()`, not `parser.NewParser()`; `http.Client`, not `http.HTTPClient`.
- **Exported means committed** — capitalize an identifier only when callers outside the package need it. Everything else is unexported and free to change.
- **Doc comments** — every exported identifier has a comment starting with its own name: `// Decode reads TOML from r and returns …`.
- **Small focused units** — a function that needs a section comment ("// now validate…") is two functions.
- Comments state constraints the code cannot express (invariants, protocol quirks, why-not-the-obvious-way) — never restate what the next line does.

**Why**: Go deliberately removed stylistic choice so that all Go code reads the same. Fighting that costs review time and buys nothing.

---

## 2. Module Layout and Toolchain

**Rule**: One module per repository, with the toolchain version pinned in `go.mod` and `go.sum` committed.

```
myproject/
  go.mod              module github.com/owner/myproject
  go.sum              committed, never hand-edited
  cmd/myproject/      package main — one directory per binary
  internal/           application packages; import-blocked outside the module
  pkg/                only if the module is a library others import
  testdata/           fixtures; ignored by the go tool
  bin/                launcher scripts (see stack/common.md)
```

```gomod
module github.com/owner/myproject

go 1.24

require github.com/some/dep v1.4.2
```

Rules:
- **Go 1.22 is the hard floor. Verify it first and stop if it is not met.** Before writing any code, run `go version`. On anything older than 1.22, stop and report the toolchain as a blocker — do not downgrade the code to compile on it, do not work around it, do not proceed and hope. The distribution-packaged Go on Debian and Ubuntu is frequently older than this and must be replaced with the official tarball.

```sh
go version | awk '{print $3}' | sed 's/^go//' | \
  awk -F. '$1<1 || ($1==1 && $2<22) { print "go 1.22+ required, found " $0; exit 1 }'
```

- Business logic lives in `internal/`. `cmd/<name>/main.go` parses flags, wires dependencies, and calls into `internal/`; it holds no behavior worth testing.
- `pkg/` exists only when external consumers import the code. A binary-only project does not need it.
- The `go` line in `go.mod` is the minimum toolchain, and it is a real constraint — `go 1.19` fails on anything newer than 1.19 syntax and stdlib. State the version the code actually requires.
- `go.sum` is committed. `go mod tidy` runs before every commit that touches dependencies, and its output is part of the diff.
- Do not vendor unless the deployment target requires it. If vendoring, `go mod vendor` output is committed whole and never edited.

**Why**: Go's tooling assumes this layout and enforces `internal/` at compile time. A project that follows it gets dependency hygiene, import boundaries, and reproducible builds without configuration. The 1.22 floor is not stylistic: 1.22 changed loop variables to be scoped per iteration, so identical source produces different behavior on 1.21 and earlier. Code written against modern semantics and compiled by an older toolchain fails silently rather than loudly.

---

## 3. Errors Are Values

**Rule**: Return errors, do not panic. Wrap with context at each layer that adds information, and inspect with `errors.Is` / `errors.As`, never by string matching.

```go
var ErrNotFound = errors.New("not found")

func LoadConfig(path string) (*Config, error) {
    data, err := os.ReadFile(path)
    if err != nil {
        return nil, fmt.Errorf("load config %s: %w", path, err)
    }
    var cfg Config
    if err := json.Unmarshal(data, &cfg); err != nil {
        return nil, fmt.Errorf("parse config %s: %w", path, err)
    }
    return &cfg, nil
}

// Caller inspects by identity, not by text
if errors.Is(err, os.ErrNotExist) { … }

var perr *json.SyntaxError
if errors.As(err, &perr) { … }
```

Rules:
- `%w` wraps exactly one error and preserves the chain. `%v` formats and discards it — use `%v` only when the chain must deliberately not leak.
- Error strings are lowercase and carry no trailing punctuation, because they are concatenated: `"parse config x: unexpected EOF"`.
- Handle an error once. Logging it and returning it is handling it twice, and the operator sees the same failure repeated at every layer.
- `panic` is for programmer error that cannot be recovered from (an impossible switch branch, a corrupt invariant). Library code never panics on bad input; it returns an error.
- `recover` appears only at a process or request boundary that must not die, and it logs and re-fails rather than swallowing.
- Never ignore an error with `_`. If it is genuinely safe to discard, say why in a comment on that line.

**Why**: Go has no exceptions, so an unhandled error is a silently wrong result rather than a crash. Wrapping preserves the failure path; `errors.Is` keeps callers working when the message text changes.

---

## 4. Types, Interfaces, and Zero Values

**Rule**: Define interfaces where they are consumed, keep them small, and make the zero value of a type useful.

```go
// GOOD — the consumer declares what it needs
package report

type Store interface {
    Get(ctx context.Context, id string) ([]byte, error)
}

func Render(ctx context.Context, s Store, id string) ([]byte, error) { … }
```

```go
// Zero value is usable — no constructor required
type Buffer struct {
    buf []byte
}

func (b *Buffer) Write(p []byte) (int, error) {
    b.buf = append(b.buf, p...)
    return len(p), nil
}

var b Buffer   // ready to use
```

Rules:
- Accept interfaces, return concrete types. A function that returns an interface hides fields the caller may legitimately need.
- One or two methods per interface. `io.Reader` is the model; a ten-method interface is a struct wearing a disguise.
- Do not define an interface until there are two implementations, or until a test genuinely needs to substitute one. Speculative interfaces are indirection with no payoff.
- Prefer a usable zero value over a `New…` constructor. When a constructor is required, it validates and returns `(*T, error)`.
- Pointer receivers when the method mutates or the struct is large; value receivers otherwise. Do not mix receiver kinds on one type.
- No naked returns in any function long enough to need scrolling.
- `context.Context` is the first parameter of any function that does I/O, blocks, or spawns work — never stored in a struct field.

**Why**: Consumer-side interfaces mean a package can be tested and substituted without the producer knowing it exists. Useful zero values remove a whole category of "forgot to initialize" bugs.

---

## 5. Concurrency With Owned Lifetimes

**Rule**: Every goroutine has a known owner, a known stop condition, and a way to report failure. Start none that you cannot stop.

```go
func Fetch(ctx context.Context, urls []string) ([]Result, error) {
    g, ctx := errgroup.WithContext(ctx)
    results := make([]Result, len(urls))
    for i, u := range urls {
        i, u := i, u
        g.Go(func() error {
            r, err := get(ctx, u)
            if err != nil {
                return fmt.Errorf("fetch %s: %w", u, err)
            }
            results[i] = r
            return nil
        })
    }
    if err := g.Wait(); err != nil {
        return nil, err
    }
    return results, nil
}
```

Rules:
- Cancellation flows through `context.Context`. A goroutine that cannot observe `ctx.Done()` is a leak waiting for load.
- The code that starts a goroutine is responsible for waiting on it — `sync.WaitGroup`, `errgroup`, or an explicit done channel. Fire-and-forget is prohibited outside `main`.
- Channels carry ownership: the sender closes, the receiver never does. Do not close a channel from more than one place.
- Use a mutex when the data is shared state and a channel when the data is being handed off. Do not build a queue out of mutexes.
- Every build and CI run includes `go test -race`. The race detector finds what review does not.
- Do not add concurrency for speed until a benchmark shows the serial version is the bottleneck.

**Why**: Go makes starting a goroutine trivial and stopping one entirely manual. Leaks and races surface under production load, not in development.

---

## 6. Table-Driven Tests

**Rule**: Tests use the stdlib `testing` package, are table-driven where cases share a shape, and run offline with no network and no credentials.

```go
func TestParseDuration(t *testing.T) {
    tests := []struct {
        name    string
        input   string
        want    time.Duration
        wantErr bool
    }{
        {name: "seconds", input: "30s", want: 30 * time.Second},
        {name: "hours", input: "2h", want: 2 * time.Hour},
        {name: "malformed", input: "2x", wantErr: true},
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            got, err := ParseDuration(tt.input)
            if (err != nil) != tt.wantErr {
                t.Fatalf("ParseDuration(%q) error = %v, wantErr %v", tt.input, err, tt.wantErr)
            }
            if got != tt.want {
                t.Errorf("ParseDuration(%q) = %v, want %v", tt.input, got, tt.want)
            }
        })
    }
}
```

Rules:
- Subtests via `t.Run` so a single case can be run with `-run TestParseDuration/malformed`.
- Failure messages state input, actual, and expected. `t.Errorf("got %v, want %v", got, want)` is the minimum; a bare `t.Fail()` is useless in CI output.
- `t.Fatalf` when the test cannot continue, `t.Errorf` when it can and more failures are informative.
- Fixtures live in `testdata/`. Golden files are regenerated by a `-update` flag, and the regenerated diff is reviewed, not rubber-stamped.
- `t.TempDir()` and `t.Cleanup()` for filesystem work — never write into the package directory or `/tmp` by hand.
- No network, no credentials, no wall-clock sleeps. Inject a clock or a fake transport instead.
- Benchmarks (`func BenchmarkX(b *testing.B)`) accompany any claim about performance.

**Why**: Table-driven tests make adding the twentieth case free, which is what keeps edge cases getting written down instead of argued about.

---

## 7. Build, Lint, and Verify

**Rule**: The same commands gate locally and in CI, and they all pass before a commit.

```bash
gofmt -l .                       # must print nothing
go vet ./...
go build ./...
go test -race -cover ./...
```

```bash
# Static, dependency-free binary for containers and scratch images
CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o bin/myproject ./cmd/myproject
```

Rules:
- `gofmt -l .` printing any filename fails the build. This is not negotiable and needs no discussion.
- `go vet ./...` is the floor. Add `staticcheck` or `golangci-lint` when the project justifies it, with the configuration committed.
- `CGO_ENABLED=0` unless a dependency genuinely needs cgo; it is the difference between a portable static binary and one that fails on a different libc.
- `-trimpath` keeps build paths out of the binary so builds are reproducible across machines.
- Pin tool versions with `go run <tool>@<version>` rather than assuming what is installed. An unpinned linter changes its mind between machines.
- Wrap the sequence in a `bin/` script (see `stack/common.md`) so there is one command to run and one place to change it.

**Why**: Go's toolchain ships almost everything needed. The remaining risk is drift between what a developer runs and what CI runs, which one scripted entry point removes.

---

## 8. Dependencies

**Rule**: The standard library first. Add a dependency only when it removes real work, and pin it.

Rules:
- Check the stdlib before searching: `net/http` is a production server, `encoding/json` is a production codec, `database/sql` is a production database layer, `log/slog` is structured logging. Frameworks are frequently unnecessary.
- Every dependency is an exact version in `go.mod`. Never `@latest` in committed configuration.
- `go mod tidy` after any dependency change; the resulting `go.mod` and `go.sum` are committed together.
- Evaluate a candidate on maintenance, transitive dependency count, and licence before importing it. A one-function dependency is usually a one-function file.
- Deprecated or archived upstream is a defect to schedule, not a warning to silence.

**Why**: Every dependency is code the project owns the consequences of but not the maintenance of. Go's stdlib is unusually complete, which makes "do I need this?" a real question.

---

## Summary Checklist

- [ ] `gofmt` clean; package and identifier names idiomatic; no stutter; exported identifiers documented
- [ ] One module; logic in `internal/`; thin `cmd/<name>/main.go`; `go.sum` committed; `go` directive states the real minimum
- [ ] Errors returned and wrapped with `%w`; inspected with `errors.Is`/`errors.As`; handled once; no ignored errors
- [ ] Interfaces defined at the consumer, one or two methods; concrete return types; useful zero values; `context.Context` first parameter
- [ ] Every goroutine has an owner, a cancellation path, and a wait; `go test -race` in every run
- [ ] Table-driven subtests with informative failures; fixtures in `testdata/`; offline and deterministic
- [ ] `gofmt -l .`, `go vet`, `go build`, `go test -race -cover` all gate locally and in CI via one `bin/` script
- [ ] Standard library preferred; dependencies pinned and tidied; each one justified

</pblock>

<pblock filename="common_compact.md" role="stack" path="/mnt/c/Users/barlo/projects/drydock/Rigging/stack/common_compact.md">

<!-- Compacted from RulesEngine/stack/common.md on 2026-04-29 by prompts/compact_file.md — regenerate via bin/rulesengine_compact.sh -->

# Common Best Practices — Compact

## Project Directory Layout

```
project-name/
├── bin/                # Operation scripts
├── data/               # Runtime data (DB, logs, backups) — gitignored
│   ├── logs/
│   └── backups/
├── docs/
├── tests/
├── .env                # gitignored
├── .env.example        # committed
├── .gitignore
├── CLAUDE.md
└── Links.md
```

Additional directories depend on the stack (e.g., `templates/`, `static/`, `migrations/`).

## Shell Scripts (bin/)

All user-facing operations live in `bin/` as bash scripts with standardized headers, logging, and error handling.

```bash
#!/bin/bash
# CommandCenter Operation
# Name: Human Readable Name
# Type: daemon|batch
# Port: 8000

# --- Standard Preamble ---
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
LOG_DIR="$PROJECT_DIR/data/logs"
mkdir -p "$LOG_DIR"

TIMESTAMP=$(date '+%Y-%m-%d_%H%M%S')
SCRIPT_NAME=$(basename "$0" .sh)
LOG_FILE="$LOG_DIR/${SCRIPT_NAME}_${TIMESTAMP}.log"

echo "=== $SCRIPT_NAME started at $(date '+%Y-%m-%d %H:%M:%S') ===" | tee "$LOG_FILE"
echo "Arguments: $*" | tee -a "$LOG_FILE"
echo "Working dir: $PROJECT_DIR" | tee -a "$LOG_FILE"
echo "---" | tee -a "$LOG_FILE"

cd "$PROJECT_DIR"

# --- Your Commands Here ---
# All output goes to both console and log file via tee
your_command 2>&1 | tee -a "$LOG_FILE"

echo "=== $SCRIPT_NAME finished at $(date '+%Y-%m-%d %H:%M:%S') ===" | tee -a "$LOG_FILE"
```

## Header Fields

| Field | Required | Values | Description |
|-------|----------|--------|-------------|
| `# CommandCenter Operation` | Yes | literal | Marks script as discoverable |
| `# Name:` | Yes | free text | Display name in UI |
| `# Type:` | No | `daemon` or `batch` | Default: `batch`. Daemons stay running. |
| `# Port:` | No | integer | Port number for daemon services |

Scripts without `# CommandCenter Operation` won't appear in Command Center's UI.

## Standard Scripts

| Script | Type | Purpose |
|--------|------|---------|
| `bin/start.sh` | daemon | Start the dev server |
| `bin/stop.sh` | batch | Stop the dev server |
| `bin/test.sh` | batch | Run test suite |
| `bin/build.sh` | batch | Build/compile the project |
| `bin/deploy.sh` | batch | Deploy to production |
| `bin/backup.sh` | batch | Backup data/database |

Logging: all stdout/stderr captured via `tee` to `data/logs/`. Log filename: `scriptname_YYYY-MM-DD_HHMMSS.log`. First lines always record timestamp, arguments, working directory.

## External Links (Links.md)

Every project maintains `Links.md` at its root:

```markdown
| Label | URL |
|-------|-----|
| Local Dev | http://localhost:5001 |
| Production | https://example.com |
| Docs | https://docs.example.com |
| GitHub | https://github.com/user/repo |
```

One table, two columns (Label, URL). Command Center's scanner reads this on startup and stores links in the project's `extra` JSON.

## CLAUDE.md Convention

Every project has `CLAUDE.md` at its root with these sections in order:

1. `## Project Overview` — what the project does, key features
2. `## Architecture` — tech stack, key files, patterns
3. `## Dev Commands` — bash commands in a code block
4. `## Service Endpoints` — URLs: `- Label: https://url`
5. `## Bookmarks` — grouped links: `### Group` then `- [Title](URL)`

Section rename rules — always use the standard name:
- `## Commands` / `## Development Commands` / `## Build Commands` → `## Dev Commands`
- `## Overview` / `## Project Purpose` → `## Project Overview`
- `## Stack` → `## Architecture`

## Git Hygiene

Never commit secrets, generated files, or runtime data.

```gitignore
# Runtime
data/
*.db
*.log

# Environment
.env
venv/
node_modules/

# Python
__pycache__/
*.pyc
*.egg-info/
dist/
build/

# OS
.DS_Store
Thumbs.db
```

- `data/` — runtime databases, logs, backups, uploads
- `.env` — secrets and local config; commit `.env.example` with placeholder values
- Write imperative commit messages: "Add health endpoint" not "Added health endpoint"

## Development Workflow

1. **Always commit immediately** after completing a task with no errors.
2. Commit messages: descriptive text, no AI/tool mentions.
3. **DO NOT push** — local commits only.
4. **NO co-authored-by lines**.
5. End code change responses with a restart notice:
   - Templates/CSS/static only: "No restart needed — browser refresh is enough."
   - Python/JS server files: "Restart required — run the start script or equivalent."

</pblock>

CONTEXT - Read-Only Support

<pblock filename="ARCHITECTURE_compact.md" role="context" path="/mnt/c/Users/barlo/projects/drydock/uat/Toml/runs/20260814.050011/workspace/targets/toml/blueprint/ARCHITECTURE_compact.md">

<!-- Compacted from ARCHITECTURE.md sha256=87d3e8f16f04cd340948533f7dcb38d62908346d19b3ce7ae5e181b29422e39e on 2026-08-14 by drydock build agent -->

Go module `github.com/owner/toml-decoder` uses standard library only. `cmd/toml-decoder` reads TOML from stdin, emits tagged JSON to stdout, reports invalid input on stderr, and exits non-zero. `internal/toml` owns parsing and explicit value kinds while preserving integer lexemes.

</pblock>

IMPLEMENTS - Authoritative Step Specifications

<pblock label="Implementation recency anchor" kind="section"> The files in this section are the load-bearing specifications for this build block. Build these files exactly. Treat earlier sections as constraints and context.

</pblock>

<pblock filename="FEATURE-Decoder-Contract.md" role="implements" path="/mnt/c/Users/barlo/projects/drydock/uat/Toml/runs/20260814.050011/workspace/targets/toml/blueprint/FEATURE-Decoder-Contract.md" guidance="Feature Specification">

# FEATURE: Decoder Contract

| Field       | Value |
|-------------|-------|
| Version     | 20260814 V1 |
| Description | Defines the argument-free stdin-to-tagged-JSON decoder command contract. |
| Depends On  | ARCHITECTURE.md |
| Provides    | cmd/toml-decoder |
| Consumes    | parser module boundary, tagged JSON contract |

## Workflow

The `cmd/toml-decoder` executable reads one TOML document from standard input and delegates parsing to `internal/toml`. For valid input it writes the encoded tagged JSON document to standard output and exits successfully. It accepts no command-line arguments, configuration, or alternate input source.

## Output Behavior

Tables and arrays retain their JSON structure. Scalar values use the tagged representation defined by `ARCHITECTURE.md`. The command does not write files, contact external services, or emit diagnostics for successful input.

## Guardrails

- The command accepts no arguments.
- TOML is read only from stdin.
- Successful output is written only to stdout.
- The command has no configuration or persistent side effects.
- Invalid-input handling is implemented by the decoder error boundary.

## Programmatic Acceptance

=== AC decoder-valid-stdin ===
Intent: A valid TOML document is accepted through stdin and produces a JSON object.
import json
import subprocess

source = 'answer = 42\n'
result = subprocess.run(
    ["./toml-decoder"],
    input=source,
    capture_output=True,
    text=True,
)
decoded = json.loads(result.stdout)
assert result.returncode == 0
assert isinstance(decoded, dict)
=== END AC decoder-valid-stdin ===

=== AC decoder-argument-free ===
Intent: Supplying an argument is rejected by the argument-free command contract.
import subprocess

result = subprocess.run(
    ["./toml-decoder", "--help"],
    input="",
    capture_output=True,
    text=True,
)
assert result.returncode != 0
=== END AC decoder-argument-free ===

=== AC decoder-stream-separation ===
Intent: Successful decoding does not write diagnostics to stderr.
import subprocess

source = 'enabled = true\n'
result = subprocess.run(
    ["./toml-decoder"],
    input=source,
    capture_output=True,
    text=True,
)
assert result.returncode == 0
assert result.stderr == ""
=== END AC decoder-stream-separation ===

## User Acceptance

- None.

## Guardrails

- None.

</pblock>

<pblock label="Build instructions" kind="instructions">

Build instructions for this block

Build the stdin-to-tagged-JSON decoder command. (decoder-contract)

Implement cmd/toml-decoder as an argument-free stdin filter. Read all TOML from stdin, delegate parsing to internal/toml, encode the tagged result as JSON on stdout, and report operational failures on stderr with a non-zero exit status. Add process-level tests for valid stdin, stdout JSON, argument rejection, and absence of configuration or side effects.

</pblock>

Agent Task

You are a Drydock build agent implementing exactly one build step of a larger plan. The build job block below names the target, the build working directory, and the step. Everything you need is stacked into this prompt under role headings:

authoritative; implement them exactly.

Operating contract:

  1. Follow the write authorization and protected paths in the stacked COMPASS.md exactly.

That persisted guardrail is the sole authority for paths this build may modify.

  1. Start by inspecting the build working directory. Preserve existing application

files unless this step's specifications require a change. Its sources/ subdirectory holds staged build assets — imported test corpora, conformance harnesses, and fixtures — placed there for you. They are read-only inputs: run them, import them, and write code against them, but never create, rewrite, trim, regenerate, or substitute one, even to make a check pass. A step that modifies a staged asset fails and the asset is restored. If an asset you expect is absent, report that; do not author a replacement.

  1. Implement only this step. Use context, stack, and rules as constraints,

not as additional work to perform.

  1. Follow the stack and rules for languages, structure, naming, and branding.
  2. The programmatic acceptance assertions in the implements specifications are

this step's Definition of Done — human-owned, declared before the build, and fixed. Build the story and, in this same step, write the deterministic tests that prove each declared assertion, as a TDD master would; add finer tests for coverage. Every test you write follows the same rule the acceptance assertions do: act on the system, read the state back, compare to expected. The oracle is a return value, parsed JSON, a status code, a stored row, file contents read back, or an exit status — never a substring of captured stdout or stderr, a test-runner tally, or a log line. Write tests in the project's own language using that language's libraries; an in-language HTTP client yields a status code and a parsed body, where curl yields text to scrape. Round-trip anything that stores state: act, then read back through the public interface. Assert declared failure signals on negative paths, never message wording. You may add tests but must never remove, soften, or weaken a declared acceptance assertion. A Suite: full conformance check gates on the entire imported test suite: the step is done only when it passes in full, never on a representative subset — reproduce the standard exactly rather than wrapping a third-party library that approximates it. For a suite, the runner's exit status is the verdict and the whole verdict: print its captured output for diagnosis, never assert on the text of its summary. When an assertion is a static or filesystem scan (import boundary, "X never appears outside Y," grep/AST gate), honor the scope the specification states and never widen it: scan production source only, exclude .venv/, site-packages, and vendored or generated code, and do not flag test doubles or fixtures that use the guarded dependency. Run every declared acceptance assertion before returning. For a conformance suite, use its section or example filters to diagnose coherent root-cause clusters, but rerun the full declared scope before reporting the result. Treat failing examples as a work queue for fixing general behavior; never add example-specific exceptions.

  1. Grow the project's own test suite as you write the code, and treat it as the project's

real coverage. The acceptance assertions in implements are gates: few, fixed, and written before any code existed, so every expectation in them is a prediction. The tests you write are written beside the finished code, so their expected values are observed rather than predicted — which is why exhaustive coverage belongs here and not there. Extend the suite in the project's established location and runner, keep it runnable by the project's declared test command, and leave it green when you return. Cover, at minimum: every public entry point and every verb it declares, including declared error paths; the boundaries — empty, exactly one, many, absent optional fields, declared maxima; declared idempotence, applied twice; one behavior per test, named for the behavior; and isolation — each test arranges its own data, with a fresh store or explicit teardown, so a run leaves no residue behind in the build directory. Where a staged authoritative suite already covers a surface, that suite is the coverage: run it, and do not restate its cases. Report the suite's pass/fail counts in your SUMMARY so a reader can see coverage moving across steps.

  1. Treat User Acceptance entries as review evidence requirements. Implement

the supporting behavior, but do not claim to have performed human judgment.

  1. The implements section is authoritative and intentionally stacked late in

the prompt as the recency anchor. Build that WHAT exactly; do not substitute generic framework defaults.

  1. Before adding or installing Python dependencies, verify each package name

against the declared registry. Do not invent package names. If a needed package cannot be verified or appears newly published, fail explicitly instead of installing it.

  1. Use the stack's required package manager workflow for dependency changes.

When the stack requires uv, update manifests through uv conventions rather than bare pip install.

  1. Do not claim success unless you actually created or modified project files in

the build working directory. If you cannot write files or cannot complete the step, report failure explicitly.

  1. Do not run git add, git commit, create branches, create tags, rewrite

history, or otherwise mutate Git history. Drydock owns the final build directory commit after you return.

  1. End your response with this exact closing structure:
RESULT: SUCCESS | FAILED

FILES CHANGED:
- relative/path

SUMMARY:
<brief reviewable summary>

BLOCKERS:
- <only if any>

Before RESULT, you may emit one optional JSON payload when implementation required a bounded choice not already settled by the owning specification. This records what you did; it does not ask permission, create a questionnaire, or excuse incomplete work:

<blueprint-decisions>
[{"spec":"FEATURE-Example.md","severity":"Material","subject":"Chosen behavior","decision":"Options A and B were available. I implemented B because ... Is that acceptable, or should this change on replan?"}]
</blueprint-decisions>

Name only a specification implemented by this build block. Use Low or Material; Build never emits a Blocking decision. Omit the payload when no implementation decision was necessary.

  1. FILES CHANGED must list only files actually written in the build working

directory. If no files were written, use RESULT: FAILED.

  1. On RESULT: FAILED, append two additional lines so the failure is actionable

without opening logs. FAILURE_SUMMARY is one line naming the cause; FAILURE_DETAIL states what happened, why, and what to change before a rerun. Name concrete conditions when they apply: token or context limit exceeded, could not execute commands in this environment, a required input was missing, or a specific tool or command failed.

FAILURE_SUMMARY: <one line naming the cause>
FAILURE_DETAIL: <what happened, why, and what to change before rerunning>
  1. When a declared acceptance criterion cannot pass no matter how the code is written,

say so with this exact token. You may not edit the criterion — it is staged and restored before grading:

AC_BROKEN: <check-id>[, <check-id>]

This is a report, not a verdict, and it stops nothing. A criterion reaches you only when its expected value is one its author could not have invented — a status code, a staged suite's exit status, a value the criterion itself supplied as input — so your claim that the criterion rather than the code is at fault is the less likely explanation, and the budget is spent as it would be for any other failure. A criterion whose expectation was hand-typed already settles DISPUTED on its own, without you naming it. Emit the token only after running the criterion and confirming the underlying command succeeded while the assertion still failed. Name the affected check ids, emit it alongside your normal RESULT line, state the reasoning in FAILURE_DETAIL, and emit it even when RESULT: SUCCESS. Do not use it for a criterion you merely failed to satisfy.

Active Commander guidance

Commander decisions

Apply these decisions as constraints; do not recreate them as questions.

analyze-display_name

analyze-short_description